diff --git a/.build/common.ts b/.build/common.ts index 274977fa26..e2190974f9 100644 --- a/.build/common.ts +++ b/.build/common.ts @@ -22,9 +22,9 @@ export const packageOptions = { packageName: 'mermaid-zenuml', file: 'detector.ts', }, - 'mermaid-flowchart-elk': { - name: 'mermaid-flowchart-elk', - packageName: 'mermaid-flowchart-elk', - file: 'detector.ts', + 'mermaid-layout-elk': { + name: 'mermaid-layout-elk', + packageName: 'mermaid-layout-elk', + file: 'layouts.ts', }, } as const; diff --git a/.build/jisonTransformer.ts b/.build/jisonTransformer.ts index 314df8a33f..b603502306 100644 --- a/.build/jisonTransformer.ts +++ b/.build/jisonTransformer.ts @@ -1,6 +1,7 @@ import jison from 'jison'; export const transformJison = (src: string): string => { + // @ts-ignore - Jison is not typed properly const parser = new jison.Generator(src, { moduleType: 'js', 'token-stack': true, diff --git a/.build/types.ts b/.build/types.ts index 4192407824..9dec05a68b 100644 --- a/.build/types.ts +++ b/.build/types.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-console */ import { packageOptions } from './common.js'; import { execSync } from 'child_process'; @@ -5,11 +6,17 @@ 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()); + if (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()); + if (e.stdout.length > 0) { + console.error(e.stdout.toString()); + } + if (e.stderr.length > 0) { + console.error(e.stderr.toString()); + } } }; diff --git a/.cspell/code-terms.txt b/.cspell/code-terms.txt index fa063616a7..9d2f700fcb 100644 --- a/.cspell/code-terms.txt +++ b/.cspell/code-terms.txt @@ -13,6 +13,7 @@ bqstring BQUOTE bramp BRKT +brotli callbackargs callbackname classdef @@ -27,6 +28,7 @@ controly CSSCLASS CYLINDEREND CYLINDERSTART +DAGA datakey DEND descr @@ -89,6 +91,7 @@ reqs rewritelinks rgba RIGHTOF +roughjs sankey sequencenumber shrc @@ -108,9 +111,11 @@ strikethrough stringifying struct STYLECLASS +STYLEDEF STYLEOPTS subcomponent subcomponents +subconfig SUBROUTINEEND SUBROUTINESTART Subschemas @@ -125,6 +130,7 @@ titlevalue topbar TRAPEND TRAPSTART +treemap ts-nocheck tsdoc typeof diff --git a/.cspell/contributors.txt b/.cspell/contributors.txt index bd3ad9da24..b7f52f8d0c 100644 --- a/.cspell/contributors.txt +++ b/.cspell/contributors.txt @@ -4,5 +4,6 @@ cpettitt Dong Cai Nikolay Rozhkov Peng Xiao +Per Brolin subhash-halder Vinod Sidharth diff --git a/.cspell/libraries.txt b/.cspell/libraries.txt index 9d29261868..c185429b09 100644 --- a/.cspell/libraries.txt +++ b/.cspell/libraries.txt @@ -20,6 +20,7 @@ dagre-d3 Deepdwn Docsify Docsy +Doctave DokuWiki dompurify elkjs @@ -54,13 +55,16 @@ presetAttributify pyplot redmine rehype +roughjs rscratch +shiki sparkline sphinxcontrib ssim stylis Swimm tsbuildinfo +tseslint Tuleap Typora unocss diff --git a/.cspell/mermaid-terms.txt b/.cspell/mermaid-terms.txt index 3fa5eff269..46ad6dddb1 100644 --- a/.cspell/mermaid-terms.txt +++ b/.cspell/mermaid-terms.txt @@ -9,6 +9,7 @@ elems gantt gitgraph gzipped +handDrawn knsv Knut marginx @@ -17,6 +18,7 @@ Markdownish mermaidjs mindmap mindmaps +mrtree multigraph nodesep NOTEGROUP diff --git a/.cspell/misc-terms.txt b/.cspell/misc-terms.txt index 467e48891e..3fc0943094 100644 --- a/.cspell/misc-terms.txt +++ b/.cspell/misc-terms.txt @@ -1 +1,6 @@ +BRANDES +circo +handDrawn +KOEPF +neato newbranch diff --git a/.esbuild/build.ts b/.esbuild/build.ts index 3c87f9d621..2bb42a557f 100644 --- a/.esbuild/build.ts +++ b/.esbuild/build.ts @@ -2,13 +2,14 @@ import { build } from 'esbuild'; import { mkdir, writeFile } from 'node:fs/promises'; import { packageOptions } from '../.build/common.js'; import { generateLangium } from '../.build/generateLangium.js'; -import { MermaidBuildOptions, defaultOptions, getBuildConfig } from './util.js'; +import type { MermaidBuildOptions } from './util.js'; +import { defaultOptions, getBuildConfig } from './util.js'; const shouldVisualize = process.argv.includes('--visualize'); const buildPackage = async (entryName: keyof typeof packageOptions) => { - const commonOptions = { ...defaultOptions, entryName } as const; - const buildConfigs = [ + const commonOptions: MermaidBuildOptions = { ...defaultOptions, entryName } as const; + const buildConfigs: MermaidBuildOptions[] = [ // package.mjs { ...commonOptions }, // package.min.mjs @@ -35,11 +36,11 @@ const buildPackage = async (entryName: keyof typeof packageOptions) => { if (shouldVisualize) { for (const { metafile } of results) { - if (!metafile) { + if (!metafile?.outputs) { continue; } const fileName = Object.keys(metafile.outputs) - .filter((file) => !file.includes('chunks') && file.endsWith('js'))[0] + .find((file) => !file.includes('chunks') && file.endsWith('js')) .replace('dist/', ''); // Upload metafile into https://esbuild.github.io/analyze/ await writeFile(`stats/${fileName}.meta.json`, JSON.stringify(metafile)); @@ -48,13 +49,14 @@ const buildPackage = async (entryName: keyof typeof packageOptions) => { }; const handler = (e) => { + // eslint-disable-next-line no-console console.error(e); process.exit(1); }; const main = async () => { await generateLangium(); - await mkdir('stats').catch(() => {}); + await mkdir('stats', { recursive: true }); const packageNames = Object.keys(packageOptions) as (keyof typeof packageOptions)[]; // it should build `parser` before `mermaid` because it's a dependency for (const pkg of packageNames) { diff --git a/.esbuild/jisonPlugin.ts b/.esbuild/jisonPlugin.ts index de801ea9f3..007516f089 100644 --- a/.esbuild/jisonPlugin.ts +++ b/.esbuild/jisonPlugin.ts @@ -1,6 +1,6 @@ import { readFile } from 'node:fs/promises'; import { transformJison } from '../.build/jisonTransformer.js'; -import { Plugin } from 'esbuild'; +import type { Plugin } from 'esbuild'; export const jisonPlugin: Plugin = { name: 'jison', diff --git a/.esbuild/server.ts b/.esbuild/server.ts index 9102c7de83..ef61ebec22 100644 --- a/.esbuild/server.ts +++ b/.esbuild/server.ts @@ -1,11 +1,12 @@ -import express from 'express'; -import type { NextFunction, Request, Response } from 'express'; +/* eslint-disable no-console */ +import chokidar from 'chokidar'; import cors from 'cors'; -import { getBuildConfig, defaultOptions } from './util.js'; import { context } from 'esbuild'; -import chokidar from 'chokidar'; -import { generateLangium } from '../.build/generateLangium.js'; +import type { Request, Response } from 'express'; +import express from 'express'; import { packageOptions } from '../.build/common.js'; +import { generateLangium } from '../.build/generateLangium.js'; +import { defaultOptions, getBuildConfig } from './util.js'; const configs = Object.values(packageOptions).map(({ packageName }) => getBuildConfig({ ...defaultOptions, minify: false, core: false, entryName: packageName }) @@ -19,16 +20,28 @@ const mermaidIIFEConfig = getBuildConfig({ }); configs.push(mermaidIIFEConfig); -const contexts = await Promise.all(configs.map((config) => context(config))); +const contexts = await Promise.all( + configs.map(async (config) => ({ config, context: await context(config) })) +); +let rebuildCounter = 1; const rebuildAll = async () => { - console.time('Rebuild time'); - await Promise.all(contexts.map((ctx) => ctx.rebuild())).catch((e) => console.error(e)); - console.timeEnd('Rebuild time'); + const buildNumber = rebuildCounter++; + const timeLabel = `Rebuild ${buildNumber} Time (total)`; + console.time(timeLabel); + await Promise.all( + contexts.map(async ({ config, context }) => { + const buildVariant = `Rebuild ${buildNumber} Time (${Object.keys(config.entryPoints!)[0]} ${config.format})`; + console.time(buildVariant); + await context.rebuild(); + console.timeEnd(buildVariant); + }) + ).catch((e) => console.error(e)); + console.timeEnd(timeLabel); }; let clients: { id: number; response: Response }[] = []; -function eventsHandler(request: Request, response: Response, next: NextFunction) { +function eventsHandler(request: Request, response: Response) { const headers = { 'Content-Type': 'text/event-stream', Connection: 'keep-alive', @@ -45,19 +58,20 @@ function eventsHandler(request: Request, response: Response, next: NextFunction) }); } -let timeoutId: NodeJS.Timeout | undefined = undefined; +let timeoutID: NodeJS.Timeout | undefined = undefined; /** * Debounce file change events to avoid rebuilding multiple times. */ function handleFileChange() { - if (timeoutId !== undefined) { - clearTimeout(timeoutId); + if (timeoutID !== undefined) { + clearTimeout(timeoutID); } - timeoutId = setTimeout(async () => { + // eslint-disable-next-line @typescript-eslint/no-misused-promises + timeoutID = setTimeout(async () => { await rebuildAll(); sendEventsToAll(); - timeoutId = undefined; + timeoutID = undefined; }, 100); } @@ -74,15 +88,16 @@ async function createServer() { ignoreInitial: true, ignored: [/node_modules/, /dist/, /docs/, /coverage/], }) + // eslint-disable-next-line @typescript-eslint/no-misused-promises .on('all', async (event, path) => { // Ignore other events. if (!['add', 'change'].includes(event)) { return; } - if (/\.langium$/.test(path)) { + console.log(`${path} changed. Rebuilding...`); + if (path.endsWith('.langium')) { await generateLangium(); } - console.log(`${path} changed. Rebuilding...`); handleFileChange(); }); @@ -99,4 +114,4 @@ async function createServer() { }); } -createServer(); +void createServer(); diff --git a/.esbuild/util.ts b/.esbuild/util.ts index 5c21cbf452..5221761138 100644 --- a/.esbuild/util.ts +++ b/.esbuild/util.ts @@ -8,7 +8,7 @@ import { jisonPlugin } from './jisonPlugin.js'; const __dirname = fileURLToPath(new URL('.', import.meta.url)); -export interface MermaidBuildOptions { +export interface MermaidBuildOptions extends BuildOptions { minify: boolean; core: boolean; metafile: boolean; @@ -56,7 +56,7 @@ export const getBuildConfig = (options: MermaidBuildOptions): BuildOptions => { const external: string[] = ['require', 'fs', 'path']; const { name, file, packageName } = packageOptions[entryName]; const outFileName = getFileName(name, options); - let output: BuildOptions = buildOptions({ + const output: BuildOptions = buildOptions({ absWorkingDir: resolve(__dirname, `../packages/${packageName}`), entryPoints: { [outFileName]: `src/${file}`, diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 08b265ba06..0000000000 --- a/.eslintignore +++ /dev/null @@ -1,11 +0,0 @@ -dist/** -.github/** -docs/Setup.md -cypress.config.js -cypress/plugins/index.js -coverage -*.json -node_modules - -# autogenereated by langium-cli -generated/ diff --git a/.eslintrc.cjs b/.eslintrc.cjs deleted file mode 100644 index dceb314c8e..0000000000 --- a/.eslintrc.cjs +++ /dev/null @@ -1,189 +0,0 @@ -module.exports = { - env: { - browser: true, - es6: true, - 'jest/globals': true, - node: true, - }, - root: true, - parser: '@typescript-eslint/parser', - parserOptions: { - ecmaFeatures: { - experimentalObjectRestSpread: true, - jsx: true, - }, - tsconfigRootDir: __dirname, - sourceType: 'module', - ecmaVersion: 2022, - allowAutomaticSingleRunInference: true, - project: ['./tsconfig.eslint.json', './packages/*/tsconfig.json'], - parser: '@typescript-eslint/parser', - }, - extends: [ - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', - 'plugin:json/recommended', - 'plugin:markdown/recommended-legacy', - 'plugin:@cspell/recommended', - 'prettier', - ], - plugins: [ - '@typescript-eslint', - 'no-only-tests', - 'html', - 'jest', - 'jsdoc', - 'json', - '@cspell', - 'lodash', - 'unicorn', - ], - ignorePatterns: [ - // this file is automatically generated by `pnpm run --filter mermaid types:build-config` - 'packages/mermaid/src/config.type.ts', - ], - rules: { - curly: 'error', - 'no-console': 'error', - 'no-prototype-builtins': 'off', - 'no-unused-vars': 'off', - 'cypress/no-async-tests': 'off', - '@typescript-eslint/consistent-type-imports': 'error', - '@typescript-eslint/no-explicit-any': 'warn', - '@typescript-eslint/no-floating-promises': 'error', - '@typescript-eslint/no-misused-promises': 'error', - '@typescript-eslint/no-unused-vars': 'warn', - '@typescript-eslint/ban-ts-comment': [ - 'error', - { - 'ts-expect-error': 'allow-with-description', - 'ts-ignore': 'allow-with-description', - 'ts-nocheck': 'allow-with-description', - 'ts-check': 'allow-with-description', - minimumDescriptionLength: 10, - }, - ], - '@typescript-eslint/naming-convention': [ - 'error', - { - selector: 'typeLike', - format: ['PascalCase'], - custom: { - regex: '^I[A-Z]', - match: false, - }, - }, - ], - 'json/*': ['error', 'allowComments'], - '@cspell/spellchecker': [ - 'error', - { - checkIdentifiers: true, - checkStrings: true, - checkStringTemplates: true, - }, - ], - 'no-empty': [ - 'error', - { - allowEmptyCatch: true, - }, - ], - 'no-only-tests/no-only-tests': 'error', - 'lodash/import-scope': ['error', 'method'], - 'unicorn/better-regex': 'error', - 'unicorn/no-abusive-eslint-disable': 'error', - 'unicorn/no-array-push-push': 'error', - 'unicorn/no-for-loop': 'error', - 'unicorn/no-instanceof-array': 'error', - 'unicorn/no-typeof-undefined': 'error', - 'unicorn/no-unnecessary-await': 'error', - 'unicorn/no-unsafe-regex': 'warn', - 'unicorn/no-useless-promise-resolve-reject': 'error', - 'unicorn/prefer-array-find': 'error', - 'unicorn/prefer-array-flat-map': 'error', - 'unicorn/prefer-array-index-of': 'error', - 'unicorn/prefer-array-some': 'error', - 'unicorn/prefer-default-parameters': 'error', - 'unicorn/prefer-includes': 'error', - 'unicorn/prefer-negative-index': 'error', - 'unicorn/prefer-object-from-entries': 'error', - 'unicorn/prefer-string-starts-ends-with': 'error', - 'unicorn/prefer-string-trim-start-end': 'error', - 'unicorn/string-content': 'error', - 'unicorn/prefer-spread': 'error', - 'unicorn/no-lonely-if': 'error', - }, - overrides: [ - { - files: ['cypress/**', 'demos/**'], - rules: { - 'no-console': 'off', - }, - }, - { - files: ['*.{js,jsx,mjs,cjs}'], - extends: ['plugin:jsdoc/recommended'], - rules: { - 'jsdoc/check-indentation': 'off', - 'jsdoc/check-alignment': 'off', - 'jsdoc/check-line-alignment': 'off', - 'jsdoc/multiline-blocks': 'off', - 'jsdoc/newline-after-description': 'off', - 'jsdoc/tag-lines': 'off', - 'jsdoc/require-param-description': 'off', - 'jsdoc/require-param-type': 'off', - 'jsdoc/require-returns': 'off', - 'jsdoc/require-returns-description': 'off', - }, - }, - { - files: ['*.{ts,tsx}'], - plugins: ['tsdoc'], - rules: { - 'no-restricted-syntax': [ - 'error', - { - selector: 'TSEnumDeclaration', - message: - 'Prefer using TypeScript union types over TypeScript enum, since TypeScript enums have a bunch of issues, see https://dev.to/dvddpl/whats-the-problem-with-typescript-enums-2okj', - }, - ], - 'tsdoc/syntax': 'error', - }, - }, - { - files: ['*.spec.{ts,js}', 'cypress/**', 'demos/**', '**/docs/**'], - rules: { - 'jsdoc/require-jsdoc': 'off', - '@typescript-eslint/no-unused-vars': 'off', - }, - }, - { - files: ['*.spec.{ts,js}', 'tests/**', 'cypress/**/*.js'], - rules: { - '@cspell/spellchecker': [ - 'error', - { - checkIdentifiers: false, - checkStrings: false, - checkStringTemplates: false, - }, - ], - }, - }, - { - files: ['*.html', '*.md', '**/*.md/*'], - rules: { - 'no-var': 'error', - 'no-undef': 'off', - '@typescript-eslint/no-unused-vars': 'off', - '@typescript-eslint/no-floating-promises': 'off', - '@typescript-eslint/no-misused-promises': 'off', - }, - parserOptions: { - project: null, - }, - }, - ], -}; diff --git a/.github/lychee.toml b/.github/lychee.toml index c5a2f0e452..2e3b08c413 100644 --- a/.github/lychee.toml +++ b/.github/lychee.toml @@ -41,7 +41,10 @@ exclude = [ "https://bundlephobia.com", # Chrome webstore migration issue. Temporary -"https://chromewebstore.google.com" +"https://chromewebstore.google.com", + +# Drupal 403 +"https://(www.)?drupal.org" ] # Exclude all private IPs from checking. diff --git a/.github/workflows/autofix.yml b/.github/workflows/autofix.yml new file mode 100644 index 0000000000..ef170fb710 --- /dev/null +++ b/.github/workflows/autofix.yml @@ -0,0 +1,41 @@ +name: autofix.ci # needed to securely identify the workflow + +on: + pull_request: +permissions: + contents: read + +jobs: + autofix: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v4 + # uses version from "packageManager" field in package.json + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + cache: pnpm + node-version-file: '.node-version' + + - name: Install Packages + run: | + pnpm install --frozen-lockfile + env: + CYPRESS_CACHE_FOLDER: .cache/Cypress + + - name: Fix Linting + shell: bash + run: pnpm -w run lint:fix + + - name: Sync `./src/config.type.ts` with `./src/schemas/config.schema.yaml` + shell: bash + run: pnpm run --filter mermaid types:build-config + + - name: Build Docs + working-directory: ./packages/mermaid + run: pnpm run docs:build + + - uses: autofix-ci/action@ff86a557419858bb967097bfc916833f5647fa8c diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index 87607bc2ff..0ce7789573 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -18,7 +18,7 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - uses: pnpm/action-setup@v2 + - uses: pnpm/action-setup@v4 - name: Setup Node.js uses: actions/setup-node@v4 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bf54772bce..c6e96912ef 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,7 +18,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v2 + - uses: pnpm/action-setup@v4 # uses version from "packageManager" field in package.json - name: Setup Node.js diff --git a/.github/workflows/e2e-applitools.yml b/.github/workflows/e2e-applitools.yml index 1238fe3713..5e5407a23b 100644 --- a/.github/workflows/e2e-applitools.yml +++ b/.github/workflows/e2e-applitools.yml @@ -32,7 +32,7 @@ jobs: - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v2 + - uses: pnpm/action-setup@v4 # uses version from "packageManager" field in package.json - name: Setup Node.js diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 6477c9eb5c..2600b3fb84 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -1,9 +1,3 @@ -# 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 on: @@ -30,6 +24,7 @@ env: ) || github.event.before }} + shouldRunParallel: ${{ secrets.CYPRESS_RECORD_KEY != '' && !(github.event_name == 'push' && github.ref == 'refs/heads/develop') }} jobs: cache: runs-on: ubuntu-latest @@ -38,7 +33,7 @@ jobs: options: --user 1001 steps: - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v2 + - uses: pnpm/action-setup@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: @@ -72,16 +67,6 @@ jobs: mkdir -p cypress/snapshots/stats/base mv stats cypress/snapshots/stats/base - - name: Cypress run - uses: cypress-io/github-action@v6 - id: cypress-snapshot-gen - if: ${{ steps.cache-snapshot.outputs.cache-hit != 'true' }} - with: - install: false - start: pnpm run dev - wait-on: 'http://localhost:9000' - browser: chrome - e2e: runs-on: ubuntu-latest container: @@ -95,7 +80,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v2 + - uses: pnpm/action-setup@v4 # uses version from "packageManager" field in package.json - name: Setup Node.js @@ -132,7 +117,7 @@ jobs: id: cypress # If CYPRESS_RECORD_KEY is set, run in parallel on all containers # Otherwise (e.g. if running from fork), we run on a single container only - if: ${{ ( env.CYPRESS_RECORD_KEY != '' ) || ( matrix.containers == 1 ) }} + if: ${{ env.shouldRunParallel == 'true' || ( matrix.containers == 1 ) }} with: install: false start: pnpm run dev:coverage @@ -140,12 +125,16 @@ jobs: browser: chrome # Disable recording if we don't have an API key # e.g. if this action was run from a fork - record: ${{ secrets.CYPRESS_RECORD_KEY != '' }} - parallel: ${{ secrets.CYPRESS_RECORD_KEY != '' }} + record: ${{ env.shouldRunParallel == 'true' }} + parallel: ${{ env.shouldRunParallel == 'true' }} env: CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} VITEST_COVERAGE: true CYPRESS_COMMIT: ${{ github.sha }} + ARGOS_TOKEN: ${{ secrets.ARGOS_TOKEN }} + ARGOS_PARALLEL: ${{ env.shouldRunParallel == 'true' }} + ARGOS_PARALLEL_TOTAL: 4 + ARGOS_PARALLEL_INDEX: ${{ matrix.containers }} - name: Upload Coverage to Codecov uses: codecov/codecov-action@v4 @@ -158,55 +147,3 @@ jobs: fail_ci_if_error: false verbose: true token: 6845cc80-77ee-4e17-85a1-026cd95e0766 - - # We upload the artifacts into numbered archives to prevent overwriting - - name: Upload Artifacts - uses: actions/upload-artifact@v4 - 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@v4 - 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: - name: error-snapshots - 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 }}" diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 8f5995d717..632cd6ddc4 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -19,7 +19,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v2 + - uses: pnpm/action-setup@v4 # uses version from "packageManager" field in package.json - name: Setup Node.js @@ -82,15 +82,3 @@ jobs: working-directory: ./packages/mermaid continue-on-error: ${{ github.event_name == 'push' }} run: pnpm run docs:verify - - - name: Rebuild Docs - if: ${{ steps.verifyDocs.outcome == 'failure' && github.event_name == 'push' }} - working-directory: ./packages/mermaid - run: pnpm run docs:build - - - name: Commit changes - uses: EndBug/add-and-commit@v9 - if: ${{ steps.verifyDocs.outcome == 'failure' && github.event_name == 'push' }} - with: - message: 'Update docs' - add: 'docs/*' diff --git a/.github/workflows/publish-docs.yml b/.github/workflows/publish-docs.yml index fb70a90ecd..4ff5f41170 100644 --- a/.github/workflows/publish-docs.yml +++ b/.github/workflows/publish-docs.yml @@ -25,7 +25,7 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - uses: pnpm/action-setup@v2 + - uses: pnpm/action-setup@v4 - name: Setup Node.js uses: actions/setup-node@v4 diff --git a/.github/workflows/release-preview-publish.yml b/.github/workflows/release-preview-publish.yml index c763430b04..91e3ac9813 100644 --- a/.github/workflows/release-preview-publish.yml +++ b/.github/workflows/release-preview-publish.yml @@ -13,7 +13,7 @@ jobs: with: fetch-depth: 0 - - uses: pnpm/action-setup@v2 + - uses: pnpm/action-setup@v4 - name: Setup Node.js uses: actions/setup-node@v4 diff --git a/.github/workflows/release-publish.yml b/.github/workflows/release-publish.yml index dce461cf57..4dcf709c01 100644 --- a/.github/workflows/release-publish.yml +++ b/.github/workflows/release-publish.yml @@ -11,7 +11,7 @@ jobs: - uses: actions/checkout@v4 - uses: fregante/setup-git-user@v2 - - uses: pnpm/action-setup@v2 + - uses: pnpm/action-setup@v4 # uses version from "packageManager" field in package.json - name: Setup Node.js diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a4bd264e05..a0b284a68f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,7 +11,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v2 + - uses: pnpm/action-setup@v4 # uses version from "packageManager" field in package.json - name: Setup Node.js diff --git a/.github/workflows/update-browserlist.yml b/.github/workflows/update-browserlist.yml index 9aac3d7b3b..f8f7696cde 100644 --- a/.github/workflows/update-browserlist.yml +++ b/.github/workflows/update-browserlist.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v2 + - uses: pnpm/action-setup@v4 - run: npx update-browserslist-db@latest - name: Commit changes uses: EndBug/add-and-commit@v9 diff --git a/.gitignore b/.gitignore index a0fd1c50b8..7448f2a810 100644 --- a/.gitignore +++ b/.gitignore @@ -35,7 +35,7 @@ cypress/snapshots/ .tsbuildinfo tsconfig.tsbuildinfo -knsv*.html +#knsv*.html local*.html stats/ @@ -48,6 +48,7 @@ demos/dev/** !/demos/dev/example.html !/demos/dev/reload.js tsx-0/** +vite.config.ts.timestamp-* # autogenereated by langium-cli -generated/ \ No newline at end of file +generated/ diff --git a/.node-version b/.node-version index ee09fac75c..87834047a6 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -v20.11.1 +20.12.2 diff --git a/.prettierignore b/.prettierignore index 7da0646e32..c700804260 100644 --- a/.prettierignore +++ b/.prettierignore @@ -16,3 +16,5 @@ generated/ # Ignore the files creates in /demos/dev except for example.html demos/dev/** !/demos/dev/example.html +# TODO: Lots of errors to fix +cypress/platform/state-refactor.html diff --git a/.vite/build.ts b/.vite/build.ts index 7ce93a497f..486d594525 100644 --- a/.vite/build.ts +++ b/.vite/build.ts @@ -1,4 +1,5 @@ -import { build, InlineConfig, type PluginOption } from 'vite'; +import type { InlineConfig } from 'vite'; +import { build, type PluginOption } from 'vite'; import { resolve } from 'path'; import { fileURLToPath } from 'url'; import jisonPlugin from './jisonPlugin.js'; @@ -46,9 +47,10 @@ interface BuildOptions { export const getBuildConfig = ({ minify, core, watch, entryName }: BuildOptions): InlineConfig => { const external: (string | RegExp)[] = ['require', 'fs', 'path']; + // eslint-disable-next-line no-console console.log(entryName, packageOptions[entryName]); const { name, file, packageName } = packageOptions[entryName]; - let output: OutputOptions = [ + const output: OutputOptions = [ { name, format: 'esm', @@ -83,7 +85,6 @@ export const getBuildConfig = ({ minify, core, watch, entryName }: BuildOptions) plugins: [ jisonPlugin(), jsonSchemaPlugin(), // handles `.schema.yaml` files - // @ts-expect-error According to the type definitions, rollup plugins are incompatible with vite typescript({ compilerOptions: { declaration: false } }), istanbul({ exclude: ['node_modules', 'test/', '__mocks__', 'generated'], @@ -121,10 +122,10 @@ await generateLangium(); if (watch) { await build(getBuildConfig({ minify: false, watch, core: false, entryName: 'parser' })); - build(getBuildConfig({ minify: false, watch, core: false, entryName: 'mermaid' })); + void build(getBuildConfig({ minify: false, watch, core: false, entryName: 'mermaid' })); if (!mermaidOnly) { - build(getBuildConfig({ minify: false, watch, entryName: 'mermaid-example-diagram' })); - build(getBuildConfig({ minify: false, watch, entryName: 'mermaid-zenuml' })); + void build(getBuildConfig({ minify: false, watch, entryName: 'mermaid-example-diagram' })); + void build(getBuildConfig({ minify: false, watch, entryName: 'mermaid-zenuml' })); } } else if (visualize) { await build(getBuildConfig({ minify: false, watch, core: false, entryName: 'parser' })); diff --git a/.vite/jsonSchemaPlugin.ts b/.vite/jsonSchemaPlugin.ts index 2e5b5cc0b5..3614d5b457 100644 --- a/.vite/jsonSchemaPlugin.ts +++ b/.vite/jsonSchemaPlugin.ts @@ -1,4 +1,4 @@ -import { PluginOption } from 'vite'; +import type { PluginOption } from 'vite'; import { getDefaults, getSchema, loadSchema } from '../.build/jsonSchema.js'; /** diff --git a/.vite/server.ts b/.vite/server.ts index 99d16f6f24..078599dc1c 100644 --- a/.vite/server.ts +++ b/.vite/server.ts @@ -23,8 +23,9 @@ async function createServer() { app.use(express.static('cypress/platform')); app.listen(9000, () => { + // eslint-disable-next-line no-console console.log(`Listening on http://localhost:9000`); }); } -createServer(); +void createServer(); diff --git a/Dockerfile b/Dockerfile index 1cc9ef0306..7bec3bd4b7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,2 +1,2 @@ -FROM node:20.11.1-alpine3.19 AS base +FROM node:20.12.2-alpine3.19 AS base RUN wget -qO- https://get.pnpm.io/install.sh | ENV="$HOME/.shrc" SHELL="$(which sh)" sh - diff --git a/FUNDING.json b/FUNDING.json new file mode 100644 index 0000000000..a1df876f47 --- /dev/null +++ b/FUNDING.json @@ -0,0 +1,7 @@ +{ + "drips": { + "ethereum": { + "ownedBy": "0x0831DDFe60d009d9448CC976157b539089aB821E" + } + } +} diff --git a/README.md b/README.md index d368a43499..8d5eebfebe 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ Try Live Editor previews of future releases: diff --git a/cypress.config.ts b/cypress.config.ts index 4182d92a87..3346b5549b 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -2,6 +2,8 @@ import { defineConfig } from 'cypress'; import { addMatchImageSnapshotPlugin } from 'cypress-image-snapshot/plugin'; import coverage from '@cypress/code-coverage/task'; import eyesPlugin from '@applitools/eyes-cypress'; +import { registerArgosTask } from '@argos-ci/cypress/task'; + export default eyesPlugin( defineConfig({ projectId: 'n2sma2', @@ -17,10 +19,17 @@ export default eyesPlugin( } return launchOptions; }); - addMatchImageSnapshotPlugin(on, config); // copy any needed variables from process.env to config.env config.env.useAppli = process.env.USE_APPLI ? true : false; + config.env.useArgos = !!process.env.CI; + if (config.env.useArgos) { + registerArgosTask(on, config, { + token: 'fc3a35cf5200db928d65b2047861582d9444032b', + }); + } else { + addMatchImageSnapshotPlugin(on, config); + } // do not forget to return the changed config object! return config; }, diff --git a/cypress/helpers/util.ts b/cypress/helpers/util.ts index aed5d7973c..133a350328 100644 --- a/cypress/helpers/util.ts +++ b/cypress/helpers/util.ts @@ -35,7 +35,7 @@ export const mermaidUrl = ( }; const objStr: string = JSON.stringify(codeObject); let url = `http://localhost:9000/e2e.html?graph=${utf8ToB64(objStr)}`; - if (api) { + if (api && typeof graphStr === 'string') { url = `http://localhost:9000/xss.html?graph=${graphStr}`; } @@ -54,16 +54,15 @@ export const imgSnapshotTest = ( ): void => { const options: CypressMermaidConfig = { ..._options, - fontFamily: _options.fontFamily || 'courier', + fontFamily: _options.fontFamily ?? 'courier', // @ts-ignore TODO: Fix type of fontSize - fontSize: _options.fontSize || '16px', + fontSize: _options.fontSize ?? '16px', sequence: { - ...(_options.sequence || {}), + ...(_options.sequence ?? {}), actorFontFamily: 'courier', - noteFontFamily: - _options.sequence && _options.sequence.noteFontFamily - ? _options.sequence.noteFontFamily - : 'courier', + noteFontFamily: _options.sequence?.noteFontFamily + ? _options.sequence.noteFontFamily + : 'courier', messageFontFamily: 'courier', }, }; @@ -95,18 +94,7 @@ export const openURLAndVerifyRendering = ( options: CypressMermaidConfig, validation?: any ): void => { - const useAppli: boolean = Cypress.env('useAppli'); - const name: string = (options.name || cy.state('runnable').fullTitle()).replace(/\s+/g, '-'); - - if (useAppli) { - cy.log(`Opening eyes ${Cypress.spec.name} --- ${name}`); - cy.eyesOpen({ - appName: 'Mermaid', - testName: name, - batchName: Cypress.spec.name, - batchId: batchId + Cypress.spec.name, - }); - } + const name: string = (options.name ?? cy.state('runnable').fullTitle()).replace(/\s+/g, '-'); cy.visit(url); cy.window().should('have.property', 'rendered', true); @@ -116,11 +104,29 @@ export const openURLAndVerifyRendering = ( cy.get('svg').should(validation); } + verifyScreenshot(name); +}; + +export const verifyScreenshot = (name: string): void => { + const useAppli: boolean = Cypress.env('useAppli'); + const useArgos: boolean = Cypress.env('useArgos'); + if (useAppli) { + cy.log(`Opening eyes ${Cypress.spec.name} --- ${name}`); + cy.eyesOpen({ + appName: 'Mermaid', + testName: name, + batchName: Cypress.spec.name, + batchId: batchId + Cypress.spec.name, + }); cy.log(`Check eyes ${Cypress.spec.name}`); cy.eyesCheckWindow('Click!'); cy.log(`Closing eyes ${Cypress.spec.name}`); cy.eyesClose(); + } else if (useArgos) { + cy.argosScreenshot(name, { + threshold: 0.01, + }); } else { cy.matchImageSnapshot(name); } diff --git a/cypress/integration/other/configuration.spec.js b/cypress/integration/other/configuration.spec.js index 544eab40fb..ad6b21e298 100644 --- a/cypress/integration/other/configuration.spec.js +++ b/cypress/integration/other/configuration.spec.js @@ -1,4 +1,4 @@ -import { renderGraph } from '../../helpers/util.ts'; +import { renderGraph, verifyScreenshot } from '../../helpers/util.ts'; describe('Configuration', () => { describe('arrowMarkerAbsolute', () => { it('should handle default value false of arrowMarkerAbsolute', () => { @@ -119,8 +119,7 @@ describe('Configuration', () => { const url = 'http://localhost:9000/regression/issue-1874.html'; cy.visit(url); cy.window().should('have.property', 'rendered', true); - cy.get('svg').should('be.visible'); - cy.matchImageSnapshot( + verifyScreenshot( 'configuration.spec-should-not-taint-initial-configuration-when-using-multiple-directives' ); }); @@ -145,7 +144,7 @@ describe('Configuration', () => { // none of the diagrams should be error diagrams expect($svg).to.not.contain('Syntax error'); }); - cy.matchImageSnapshot( + verifyScreenshot( 'configuration.spec-should-not-render-error-diagram-if-suppressErrorRendering-is-set' ); }); @@ -162,7 +161,7 @@ describe('Configuration', () => { // some of the diagrams should be error diagrams expect($svg).to.contain('Syntax error'); }); - cy.matchImageSnapshot( + verifyScreenshot( 'configuration.spec-should-render-error-diagram-if-suppressErrorRendering-is-not-set' ); }); diff --git a/cypress/integration/other/flowchart-elk.spec.js b/cypress/integration/other/flowchart-elk.spec.js deleted file mode 100644 index 22a6efc0f5..0000000000 --- a/cypress/integration/other/flowchart-elk.spec.js +++ /dev/null @@ -1,14 +0,0 @@ -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', - }); - }); -}); diff --git a/cypress/integration/other/xss.spec.js b/cypress/integration/other/xss.spec.js index 678040f98a..1e51d2f234 100644 --- a/cypress/integration/other/xss.spec.js +++ b/cypress/integration/other/xss.spec.js @@ -10,7 +10,6 @@ describe('XSS', () => { cy.wait(1000).then(() => { cy.get('.mermaid').should('exist'); }); - cy.get('svg'); }); it('should not allow tags in the css', () => { @@ -137,4 +136,9 @@ describe('XSS', () => { cy.wait(1000); cy.get('#the-malware').should('not.exist'); }); + it('should sanitize backticks block diagram labels properly', () => { + cy.visit('http://localhost:9000/xss25.html'); + cy.wait(1000); + cy.get('#the-malware').should('not.exist'); + }); }); diff --git a/cypress/integration/rendering/appli.spec.js b/cypress/integration/rendering/appli.spec.js index 5def968157..51eeb657eb 100644 --- a/cypress/integration/rendering/appli.spec.js +++ b/cypress/integration/rendering/appli.spec.js @@ -11,6 +11,27 @@ describe('Git Graph diagram', () => { {} ); }); + 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 } } } + ); + }); // it(`ultraFastTest`, function () { // // Navigate to the url we want to test // // ⭐️ Note to see visual bugs, run the test using the above URL for the 1st run. diff --git a/cypress/integration/rendering/block.spec.js b/cypress/integration/rendering/block.spec.js index 9d62c642dc..f5d5103e89 100644 --- a/cypress/integration/rendering/block.spec.js +++ b/cypress/integration/rendering/block.spec.js @@ -236,7 +236,7 @@ describe('Block diagram', () => { ); }); - it('BL16: width alignment - blocks shold be equal in width', () => { + it('BL17: width alignment - blocks shold be equal in width', () => { imgSnapshotTest( `block-beta A("This is the text") @@ -247,7 +247,7 @@ describe('Block diagram', () => { ); }); - it('BL17: block types 1 - square, rounded and circle', () => { + it('BL18: block types 1 - square, rounded and circle', () => { imgSnapshotTest( `block-beta A["square"] @@ -258,7 +258,7 @@ describe('Block diagram', () => { ); }); - it('BL18: block types 2 - odd, diamond and hexagon', () => { + it('BL19: block types 2 - odd, diamond and hexagon', () => { imgSnapshotTest( `block-beta A>"rect_left_inv_arrow"] @@ -269,7 +269,7 @@ describe('Block diagram', () => { ); }); - it('BL19: block types 3 - stadium', () => { + it('BL20: block types 3 - stadium', () => { imgSnapshotTest( `block-beta A(["stadium"]) @@ -278,7 +278,7 @@ describe('Block diagram', () => { ); }); - it('BL20: block types 4 - lean right, lean left, trapezoid and inv trapezoid', () => { + it('BL21: block types 4 - lean right, lean left, trapezoid and inv trapezoid', () => { imgSnapshotTest( `block-beta A[/"lean right"/] @@ -290,7 +290,7 @@ describe('Block diagram', () => { ); }); - it('BL21: block types 1 - square, rounded and circle', () => { + it('BL22: block types 1 - square, rounded and circle', () => { imgSnapshotTest( `block-beta A["square"] @@ -301,7 +301,7 @@ describe('Block diagram', () => { ); }); - it('BL22: sizing - it should be possible to make a block wider', () => { + it('BL23: sizing - it should be possible to make a block wider', () => { imgSnapshotTest( `block-beta A("rounded"):2 @@ -312,7 +312,7 @@ describe('Block diagram', () => { ); }); - it('BL23: sizing - it should be possible to make a composite block wider', () => { + it('BL24: sizing - it should be possible to make a composite block wider', () => { imgSnapshotTest( `block-beta block:2 @@ -324,7 +324,7 @@ describe('Block diagram', () => { ); }); - it('BL24: block in the middle with space on each side', () => { + it('BL25: block in the middle with space on each side', () => { imgSnapshotTest( `block-beta columns 3 @@ -335,7 +335,7 @@ describe('Block diagram', () => { {} ); }); - it('BL25: space and an edge', () => { + it('BL26: space and an edge', () => { imgSnapshotTest( `block-beta columns 5 @@ -345,7 +345,7 @@ describe('Block diagram', () => { {} ); }); - it('BL26: block sizes for regular blocks', () => { + it('BL27: block sizes for regular blocks', () => { imgSnapshotTest( `block-beta columns 3 @@ -354,7 +354,7 @@ describe('Block diagram', () => { {} ); }); - it('BL27: composite block with a set width - f should use the available space', () => { + it('BL28: composite block with a set width - f should use the available space', () => { imgSnapshotTest( `block-beta columns 3 @@ -363,11 +363,12 @@ describe('Block diagram', () => { f end g - `, + `, {} ); }); - it('BL23: composite block with a set width - f and g should split the available space', () => { + + it('BL29: composite block with a set width - f and g should split the available space', () => { imgSnapshotTest( `block-beta columns 3 @@ -379,7 +380,7 @@ describe('Block diagram', () => { h i j - `, + `, {} ); }); diff --git a/cypress/integration/rendering/c4.spec.js b/cypress/integration/rendering/c4.spec.js index 59af6504b9..00e71adec8 100644 --- a/cypress/integration/rendering/c4.spec.js +++ b/cypress/integration/rendering/c4.spec.js @@ -1,7 +1,7 @@ import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts'; describe('C4 diagram', () => { - it('should render a simple C4Context diagram', () => { + it('C4.1 should render a simple C4Context diagram', () => { imgSnapshotTest( ` C4Context @@ -30,9 +30,8 @@ describe('C4 diagram', () => { `, {} ); - cy.get('svg'); }); - it('should render a simple C4Container diagram', () => { + it('C4.2 should render a simple C4Container diagram', () => { imgSnapshotTest( ` C4Container @@ -50,9 +49,8 @@ describe('C4 diagram', () => { `, {} ); - cy.get('svg'); }); - it('should render a simple C4Component diagram', () => { + it('C4.3 should render a simple C4Component diagram', () => { imgSnapshotTest( ` C4Component @@ -69,9 +67,8 @@ describe('C4 diagram', () => { `, {} ); - cy.get('svg'); }); - it('should render a simple C4Dynamic diagram', () => { + it('C4.4 should render a simple C4Dynamic diagram', () => { imgSnapshotTest( ` C4Dynamic @@ -93,9 +90,8 @@ describe('C4 diagram', () => { `, {} ); - cy.get('svg'); }); - it('should render a simple C4Deployment diagram', () => { + it('C4.5 should render a simple C4Deployment diagram', () => { imgSnapshotTest( ` C4Deployment @@ -117,6 +113,5 @@ describe('C4 diagram', () => { `, {} ); - cy.get('svg'); }); }); diff --git a/cypress/integration/rendering/classDiagram-v2.spec.js b/cypress/integration/rendering/classDiagram-v2.spec.js index 20a1aea0ab..258f8529f6 100644 --- a/cypress/integration/rendering/classDiagram-v2.spec.js +++ b/cypress/integration/rendering/classDiagram-v2.spec.js @@ -76,7 +76,7 @@ describe('Class diagram V2', () => { ); }); - it('should render a simple class diagram with different visibilities', () => { + it('2.1 should render a simple class diagram with different visibilities', () => { imgSnapshotTest( ` classDiagram-v2 @@ -93,7 +93,7 @@ describe('Class diagram V2', () => { ); }); - it('should render multiple class diagrams', () => { + it('3: should render multiple class diagrams', () => { imgSnapshotTest( [ ` diff --git a/cypress/integration/rendering/classDiagram.spec.js b/cypress/integration/rendering/classDiagram.spec.js index cab3649df4..a98a359edf 100644 --- a/cypress/integration/rendering/classDiagram.spec.js +++ b/cypress/integration/rendering/classDiagram.spec.js @@ -32,7 +32,6 @@ describe('Class diagram', () => { `, { logLevel: 1 } ); - cy.get('svg'); }); it('2: should render a simple class diagrams with cardinality', () => { @@ -61,7 +60,6 @@ describe('Class diagram', () => { `, {} ); - cy.get('svg'); }); it('3: should render a simple class diagram with different visibilities', () => { @@ -79,7 +77,6 @@ describe('Class diagram', () => { `, {} ); - cy.get('svg'); }); it('4: should render a simple class diagram with comments', () => { @@ -109,7 +106,6 @@ describe('Class diagram', () => { `, {} ); - cy.get('svg'); }); it('5: should render a simple class diagram with abstract method', () => { @@ -121,7 +117,6 @@ describe('Class diagram', () => { `, {} ); - cy.get('svg'); }); it('6: should render a simple class diagram with static method', () => { @@ -133,7 +128,6 @@ describe('Class diagram', () => { `, {} ); - cy.get('svg'); }); it('7: should render a simple class diagram with Generic class', () => { @@ -153,7 +147,6 @@ describe('Class diagram', () => { `, {} ); - cy.get('svg'); }); it('8: should render a simple class diagram with Generic class and relations', () => { @@ -174,7 +167,6 @@ describe('Class diagram', () => { `, {} ); - cy.get('svg'); }); it('9: should render a simple class diagram with clickable link', () => { @@ -196,7 +188,6 @@ describe('Class diagram', () => { `, {} ); - cy.get('svg'); }); it('10: should render a simple class diagram with clickable callback', () => { @@ -218,7 +209,6 @@ describe('Class diagram', () => { `, {} ); - cy.get('svg'); }); it('11: should render a simple class diagram with return type on method', () => { @@ -233,7 +223,6 @@ describe('Class diagram', () => { `, {} ); - cy.get('svg'); }); it('12: should render a simple class diagram with generic types', () => { @@ -249,7 +238,6 @@ describe('Class diagram', () => { `, {} ); - cy.get('svg'); }); it('13: should render a simple class diagram with css classes applied', () => { @@ -267,7 +255,6 @@ describe('Class diagram', () => { `, {} ); - cy.get('svg'); }); it('14: should render a simple class diagram with css classes applied directly', () => { @@ -283,7 +270,6 @@ describe('Class diagram', () => { `, {} ); - cy.get('svg'); }); it('15: should render a simple class diagram with css classes applied to multiple classes', () => { @@ -298,7 +284,6 @@ describe('Class diagram', () => { `, {} ); - cy.get('svg'); }); it('16: should render multiple class diagrams', () => { @@ -351,7 +336,6 @@ describe('Class diagram', () => { ], {} ); - cy.get('svg'); }); // it('17: should render a class diagram when useMaxWidth is true (default)', () => { @@ -421,7 +405,6 @@ describe('Class diagram', () => { `, { logLevel: 1 } ); - cy.get('svg'); }); it('should render class diagram with newlines in title', () => { @@ -439,7 +422,6 @@ describe('Class diagram', () => { +quack() } `); - cy.get('svg'); }); it('should render class diagram with many newlines in title', () => { diff --git a/cypress/integration/rendering/erDiagram.spec.js b/cypress/integration/rendering/erDiagram.spec.js index 578f5a3984..1a2340906a 100644 --- a/cypress/integration/rendering/erDiagram.spec.js +++ b/cypress/integration/rendering/erDiagram.spec.js @@ -218,7 +218,6 @@ describe('Entity Relationship Diagram', () => { `, { loglevel: 1 } ); - cy.get('svg'); }); it('should render entities with keys', () => { diff --git a/cypress/integration/rendering/errorDiagram.spec.js b/cypress/integration/rendering/errorDiagram.spec.js index e837565d3a..9eeb2e3106 100644 --- a/cypress/integration/rendering/errorDiagram.spec.js +++ b/cypress/integration/rendering/errorDiagram.spec.js @@ -3,7 +3,7 @@ import { imgSnapshotTest } from '../../helpers/util'; describe('Error Diagrams', () => { beforeEach(() => { cy.on('uncaught:exception', (err) => { - expect(err.message).to.include('Parse error'); + expect(err.message).to.include('error'); // return false to prevent the error from // failing this test return false; diff --git a/cypress/integration/rendering/flowchart-elk.spec.js b/cypress/integration/rendering/flowchart-elk.spec.js index e931025e91..b5caef9733 100644 --- a/cypress/integration/rendering/flowchart-elk.spec.js +++ b/cypress/integration/rendering/flowchart-elk.spec.js @@ -837,6 +837,26 @@ subgraph "\`**Two**\`" in the hat\`") -- "\`1o **ipa**\`" --> d("The dog in the hog") end +`, + { flowchart: { titleTopMargin: 0 } } + ); + }); + it('Sub graphs and markdown strings', () => { + imgSnapshotTest( + `--- +config: + layout: elk +--- + +flowchart LR + subgraph subgraph_ko6czgs5u["Untitled subgraph"] + D["Option 1"] + end + C{"Evaluate"} -- One --> D + C -- Two --> E(("Option 2")) + D --> E + A["A"] + `, { flowchart: { titleTopMargin: 0 } } ); @@ -855,7 +875,7 @@ describe('Title and arrow styling #4813', () => { flowchart LR A-->B A-->C`, - { flowchart: { defaultRenderer: 'elk' } } + { layout: 'elk' } ); cy.get('svg').should((svg) => { const title = svg[0].querySelector('text'); @@ -871,15 +891,14 @@ describe('Title and arrow styling #4813', () => { B-.-oC C==xD D ~~~ A`, - { flowchart: { defaultRenderer: 'elk' } } + { layout: 'elk' } ); cy.get('svg').should((svg) => { const edges = svg[0].querySelectorAll('.edges path'); - console.log(edges); - expect(edges[0]).to.have.attr('pattern', 'solid'); - expect(edges[1]).to.have.attr('pattern', 'dotted'); - expect(edges[2]).to.have.css('stroke-width', '3.5px'); - expect(edges[3]).to.have.css('stroke-width', '1.5px'); + expect(edges[0].getAttribute('class')).to.contain('edge-pattern-solid'); + expect(edges[1].getAttribute('class')).to.contain('edge-pattern-dotted'); + expect(edges[2].getAttribute('class')).to.contain('edge-thickness-thick'); + expect(edges[3].getAttribute('class')).to.contain('edge-thickness-invisible'); }); }); }); diff --git a/cypress/integration/rendering/flowchart-handDrawn.spec.js b/cypress/integration/rendering/flowchart-handDrawn.spec.js new file mode 100644 index 0000000000..d2e3edde0f --- /dev/null +++ b/cypress/integration/rendering/flowchart-handDrawn.spec.js @@ -0,0 +1,1060 @@ +import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts'; + +describe('Flowchart HandDrawn', () => { + it('FHD1: should render a simple flowchart no htmlLabels', () => { + imgSnapshotTest( + `graph TD + A[Christmas] -->|Get money| B(Go shopping) + B --> C{Let me think} + C -->|One| D[Laptop] + C -->|Two| E[iPhone] + C -->|Three| F[fa:fa-car Car] + `, + { + look: 'handDrawn', + handDrawnSeed: 0, + flowchart: { htmlLabels: false }, + fontFamily: 'courier', + } + ); + }); + + it('FHD2: should render a simple flowchart with htmlLabels', () => { + imgSnapshotTest( + `graph TD + A[Christmas] -->|Get money| B(Go shopping) + B --> C{Let me think} + C -->|One| D[Laptop] + C -->|Two| E[iPhone] + C -->|Three| F[fa:fa-car Car] + `, + { + look: 'handDrawn', + handDrawnSeed: 0, + flowchart: { htmlLabels: true }, + fontFamily: 'courier', + } + ); + }); + + it('FHD3: should render a simple flowchart with line breaks', () => { + imgSnapshotTest( + ` + graph TD + A[Christmas] -->|Get money| B(Go shopping) + B --> C{Let me thinksssss
ssssssssssssssssssssss
sssssssssssssssssssssssssss} + C -->|One| D[Laptop] + C -->|Two| E[iPhone] + C -->|Three| F[Car] + `, + { look: 'handDrawn', handDrawnSeed: 0, fontFamily: 'courier' } + ); + }); + + it('FHD4: should render a simple flowchart with trapezoid and inverse trapezoid vertex options.', () => { + imgSnapshotTest( + ` + graph TD + A[/Christmas\\] + A -->|Get money| B[\\Go shopping/] + B --> C{Let me thinksssss
ssssssssssssssssssssss
sssssssssssssssssssssssssss} + C -->|One| D[/Laptop/] + C -->|Two| E[\\iPhone\\] + C -->|Three| F[Car] + `, + { look: 'handDrawn', handDrawnSeed: 0, fontFamily: 'courier' } + ); + }); + + it('FHD5: should style nodes via a class.', () => { + imgSnapshotTest( + ` + graph TD + 1A --> 1B + 1B --> 1C + 1C --> D + 1C --> E + + classDef processHead fill:#888888,color:white,font-weight:bold,stroke-width:3px,stroke:#001f3f + class 1A,1B,D,E processHead + `, + { look: 'handDrawn', handDrawnSeed: 0, fontFamily: 'courier' } + ); + }); + + it('FHD6: should render a flowchart full of circles', () => { + imgSnapshotTest( + ` + graph LR + 47(SAM.CommonFA.FMESummary)-->48(SAM.CommonFA.CommonFAFinanceBudget) + 37(SAM.CommonFA.BudgetSubserviceLineVolume)-->48(SAM.CommonFA.CommonFAFinanceBudget) + 35(SAM.CommonFA.PopulationFME)-->47(SAM.CommonFA.FMESummary) + 41(SAM.CommonFA.MetricCost)-->47(SAM.CommonFA.FMESummary) + 44(SAM.CommonFA.MetricOutliers)-->47(SAM.CommonFA.FMESummary) + 46(SAM.CommonFA.MetricOpportunity)-->47(SAM.CommonFA.FMESummary) + 40(SAM.CommonFA.OPVisits)-->47(SAM.CommonFA.FMESummary) + 38(SAM.CommonFA.CommonFAFinanceRefund)-->47(SAM.CommonFA.FMESummary) + 43(SAM.CommonFA.CommonFAFinancePicuDays)-->47(SAM.CommonFA.FMESummary) + 42(SAM.CommonFA.CommonFAFinanceNurseryDays)-->47(SAM.CommonFA.FMESummary) + 45(SAM.CommonFA.MetricPreOpportunity)-->46(SAM.CommonFA.MetricOpportunity) + 35(SAM.CommonFA.PopulationFME)-->45(SAM.CommonFA.MetricPreOpportunity) + 41(SAM.CommonFA.MetricCost)-->45(SAM.CommonFA.MetricPreOpportunity) + 41(SAM.CommonFA.MetricCost)-->44(SAM.CommonFA.MetricOutliers) + 39(SAM.CommonFA.ChargeDetails)-->43(SAM.CommonFA.CommonFAFinancePicuDays) + 39(SAM.CommonFA.ChargeDetails)-->42(SAM.CommonFA.CommonFAFinanceNurseryDays) + 39(SAM.CommonFA.ChargeDetails)-->41(SAM.CommonFA.MetricCost) + 39(SAM.CommonFA.ChargeDetails)-->40(SAM.CommonFA.OPVisits) + 35(SAM.CommonFA.PopulationFME)-->39(SAM.CommonFA.ChargeDetails) + 36(SAM.CommonFA.PremetricCost)-->39(SAM.CommonFA.ChargeDetails) + `, + { look: 'handDrawn', handDrawnSeed: 0, fontFamily: 'courier' } + ); + }); + + it('FHD7: should render a flowchart full of icons', () => { + imgSnapshotTest( + ` + graph TD + 9e122290_1ec3_e711_8c5a_005056ad0002("fa:fa-creative-commons My System | Test Environment") + 82072290_1ec3_e711_8c5a_005056ad0002("fa:fa-cogs Shared Business Logic Server:Service 1") + db052290_1ec3_e711_8c5a_005056ad0002("fa:fa-cogs Shared Business Logic Server:Service 2") + 4e112290_1ec3_e711_8c5a_005056ad0002("fa:fa-cogs Shared Report Server:Service 1") + 30122290_1ec3_e711_8c5a_005056ad0002("fa:fa-cogs Shared Report Server:Service 2") + 5e112290_1ec3_e711_8c5a_005056ad0002("fa:fa-cogs Dedicated Test Business Logic Server:Service 1") + c1112290_1ec3_e711_8c5a_005056ad0002("fa:fa-cogs Dedicated Test Business Logic Server:Service 2") + b7042290_1ec3_e711_8c5a_005056ad0002("fa:fa-circle [DBServer\\SharedDbInstance].[SupportDb]") + 8f102290_1ec3_e711_8c5a_005056ad0002("fa:fa-circle [DBServer\\SharedDbInstance].[DevelopmentDb]") + 0e102290_1ec3_e711_8c5a_005056ad0002("fa:fa-circle [DBServer\\SharedDbInstance].[TestDb]") + 07132290_1ec3_e711_8c5a_005056ad0002("fa:fa-circle [DBServer\\SharedDbInstance].[SharedReportingDb]") + c7072290_1ec3_e711_8c5a_005056ad0002("fa:fa-server Shared Business Logic Server") + ca122290_1ec3_e711_8c5a_005056ad0002("fa:fa-server Shared Report Server") + 68102290_1ec3_e711_8c5a_005056ad0002("fa:fa-server Dedicated Test Business Logic Server") + f4112290_1ec3_e711_8c5a_005056ad0002("fa:fa-database [DBServer\\SharedDbInstance]") + d6072290_1ec3_e711_8c5a_005056ad0002("fa:fa-server DBServer") + 71082290_1ec3_e711_8c5a_005056ad0002("fa:fa-cogs DBServer\\:MSSQLSERVER") + c0102290_1ec3_e711_8c5a_005056ad0002("fa:fa-cogs DBServer\\:SQLAgent") + 9a072290_1ec3_e711_8c5a_005056ad0002("fa:fa-cogs DBServer\\:SQLBrowser") + 1d0a2290_1ec3_e711_8c5a_005056ad0002("fa:fa-server VmHost1") + 200a2290_1ec3_e711_8c5a_005056ad0002("fa:fa-server VmHost2") + 1c0a2290_1ec3_e711_8c5a_005056ad0002("fa:fa-server VmHost3") + 9e122290_1ec3_e711_8c5a_005056ad0002-->82072290_1ec3_e711_8c5a_005056ad0002 + 9e122290_1ec3_e711_8c5a_005056ad0002-->db052290_1ec3_e711_8c5a_005056ad0002 + 9e122290_1ec3_e711_8c5a_005056ad0002-->4e112290_1ec3_e711_8c5a_005056ad0002 + 9e122290_1ec3_e711_8c5a_005056ad0002-->30122290_1ec3_e711_8c5a_005056ad0002 + 9e122290_1ec3_e711_8c5a_005056ad0002-->5e112290_1ec3_e711_8c5a_005056ad0002 + 9e122290_1ec3_e711_8c5a_005056ad0002-->c1112290_1ec3_e711_8c5a_005056ad0002 + 82072290_1ec3_e711_8c5a_005056ad0002-->b7042290_1ec3_e711_8c5a_005056ad0002 + 82072290_1ec3_e711_8c5a_005056ad0002-->8f102290_1ec3_e711_8c5a_005056ad0002 + 82072290_1ec3_e711_8c5a_005056ad0002-->0e102290_1ec3_e711_8c5a_005056ad0002 + 82072290_1ec3_e711_8c5a_005056ad0002-->c7072290_1ec3_e711_8c5a_005056ad0002 + db052290_1ec3_e711_8c5a_005056ad0002-->c7072290_1ec3_e711_8c5a_005056ad0002 + db052290_1ec3_e711_8c5a_005056ad0002-->82072290_1ec3_e711_8c5a_005056ad0002 + 4e112290_1ec3_e711_8c5a_005056ad0002-->b7042290_1ec3_e711_8c5a_005056ad0002 + 4e112290_1ec3_e711_8c5a_005056ad0002-->8f102290_1ec3_e711_8c5a_005056ad0002 + 4e112290_1ec3_e711_8c5a_005056ad0002-->0e102290_1ec3_e711_8c5a_005056ad0002 + 4e112290_1ec3_e711_8c5a_005056ad0002-->07132290_1ec3_e711_8c5a_005056ad0002 + 4e112290_1ec3_e711_8c5a_005056ad0002-->ca122290_1ec3_e711_8c5a_005056ad0002 + 30122290_1ec3_e711_8c5a_005056ad0002-->ca122290_1ec3_e711_8c5a_005056ad0002 + 30122290_1ec3_e711_8c5a_005056ad0002-->4e112290_1ec3_e711_8c5a_005056ad0002 + 5e112290_1ec3_e711_8c5a_005056ad0002-->8f102290_1ec3_e711_8c5a_005056ad0002 + 5e112290_1ec3_e711_8c5a_005056ad0002-->68102290_1ec3_e711_8c5a_005056ad0002 + c1112290_1ec3_e711_8c5a_005056ad0002-->68102290_1ec3_e711_8c5a_005056ad0002 + c1112290_1ec3_e711_8c5a_005056ad0002-->5e112290_1ec3_e711_8c5a_005056ad0002 + b7042290_1ec3_e711_8c5a_005056ad0002-->f4112290_1ec3_e711_8c5a_005056ad0002 + 8f102290_1ec3_e711_8c5a_005056ad0002-->f4112290_1ec3_e711_8c5a_005056ad0002 + 0e102290_1ec3_e711_8c5a_005056ad0002-->f4112290_1ec3_e711_8c5a_005056ad0002 + 07132290_1ec3_e711_8c5a_005056ad0002-->f4112290_1ec3_e711_8c5a_005056ad0002 + c7072290_1ec3_e711_8c5a_005056ad0002-->1d0a2290_1ec3_e711_8c5a_005056ad0002 + ca122290_1ec3_e711_8c5a_005056ad0002-->200a2290_1ec3_e711_8c5a_005056ad0002 + 68102290_1ec3_e711_8c5a_005056ad0002-->1c0a2290_1ec3_e711_8c5a_005056ad0002 + f4112290_1ec3_e711_8c5a_005056ad0002-->d6072290_1ec3_e711_8c5a_005056ad0002 + f4112290_1ec3_e711_8c5a_005056ad0002-->71082290_1ec3_e711_8c5a_005056ad0002 + f4112290_1ec3_e711_8c5a_005056ad0002-->c0102290_1ec3_e711_8c5a_005056ad0002 + f4112290_1ec3_e711_8c5a_005056ad0002-->9a072290_1ec3_e711_8c5a_005056ad0002 + d6072290_1ec3_e711_8c5a_005056ad0002-->1c0a2290_1ec3_e711_8c5a_005056ad0002 + 71082290_1ec3_e711_8c5a_005056ad0002-->d6072290_1ec3_e711_8c5a_005056ad0002 + c0102290_1ec3_e711_8c5a_005056ad0002-->d6072290_1ec3_e711_8c5a_005056ad0002 + c0102290_1ec3_e711_8c5a_005056ad0002-->71082290_1ec3_e711_8c5a_005056ad0002 + 9a072290_1ec3_e711_8c5a_005056ad0002-->d6072290_1ec3_e711_8c5a_005056ad0002 + 9a072290_1ec3_e711_8c5a_005056ad0002-->71082290_1ec3_e711_8c5a_005056ad0002 + `, + { look: 'handDrawn', handDrawnSeed: 0, fontFamily: 'courier' } + ); + }); + + it('FHD8: should render labels with numbers at the start', () => { + imgSnapshotTest( + ` + graph TB;subgraph "number as labels";1;end; + `, + { look: 'handDrawn', handDrawnSeed: 0, fontFamily: 'courier' } + ); + }); + + it('FHD9: should render subgraphs', () => { + imgSnapshotTest( + ` + graph TB + subgraph One + a1-->a2 + end + `, + { look: 'handDrawn', handDrawnSeed: 0, fontFamily: 'courier' } + ); + }); + + it('FHD10: should render subgraphs with a title starting with a digit', () => { + imgSnapshotTest( + ` + graph TB + subgraph 2Two + a1-->a2 + end + `, + { look: 'handDrawn', handDrawnSeed: 0, fontFamily: 'courier' } + ); + }); + + it('FHD11: should render styled subgraphs', () => { + imgSnapshotTest( + ` + graph TB + A + B + subgraph foo[Foo SubGraph] + C + D + end + subgraph bar[Bar SubGraph] + E + F + end + G + + A-->B + B-->C + C-->D + B-->D + D-->E + E-->A + E-->F + F-->D + F-->G + B-->G + G-->D + + style foo fill:#F99,stroke-width:2px,stroke:#F0F,color:darkred + style bar fill:#999,stroke-width:10px,stroke:#0F0,color:blue + `, + { look: 'handDrawn', handDrawnSeed: 0, fontFamily: 'courier' } + ); + }); + + it('FHD12: should render a flowchart with long names and class definitions', () => { + imgSnapshotTest( + `graph LR + sid-B3655226-6C29-4D00-B685-3D5C734DC7E1[" + + 提交申请 + 熊大 + "]; + class sid-B3655226-6C29-4D00-B685-3D5C734DC7E1 node-executed; + sid-4DA958A0-26D9-4D47-93A7-70F39FD7D51A[" + 负责人审批 + 强子 + "]; + class sid-4DA958A0-26D9-4D47-93A7-70F39FD7D51A node-executed; + sid-E27C0367-E6D6-497F-9736-3CDC21FDE221[" + DBA审批 + 强子 + "]; + class sid-E27C0367-E6D6-497F-9736-3CDC21FDE221 node-executed; + sid-BED98281-9585-4D1B-934E-BD1AC6AC0EFD[" + SA审批 + 阿美 + "]; + class sid-BED98281-9585-4D1B-934E-BD1AC6AC0EFD node-executed; + sid-7CE72B24-E0C1-46D3-8132-8BA66BE05AA7[" + 主管审批 + 光头强 + "]; + class sid-7CE72B24-E0C1-46D3-8132-8BA66BE05AA7 node-executed; + sid-A1B3CD96-7697-4D7C-BEAA-73D187B1BE89[" + DBA确认 + 强子 + "]; + class sid-A1B3CD96-7697-4D7C-BEAA-73D187B1BE89 node-executed; + sid-3E35A7FF-A2F4-4E07-9247-DBF884C81937[" + SA确认 + 阿美 + "]; + class sid-3E35A7FF-A2F4-4E07-9247-DBF884C81937 node-executed; + sid-4FC27B48-A6F9-460A-A675-021F5854FE22[" + 结束 + "]; + class sid-4FC27B48-A6F9-460A-A675-021F5854FE22 node-executed; + sid-19DD9E9F-98C1-44EE-B604-842AFEE76F1E[" + SA执行1 + 强子 + "]; + class sid-19DD9E9F-98C1-44EE-B604-842AFEE76F1E node-executed; + sid-6C2120F3-D940-4958-A067-0903DCE879C4[" + SA执行2 + 强子 + "]; + class sid-6C2120F3-D940-4958-A067-0903DCE879C4 node-executed; + sid-9180E2A0-5C4B-435F-B42F-0D152470A338[" + DBA执行1 + 强子 + "]; + class sid-9180E2A0-5C4B-435F-B42F-0D152470A338 node-executed; + sid-03A2C3AC-5337-48A5-B154-BB3FD0EC8DAD[" + DBA执行3 + 强子 + "]; + class sid-03A2C3AC-5337-48A5-B154-BB3FD0EC8DAD node-executed; + sid-D5E1F2F4-306C-47A2-BF74-F66E3D769756[" + DBA执行2 + 强子 + "]; + class sid-D5E1F2F4-306C-47A2-BF74-F66E3D769756 node-executed; + sid-8C3F2F1D-F014-4F99-B966-095DC1A2BD93[" + DBA执行4 + 强子 + "]; + class sid-8C3F2F1D-F014-4F99-B966-095DC1A2BD93 node-executed; + sid-1897B30A-9C5C-4D5B-B80B-76A038785070[" + 负责人确认 + 梁静茹 + "]; + class sid-1897B30A-9C5C-4D5B-B80B-76A038785070 node-executed; + sid-B3655226-6C29-4D00-B685-3D5C734DC7E1-->sid-7CE72B24-E0C1-46D3-8132-8BA66BE05AA7; + sid-4DA958A0-26D9-4D47-93A7-70F39FD7D51A-->sid-1897B30A-9C5C-4D5B-B80B-76A038785070; + sid-E27C0367-E6D6-497F-9736-3CDC21FDE221-->sid-A1B3CD96-7697-4D7C-BEAA-73D187B1BE89; + sid-BED98281-9585-4D1B-934E-BD1AC6AC0EFD-->sid-3E35A7FF-A2F4-4E07-9247-DBF884C81937; + sid-19DD9E9F-98C1-44EE-B604-842AFEE76F1E-->sid-6C2120F3-D940-4958-A067-0903DCE879C4; + sid-9180E2A0-5C4B-435F-B42F-0D152470A338-->sid-D5E1F2F4-306C-47A2-BF74-F66E3D769756; + sid-03A2C3AC-5337-48A5-B154-BB3FD0EC8DAD-->sid-8C3F2F1D-F014-4F99-B966-095DC1A2BD93; + sid-6C2120F3-D940-4958-A067-0903DCE879C4-->sid-4DA958A0-26D9-4D47-93A7-70F39FD7D51A; + sid-1897B30A-9C5C-4D5B-B80B-76A038785070-->sid-4FC27B48-A6F9-460A-A675-021F5854FE22; + sid-3E35A7FF-A2F4-4E07-9247-DBF884C81937-->sid-19DD9E9F-98C1-44EE-B604-842AFEE76F1E; + sid-A1B3CD96-7697-4D7C-BEAA-73D187B1BE89-->sid-9180E2A0-5C4B-435F-B42F-0D152470A338; + sid-A1B3CD96-7697-4D7C-BEAA-73D187B1BE89-->sid-03A2C3AC-5337-48A5-B154-BB3FD0EC8DAD; + sid-D5E1F2F4-306C-47A2-BF74-F66E3D769756-->sid-4DA958A0-26D9-4D47-93A7-70F39FD7D51A; + sid-8C3F2F1D-F014-4F99-B966-095DC1A2BD93-->sid-4DA958A0-26D9-4D47-93A7-70F39FD7D51A; + sid-7CE72B24-E0C1-46D3-8132-8BA66BE05AA7-->sid-BED98281-9585-4D1B-934E-BD1AC6AC0EFD; + sid-7CE72B24-E0C1-46D3-8132-8BA66BE05AA7-->sid-E27C0367-E6D6-497F-9736-3CDC21FDE221; + sid-3E35A7FF-A2F4-4E07-9247-DBF884C81937-->sid-6C2120F3-D940-4958-A067-0903DCE879C4; + sid-7CE72B24-E0C1-46D3-8132-8BA66BE05AA7-->sid-4DA958A0-26D9-4D47-93A7-70F39FD7D51A; + sid-7CE72B24-E0C1-46D3-8132-8BA66BE05AA7-->sid-4FC27B48-A6F9-460A-A675-021F5854FE22; + `, + { look: 'handDrawn', handDrawnSeed: 0, fontFamily: 'courier' } + ); + }); + + it('FHD13: should render color of styled nodes', () => { + imgSnapshotTest( + ` + graph LR + foo-->bar + + classDef foo fill:lightblue,color:green,stroke:#FF9E2C,font-weight:bold + style foo fill:#F99,stroke-width:2px,stroke:#F0F + style bar fill:#999,color: #00ff00, stroke-width:10px,stroke:#0F0 + `, + { + look: 'handDrawn', + handDrawnSeed: 0, + listUrl: false, + listId: 'color styling', + fontFamily: 'courier', + logLevel: 0, + } + ); + }); + + it('FHD14: should render hexagons', () => { + imgSnapshotTest( + ` + graph TD + A[Christmas] -->|Get money| B(Go shopping) + B --> C{{Let me think...
Do I want something for work,
something to spend every free second with,
or something to get around?}} + C -->|One| D[Laptop] + C -->|Two| E[iPhone] + C -->|Three| F[Car] + click A "index.html#link-clicked" "link test" + click B testClick "click test" + classDef someclass fill:#f96; + class A someclass; + class C someclass; + `, + { + look: 'handDrawn', + handDrawnSeed: 0, + listUrl: false, + listId: 'color styling', + fontFamily: 'courier', + logLevel: 0, + } + ); + }); + + it('FHD15: should render a simple flowchart with comments', () => { + imgSnapshotTest( + `graph TD + A[Christmas] -->|Get money| B(Go shopping) + B --> C{Let me think} + %% this is a comment + C -->|One| D[Laptop] + C -->|Two| E[iPhone] + C -->|Three| F[fa:fa-car Car] + `, + { + look: 'handDrawn', + handDrawnSeed: 0, + flowchart: { htmlLabels: false }, + fontFamily: 'courier', + } + ); + }); + + it('FHD16: Render Stadium shape', () => { + imgSnapshotTest( + ` graph TD + A([stadium shape test]) + A -->|Get money| B([Go shopping]) + B --> C([Let me think...
Do I want something for work,
something to spend every free second with,
or something to get around?]) + C -->|One| D([Laptop]) + C -->|Two| E([iPhone]) + C -->|Three| F([Car
wroom wroom]) + click A "index.html#link-clicked" "link test" + click B testClick "click test" + classDef someclass fill:#f96; + class A someclass; + class C someclass; + `, + { + look: 'handDrawn', + handDrawnSeed: 0, + flowchart: { htmlLabels: false }, + fontFamily: 'courier', + } + ); + }); + + it('FHD17: Render multiline texts', () => { + imgSnapshotTest( + `graph LR + A1[Multi
Line] -->|Multi
Line| B1(Multi
Line) + C1[Multi
Line] -->|Multi
Line| D1(Multi
Line) + E1[Multi
Line] -->|Multi
Line| F1(Multi
Line) + A2[Multi
Line] -->|Multi
Line| B2(Multi
Line) + C2[Multi
Line] -->|Multi
Line| D2(Multi
Line) + E2[Multi
Line] -->|Multi
Line| F2(Multi
Line) + linkStyle 0 stroke:DarkGray,stroke-width:2px + linkStyle 1 stroke:DarkGray,stroke-width:2px + linkStyle 2 stroke:DarkGray,stroke-width:2px + `, + { + look: 'handDrawn', + handDrawnSeed: 0, + flowchart: { htmlLabels: false }, + fontFamily: 'courier', + } + ); + }); + + it('FHD18: Chaining of nodes', () => { + imgSnapshotTest( + `graph LR + a --> b --> c + `, + { + look: 'handDrawn', + handDrawnSeed: 0, + flowchart: { htmlLabels: false }, + fontFamily: 'courier', + } + ); + }); + + it('FHD19: Multiple nodes and chaining in one statement', () => { + imgSnapshotTest( + `graph LR + a --> b & c--> d + `, + { + look: 'handDrawn', + handDrawnSeed: 0, + flowchart: { htmlLabels: false }, + fontFamily: 'courier', + } + ); + }); + + it('FHD20: Multiple nodes and chaining in one statement', () => { + imgSnapshotTest( + `graph TD + A[ h ] -- hello --> B[" test "]:::exClass & C --> D; + classDef exClass background:#bbb,border:1px solid red; + `, + { + look: 'handDrawn', + handDrawnSeed: 0, + flowchart: { htmlLabels: false }, + fontFamily: 'courier', + } + ); + }); + + it('FDH21: Render cylindrical shape', () => { + imgSnapshotTest( + `graph LR + A[(cylindrical
shape
test)] + A -->|Get money| B1[(Go shopping 1)] + A -->|Get money| B2[(Go shopping 2)] + A -->|Get money| B3[(Go shopping 3)] + C[(Let me think...
Do I want something for work,
something to spend every free second with,
or something to get around?)] + B1 --> C + B2 --> C + B3 --> C + C -->|One| D[(Laptop)] + C -->|Two| E[(iPhone)] + C -->|Three| F[(Car)] + click A "index.html#link-clicked" "link test" + click B testClick "click test" + classDef someclass fill:#f96; + class A someclass;`, + { + look: 'handDrawn', + handDrawnSeed: 0, + flowchart: { htmlLabels: false }, + fontFamily: 'courier', + } + ); + }); + + it('FDH22: Render a simple flowchart with nodeSpacing set to 100', () => { + imgSnapshotTest( + `graph TD + A[Christmas] -->|Get money| B(Go shopping) + B --> C{Let me think} + %% this is a comment + C -->|One| D[Laptop] + C -->|Two| E[iPhone] + C -->|Three| F[fa:fa-car Car] + `, + { look: 'handDrawn', handDrawnSeed: 0, flowchart: { nodeSpacing: 50 }, fontFamily: 'courier' } + ); + }); + + it('FDH23: Render a simple flowchart with rankSpacing set to 100', () => { + imgSnapshotTest( + `graph TD + A[Christmas] -->|Get money| B(Go shopping) + B --> C{Let me think} + %% this is a comment + C -->|One| D[Laptop] + C -->|Two| E[iPhone] + C -->|Three| F[fa:fa-car Car] + `, + { + look: 'handDrawn', + handDrawnSeed: 0, + flowchart: { rankSpacing: '100' }, + fontFamily: 'courier', + } + ); + }); + + it('FDH24: Keep node label text (if already defined) when a style is applied', () => { + imgSnapshotTest( + `graph LR + A(( )) -->|step 1| B(( )) + B(( )) -->|step 2| C(( )) + C(( )) -->|step 3| D(( )) + linkStyle 1 stroke:greenyellow,stroke-width:2px + style C fill:greenyellow,stroke:green,stroke-width:4px + `, + { + look: 'handDrawn', + handDrawnSeed: 0, + flowchart: { htmlLabels: false }, + fontFamily: 'courier', + } + ); + }); + + it('FDH25: Handle link click events (link, anchor, mailto, other protocol, script)', () => { + imgSnapshotTest( + `graph TB + TITLE["Link Click Events
(click the nodes below)"] + A["link test (open in same tab)"] + B["link test (open in new tab)"] + C[anchor test] + D[mailto test] + E[other protocol test] + F[script test] + TITLE --> A & B & C & D & E & F + click A "https://mermaid-js.github.io/mermaid/#/" "link test (open in same tab)" + click B "https://mermaid-js.github.io/mermaid/#/" "link test (open in new tab)" _blank + click C "#link-clicked" + click D "mailto:user@user.user" "mailto test" + click E "notes://do-your-thing/id" "other protocol test" + click F "javascript:alert('test')" "script test" + `, + { look: 'handDrawn', handDrawnSeed: 0, securityLevel: 'loose', fontFamily: 'courier' } + ); + }); + + it('FDH26: Set text color of nodes and links according to styles when html labels are enabled', () => { + imgSnapshotTest( + `graph LR + A[red
text] -->|red
text| B(blue
text) + C[/red
text/] -->|blue
text| D{blue
text} + E{{default
style}} -->|default
style| F([default
style]) + linkStyle default color:Sienna; + linkStyle 0 color:red; + linkStyle 1 stroke:DarkGray,stroke-width:2px,color:#0000ff + style A color:red; + style B color:blue; + style C stroke:#ff0000,fill:#ffcccc,color:#ff0000 + style D stroke:#0000ff,fill:#ccccff,color:#0000ff + click B "index.html#link-clicked" "link test" + click D testClick "click test" + `, + { look: 'handDrawn', handDrawnSeed: 0, flowchart: { htmlLabels: true } } + ); + }); + + it('FDH27: Set text color of nodes and links according to styles when html labels are disabled', () => { + imgSnapshotTest( + `graph LR + A[red
text] -->|red
text| B(blue
text) + C[/red
text/] -->|blue
text| D{blue
text} + E{{default
style}} -->|default
style| F([default
style]) + linkStyle default color:Sienna; + linkStyle 0 color:red; + linkStyle 1 stroke:DarkGray,stroke-width:2px,color:#0000ff + style A color:red; + style B color:blue; + style C stroke:#ff0000,fill:#ffcccc,color:#ff0000 + style D stroke:#0000ff,fill:#ccccff,color:#0000ff + click B "index.html#link-clicked" "link test" + click D testClick "click test" + `, + { + look: 'handDrawn', + handDrawnSeed: 0, + flowchart: { htmlLabels: false }, + fontFamily: 'courier', + } + ); + }); + + it('FDH28: Apply default class to all nodes which do not have another class assigned (htmlLabels enabled)', () => { + imgSnapshotTest( + `graph TD + A[myClass1] --> B[default] & C[default] + B[default] & C[default] --> D[myClass2] + classDef default stroke-width:2px,fill:none,stroke:silver + classDef node color:red + classDef myClass1 color:#0000ff + classDef myClass2 stroke:#0000ff,fill:#ccccff + class A myClass1 + class D myClass2 + `, + { look: 'handDrawn', handDrawnSeed: 0, flowchart: { htmlLabels: true } } + ); + }); + + it('FDH29: Apply default class to all nodes which do not have another class assigned (htmlLabels disabled)', () => { + imgSnapshotTest( + `graph TD + A[myClass1] --> B[default] & C[default] + B[default] & C[default] --> D[myClass2] + classDef default stroke-width:2px,fill:none,stroke:silver + classDef node color:red + classDef myClass1 color:#0000ff + classDef myClass2 stroke:#0000ff,fill:#ccccff + class A myClass1 + class D myClass2 + `, + { + look: 'handDrawn', + handDrawnSeed: 0, + flowchart: { htmlLabels: false }, + fontFamily: 'courier', + } + ); + }); + + it('FDH30: Possibility to style text color of nodes and subgraphs as well as apply classes to subgraphs', () => { + imgSnapshotTest( + `graph LR + subgraph id1 [title is set] + A-->B + end + subgraph id2 [title] + E + end + + B-->C + + subgraph id3 + C-->D + end + class id3,id2,A redBg; + class id3,A whiteTxt; + classDef redBg fill:#622; + classDef whiteTxt color: white; + `, + { + look: 'handDrawn', + handDrawnSeed: 0, + flowchart: { htmlLabels: false }, + fontFamily: 'courier', + } + ); + }); + + it('FDH31: should not slice off edges that are to the left of the left-most vertex', () => { + imgSnapshotTest( + `graph TD + work --> sleep + sleep --> work + eat --> sleep + work --> eat + `, + { + look: 'handDrawn', + handDrawnSeed: 0, + flowchart: { htmlLabels: false }, + fontFamily: 'courier', + } + ); + }); + + it('FDH32: Render Subroutine shape', () => { + imgSnapshotTest( + `graph LR + A[[subroutine shape test]] + A -->|Get money| B[[Go shopping]] + B --> C[[Let me think...
Do I want something for work,
something to spend every free second with,
or something to get around?]] + C -->|One| D[[Laptop]] + C -->|Two| E[[iPhone]] + C -->|Three| F[[Car
wroom wroom]] + click A "index.html#link-clicked" "link test" + click B testClick "click test" + classDef someclass fill:#f96; + class A someclass; + class C someclass; + `, + { + look: 'handDrawn', + handDrawnSeed: 0, + flowchart: { htmlLabels: false }, + fontFamily: 'courier', + } + ); + }); + + it('FDH33: should render a simple flowchart with diagramPadding set to 0', () => { + imgSnapshotTest( + `graph TD + A[Christmas] -->|Get money| B(Go shopping) + B --> C{Let me think} + %% this is a comment + C -->|One| D[Laptop] + C -->|Two| E[iPhone] + C -->|Three| F[fa:fa-car Car] + `, + { look: 'handDrawn', handDrawnSeed: 0, flowchart: { diagramPadding: 0 } } + ); + }); + + it('FDH34: testing the label width in percy', () => { + imgSnapshotTest( + `graph TD + A[Christmas] + `, + { look: 'handDrawn', handDrawnSeed: 0 } + ); + }); + + it('FDH35: should honor minimum edge length as specified by the user', () => { + imgSnapshotTest( + `graph TD + L1 --- L2 + L2 --- C + M1 ---> C + R1 .-> R2 + R2 <.-> C + C -->|Label 1| E1 + C -- Label 2 ---> E2 + C ----> E3 + C -----> E4 + C ======> E5 + `, + { look: 'handDrawn', handDrawnSeed: 0 } + ); + }); + it('FDH36: should render escaped without html labels', () => { + imgSnapshotTest( + `graph TD + a["Haiya"]-->b + `, + { look: 'handDrawn', handDrawnSeed: 0, htmlLabels: false, flowchart: { htmlLabels: false } } + ); + }); + it('FDH37: should render non-escaped with html labels', () => { + imgSnapshotTest( + `graph TD + a["Haiya"]-->b + `, + { + look: 'handDrawn', + handDrawnSeed: 0, + htmlLabels: true, + flowchart: { htmlLabels: true }, + securityLevel: 'loose', + } + ); + }); + it('FDH38: should render a flowchart when useMaxWidth is true (default)', () => { + renderGraph( + `flowchart TD + A[Christmas] -->|Get money| B(Go shopping) + B --> C{Let me think} + C -->|One| D[Laptop] + C -->|Two| E[iPhone] + C -->|Three| F[fa:fa-car Car] + `, + { look: 'handDrawn', handDrawnSeed: 0, flowchart: { useMaxWidth: true } } + ); + cy.get('svg').should((svg) => { + expect(svg).to.have.attr('width', '100%'); + // expect(svg).to.have.attr('height'); + // use within because the absolute value can be slightly different depending on the environment ±10% + // const height = parseFloat(svg.attr('height')); + // expect(height).to.be.within(446 * 0.95, 446 * 1.05); + const style = svg.attr('style'); + expect(style).to.match(/^max-width: [\d.]+px;$/); + const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join('')); + expect(maxWidthValue).to.be.within(446 * 0.9, 446 * 1.1); + }); + }); + it('FDH39: should render a flowchart when useMaxWidth is false', () => { + renderGraph( + `graph TD + A[Christmas] -->|Get money| B(Go shopping) + B --> C{Let me think} + C -->|One| D[Laptop] + C -->|Two| E[iPhone] + C -->|Three| F[fa:fa-car Car] + `, + { look: 'handDrawn', handDrawnSeed: 0, flowchart: { useMaxWidth: false } } + ); + cy.get('svg').should((svg) => { + // const height = parseFloat(svg.attr('height')); + const width = parseFloat(svg.attr('width')); + // use within because the absolute value can be slightly different depending on the environment ±10% + // expect(height).to.be.within(446 * 0.95, 446 * 1.05); + expect(width).to.be.within(446 * 0.9, 446 * 1.1); + expect(svg).to.not.have.attr('style'); + }); + }); + it('FDH40: handle styling with style expressions', () => { + imgSnapshotTest( + ` + graph LR + id1(Start)-->id2(Stop) + style id1 fill:#f9f,stroke:#333,stroke-width:4px + style id2 fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5 + `, + { + look: 'handDrawn', + handDrawnSeed: 0, + htmlLabels: true, + flowchart: { htmlLabels: true }, + securityLevel: 'loose', + } + ); + }); + it('FDH41: handle styling for all node shapes', () => { + imgSnapshotTest( + ` + graph LR + A[red text] -->|default style| B(blue text) + C([red text]) -->|default style| D[[blue text]] + E[(red text)] -->|default style| F((blue text)) + G>red text] -->|default style| H{blue text} + I{{red text}} -->|default style| J[/blue text/] + linkStyle default color:Sienna; + style A stroke:#ff0000,fill:#ffcccc,color:#ff0000 + style B stroke:#0000ff,fill:#ccccff,color:#0000ff + style C stroke:#ff0000,fill:#ffcccc,color:#ff0000 + style D stroke:#0000ff,fill:#ccccff,color:#0000ff + style E stroke:#ff0000,fill:#ffcccc,color:#ff0000 + style F stroke:#0000ff,fill:#ccccff,color:#0000ff + style G stroke:#ff0000,fill:#ffcccc,color:#ff0000 + style H stroke:#0000ff,fill:#ccccff,color:#0000ff + style I stroke:#ff0000,fill:#ffcccc,color:#ff0000 + style J stroke:#0000ff,fill:#ccccff,color:#0000ff + `, + { + look: 'handDrawn', + handDrawnSeed: 0, + htmlLabels: true, + flowchart: { htmlLabels: true }, + securityLevel: 'loose', + } + ); + }); + it('FDH42: fontawesome icons in edge labels', () => { + imgSnapshotTest( + ` +graph TD + C -->|fa:fa-car Car| F[fa:fa-car Car] + `, + { + look: 'handDrawn', + handDrawnSeed: 0, + htmlLabels: true, + flowchart: { htmlLabels: true }, + securityLevel: 'loose', + } + ); + }); + it('FDH43: fontawesome icons in edge labels', () => { + imgSnapshotTest( + ` + graph TB + subgraph bar[Bar] + F + end + style bar fill:#999,stroke-width:10px,stroke:#0F0,color:blue + `, + { + look: 'handDrawn', + handDrawnSeed: 0, + htmlLabels: true, + flowchart: { htmlLabels: true }, + securityLevel: 'loose', + } + ); + }); + it('FDH44: fontawesome icons in edge labels', () => { + imgSnapshotTest( + ` + graph TB + A + B + subgraph foo[Foo SubGraph] + C + D + end + subgraph bar[Bar SubGraph] + E + F + end + G + + A-->B + B-->C + C-->D + B-->D + D-->E + E-->A + E-->F + F-->D + F-->G + B-->G + G-->D + + style foo fill:#F99,stroke-width:2px,stroke:#F0F,color:darkred + style bar fill:#999,stroke-width:10px,stroke:#0F0,color:blue + `, + { + look: 'handDrawn', + handDrawnSeed: 0, + htmlLabels: true, + flowchart: { htmlLabels: true }, + securityLevel: 'loose', + } + ); + }); + it('FDH45: fontawesome icons in edge labels', () => { + imgSnapshotTest( + ` + %%{init:{"theme":"base", "themeVariables": {"primaryColor":"#411d4e", "titleColor":"white", "darkMode":true}}}%% + flowchart LR + subgraph A + a --> b + end + subgraph B + i -->f + end + A --> B + `, + { + look: 'handDrawn', + handDrawnSeed: 0, + htmlLabels: true, + flowchart: { htmlLabels: true }, + securityLevel: 'loose', + } + ); + }); + it('FDH46: text-color from classes', () => { + imgSnapshotTest( + ` + flowchart LR + classDef dark fill:#000,stroke:#000,stroke-width:4px,color:#fff + Lorem --> Ipsum --> Dolor + class Lorem,Dolor dark + `, + { + look: 'handDrawn', + handDrawnSeed: 0, + htmlLabels: true, + flowchart: { htmlLabels: true }, + securityLevel: 'loose', + } + ); + }); + it('FDH47: apply class called default on node called default', () => { + imgSnapshotTest( + ` + graph TD + classDef default fill:#a34,stroke:#000,stroke-width:4px,color:#fff + hello --> default + `, + { + look: 'handDrawn', + handDrawnSeed: 0, + htmlLabels: true, + flowchart: { htmlLabels: true }, + securityLevel: 'loose', + } + ); + }); + + it('FDH48: should be able to style default node independently', () => { + imgSnapshotTest( + ` + flowchart TD + classDef default fill:#a34 + hello --> default + + style default stroke:#000,stroke-width:4px + `, + { + look: 'handDrawn', + handDrawnSeed: 0, + flowchart: { htmlLabels: true }, + securityLevel: 'loose', + } + ); + }); +}); diff --git a/cypress/integration/rendering/flowchart-v2.spec.js b/cypress/integration/rendering/flowchart-v2.spec.js index 3eb2a0432a..c2fd0b0119 100644 --- a/cypress/integration/rendering/flowchart-v2.spec.js +++ b/cypress/integration/rendering/flowchart-v2.spec.js @@ -99,7 +99,7 @@ describe('Flowchart v2', () => { const style = svg.attr('style'); expect(style).to.match(/^max-width: [\d.]+px;$/); const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join('')); - expect(maxWidthValue).to.be.within(290 * 0.95 - 1, 290 * 1.05); + expect(maxWidthValue).to.be.within(446 * 0.95 - 1, 446 * 1.05); }); }); it('8: should render a flowchart when useMaxWidth is false', () => { @@ -118,7 +118,7 @@ describe('Flowchart v2', () => { const width = parseFloat(svg.attr('width')); // use within because the absolute value can be slightly different depending on the environment ±5% // expect(height).to.be.within(446 * 0.95, 446 * 1.05); - expect(width).to.be.within(290 * 0.95 - 1, 290 * 1.05); + expect(width).to.be.within(446 * 0.95 - 1, 446 * 1.05); expect(svg).to.not.have.attr('style'); }); }); @@ -1047,7 +1047,9 @@ end A --lb3--> TOP --lb4--> B B1 --lb5--> B2 `, - { flowchart: { subGraphTitleMargin: { top: 10, bottom: 5 } } } + { + flowchart: { subGraphTitleMargin: { top: 10, bottom: 5 } }, + } ); }); }); diff --git a/cypress/integration/rendering/flowchart.spec.js b/cypress/integration/rendering/flowchart.spec.js index e4766e7923..d3a83ae5f2 100644 --- a/cypress/integration/rendering/flowchart.spec.js +++ b/cypress/integration/rendering/flowchart.spec.js @@ -733,7 +733,7 @@ describe('Graph', () => { }); it('38: should render a flowchart when useMaxWidth is true (default)', () => { renderGraph( - `graph TD + `flowchart TD A[Christmas] -->|Get money| B(Go shopping) B --> C{Let me think} C -->|One| D[Laptop] @@ -751,7 +751,7 @@ describe('Graph', () => { const style = svg.attr('style'); expect(style).to.match(/^max-width: [\d.]+px;$/); const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join('')); - expect(maxWidthValue).to.be.within(300 * 0.9, 300 * 1.1); + expect(maxWidthValue).to.be.within(446 * 0.9, 446 * 1.1); }); }); it('39: should render a flowchart when useMaxWidth is false', () => { @@ -770,7 +770,7 @@ describe('Graph', () => { const width = parseFloat(svg.attr('width')); // use within because the absolute value can be slightly different depending on the environment ±10% // expect(height).to.be.within(446 * 0.95, 446 * 1.05); - expect(width).to.be.within(300 * 0.9, 300 * 1.1); + expect(width).to.be.within(446 * 0.9, 446 * 1.1); expect(svg).to.not.have.attr('style'); }); }); @@ -905,13 +905,16 @@ graph TD it('67: should be able to style default node independently', () => { imgSnapshotTest( ` - flowchart TD + flowchart TD classDef default fill:#a34 hello --> default style default stroke:#000,stroke-width:4px `, - { htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' } + { + flowchart: { htmlLabels: true }, + securityLevel: 'loose', + } ); }); }); diff --git a/cypress/integration/rendering/gitGraph.spec.js b/cypress/integration/rendering/gitGraph.spec.js index 4e8f7fdcac..249febd08d 100644 --- a/cypress/integration/rendering/gitGraph.spec.js +++ b/cypress/integration/rendering/gitGraph.spec.js @@ -1458,5 +1458,115 @@ gitGraph TB: { gitGraph: { parallelCommits: true } } ); }); + it('73: should render a simple gitgraph with three branches and tagged merge commit using switch instead of checkout', () => { + imgSnapshotTest( + `gitGraph + commit id: "1" + commit id: "2" + branch nice_feature + switch nice_feature + commit id: "3" + switch main + commit id: "4" + switch nice_feature + branch very_nice_feature + switch very_nice_feature + commit id: "5" + switch main + commit id: "6" + switch nice_feature + commit id: "7" + switch main + merge nice_feature id: "12345" tag: "my merge commit" + switch very_nice_feature + commit id: "8" + switch main + commit id: "9" + `, + {} + ); + }); + it('74: should render commits for more than 8 branches using switch instead of checkout', () => { + imgSnapshotTest( + ` + gitGraph + switch main + %% Make sure to manually set the ID of all commits, for consistent visual tests + commit id: "1-abcdefg" + switch main + branch branch1 + commit id: "2-abcdefg" + switch main + merge branch1 + branch branch2 + commit id: "3-abcdefg" + switch main + merge branch2 + branch branch3 + commit id: "4-abcdefg" + switch main + merge branch3 + branch branch4 + commit id: "5-abcdefg" + switch main + merge branch4 + branch branch5 + commit id: "6-abcdefg" + switch main + merge branch5 + branch branch6 + commit id: "7-abcdefg" + switch main + merge branch6 + branch branch7 + commit id: "8-abcdefg" + switch main + merge branch7 + branch branch8 + commit id: "9-abcdefg" + switch main + merge branch8 + branch branch9 + commit id: "10-abcdefg" + `, + {} + ); + }); + it('75: should render a gitGraph with multiple tags on a merge commit on bottom-to-top orientation', () => { + imgSnapshotTest( + `gitGraph BT: + commit id: "ZERO" + branch develop + commit id:"A" + checkout main + commit id:"ONE" + checkout develop + commit id:"B" + checkout main + merge develop id:"Release 1.0" type:HIGHLIGHT tag: "SAML v2.0" tag: "OpenID v1.1" + commit id:"TWO" + checkout develop + commit id:"C"`, + {} + ); + }); + }); + it('76: should render a gitGraph with multiple tags on a merge commit on left-to-right orientation', () => { + imgSnapshotTest( + `gitGraph + commit id: "ZERO" + branch develop + commit id:"A" + checkout main + commit id:"ONE" + checkout develop + commit id:"B" + checkout main + merge develop id:"Release 1.0" type:HIGHLIGHT tag: "SAML v2.0" tag: "OpenID v1.1" + commit id:"TWO" + checkout develop + commit id:"C"`, + {} + ); }); }); diff --git a/cypress/integration/rendering/packet.spec.ts b/cypress/integration/rendering/packet.spec.ts index 61555ea530..c64538875d 100644 --- a/cypress/integration/rendering/packet.spec.ts +++ b/cypress/integration/rendering/packet.spec.ts @@ -10,6 +10,15 @@ describe('packet structure', () => { ); }); + it('should render a simple packet diagram without ranges', () => { + imgSnapshotTest( + `packet-beta + 0: "h" + 1: "i" +` + ); + }); + it('should render a complex packet diagram', () => { imgSnapshotTest( `packet-beta diff --git a/cypress/integration/rendering/quadrantChart.spec.js b/cypress/integration/rendering/quadrantChart.spec.js index 1be1f7deff..4830db6568 100644 --- a/cypress/integration/rendering/quadrantChart.spec.js +++ b/cypress/integration/rendering/quadrantChart.spec.js @@ -1,4 +1,4 @@ -import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts'; +import { imgSnapshotTest } from '../../helpers/util.ts'; describe('Quadrant Chart', () => { it('should render if only chart type is provided', () => { @@ -8,7 +8,6 @@ describe('Quadrant Chart', () => { `, {} ); - cy.get('svg'); }); it('should render a complete quadrant chart', () => { imgSnapshotTest( @@ -30,7 +29,6 @@ describe('Quadrant Chart', () => { `, {} ); - cy.get('svg'); }); it('should render without points', () => { imgSnapshotTest( @@ -46,7 +44,6 @@ describe('Quadrant Chart', () => { `, {} ); - cy.get('svg'); }); it('should able to render y-axix on right side', () => { imgSnapshotTest( @@ -63,7 +60,6 @@ describe('Quadrant Chart', () => { `, {} ); - cy.get('svg'); }); it('should able to render x-axix on bottom', () => { imgSnapshotTest( @@ -80,7 +76,6 @@ describe('Quadrant Chart', () => { `, {} ); - cy.get('svg'); }); it('should able to render x-axix on bottom and y-axis on right', () => { imgSnapshotTest( @@ -97,7 +92,6 @@ describe('Quadrant Chart', () => { `, {} ); - cy.get('svg'); }); it('should render without title', () => { imgSnapshotTest( @@ -112,7 +106,6 @@ describe('Quadrant Chart', () => { `, {} ); - cy.get('svg'); }); it('should use all the config', () => { imgSnapshotTest( @@ -135,7 +128,6 @@ describe('Quadrant Chart', () => { `, {} ); - cy.get('svg'); }); it('should use all the theme variable', () => { imgSnapshotTest( @@ -158,7 +150,6 @@ describe('Quadrant Chart', () => { `, {} ); - cy.get('svg'); }); it('should render x-axis labels in the center, if x-axis has two labels', () => { imgSnapshotTest( @@ -180,7 +171,6 @@ describe('Quadrant Chart', () => { `, {} ); - cy.get('svg'); }); it('should render y-axis labels in the center, if y-axis has two labels', () => { imgSnapshotTest( @@ -202,7 +192,6 @@ describe('Quadrant Chart', () => { `, {} ); - cy.get('svg'); }); it('should render both axes labels on the left and bottom, if both axes have only one label', () => { imgSnapshotTest( @@ -224,6 +213,52 @@ describe('Quadrant Chart', () => { `, {} ); - cy.get('svg'); + }); + + it('it should render data points with styles', () => { + imgSnapshotTest( + ` + quadrantChart + title Reach and engagement of campaigns + x-axis Reach --> + y-axis Engagement --> + quadrant-1 We should expand + quadrant-2 Need to promote + quadrant-3 Re-evaluate + quadrant-4 May be improved + Campaign A: [0.3, 0.6] radius: 20 + Campaign B: [0.45, 0.23] color: #ff0000 + Campaign C: [0.57, 0.69] stroke-color: #ff00ff + Campaign D: [0.78, 0.34] stroke-width: 3px + Campaign E: [0.40, 0.34] radius: 20, color: #ff0000 , stroke-color : #ff00ff, stroke-width : 3px + Campaign F: [0.35, 0.78] stroke-width: 3px , color: #ff0000, radius: 20, stroke-color: #ff00ff + Campaign G: [0.22, 0.22] stroke-width: 3px , color: #309708 , radius : 20 , stroke-color: #5060ff + Campaign H: [0.22, 0.44] + `, + {} + ); + }); + + it('it should render data points with styles + classes', () => { + imgSnapshotTest( + ` + quadrantChart + title Reach and engagement of campaigns + x-axis Reach --> + y-axis Engagement --> + quadrant-1 We should expand + quadrant-2 Need to promote + quadrant-3 Re-evaluate + quadrant-4 May be improved + Campaign A:::class1: [0.3, 0.6] radius: 20 + Campaign B: [0.45, 0.23] color: #ff0000 + Campaign C: [0.57, 0.69] stroke-color: #ff00ff + Campaign D:::class2: [0.78, 0.34] stroke-width: 3px + Campaign E:::class2: [0.40, 0.34] radius: 20, color: #ff0000, stroke-color: #ff00ff, stroke-width: 3px + Campaign F:::class1: [0.35, 0.78] + classDef class1 color: #908342, radius : 10, stroke-color: #310085, stroke-width: 10px + classDef class2 color: #f00fff, radius : 10 + ` + ); }); }); diff --git a/cypress/integration/rendering/requirement.spec.js b/cypress/integration/rendering/requirement.spec.js index f33ae7a0cb..3434418483 100644 --- a/cypress/integration/rendering/requirement.spec.js +++ b/cypress/integration/rendering/requirement.spec.js @@ -44,6 +44,5 @@ describe('Requirement diagram', () => { `, {} ); - cy.get('svg'); }); }); diff --git a/cypress/integration/rendering/sequencediagram.spec.js b/cypress/integration/rendering/sequencediagram.spec.js index 1285a0832d..f18e99abf8 100644 --- a/cypress/integration/rendering/sequencediagram.spec.js +++ b/cypress/integration/rendering/sequencediagram.spec.js @@ -1,8 +1,6 @@ -/// - import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts'; -context('Sequence diagram', () => { +describe('Sequence diagram', () => { it('should render a sequence diagram with boxes', () => { renderGraph( ` @@ -68,6 +66,19 @@ context('Sequence diagram', () => { { sequence: { actorFontFamily: 'courier' } } ); }); + it('should render bidirectional arrows', () => { + imgSnapshotTest( + ` + sequenceDiagram + Alice<<->>John: Hello John, how are you? + Alice<<-->>John: Hi Alice, I can hear you! + John<<->>Alice: This also works the other way + John<<-->>Alice: Yes + Alice->John: Test + John->>Alice: Still works + ` + ); + }); it('should handle different line breaks', () => { imgSnapshotTest( ` @@ -231,7 +242,7 @@ context('Sequence diagram', () => { ` ); }); - context('font settings', () => { + describe('font settings', () => { it('should render different note fonts when configured', () => { imgSnapshotTest( ` @@ -328,7 +339,7 @@ context('Sequence diagram', () => { ); }); }); - context('auth width scaling', () => { + describe('auth width scaling', () => { it('should render long actor descriptions', () => { imgSnapshotTest( ` @@ -464,6 +475,18 @@ context('Sequence diagram', () => { {} ); }); + it('should render notes over actors and participant', () => { + imgSnapshotTest( + ` + sequenceDiagram + actor Alice + participant Charlie + note over Alice: some note + note over Charlie: other note + `, + {} + ); + }); it('should render long messages from an actor to the left to one to the right', () => { imgSnapshotTest( ` @@ -505,7 +528,7 @@ context('Sequence diagram', () => { ); }); }); - context('background rects', () => { + describe('background rects', () => { it('should render a single and nested rects', () => { imgSnapshotTest( ` @@ -785,7 +808,7 @@ context('Sequence diagram', () => { ); }); }); - context('directives', () => { + describe('directives', () => { it('should override config with directive settings', () => { imgSnapshotTest( ` @@ -817,7 +840,7 @@ context('Sequence diagram', () => { ); }); }); - context('links', () => { + describe('links', () => { it('should support actor links', () => { renderGraph( ` @@ -833,7 +856,7 @@ context('Sequence diagram', () => { ); cy.get('#actor0_popup').should((popupMenu) => { const style = popupMenu.attr('style'); - expect(style).to.undefined; + // expect(style).to.undefined; }); cy.get('#root-0').click(); cy.get('#actor0_popup').should((popupMenu) => { @@ -908,7 +931,7 @@ context('Sequence diagram', () => { ); }); }); - context('svg size', () => { + describe('svg size', () => { it('should render a sequence diagram when useMaxWidth is true (default)', () => { renderGraph( ` @@ -987,7 +1010,7 @@ context('Sequence diagram', () => { }); }); }); - context('render after error', () => { + describe('render after error', () => { it('should render diagram after fixing destroy participant error', () => { cy.on('uncaught:exception', (err) => { return false; diff --git a/cypress/integration/rendering/stateDiagram-v2.spec.js b/cypress/integration/rendering/stateDiagram-v2.spec.js index 9a1a27abe5..606a1a3f57 100644 --- a/cypress/integration/rendering/stateDiagram-v2.spec.js +++ b/cypress/integration/rendering/stateDiagram-v2.spec.js @@ -8,7 +8,6 @@ describe('State diagram', () => { `, { logLevel: 1, fontFamily: 'courier' } ); - cy.get('svg'); }); it('v2 should render a simple state diagrams', () => { imgSnapshotTest( @@ -20,7 +19,6 @@ describe('State diagram', () => { `, { logLevel: 0, fontFamily: 'courier' } ); - cy.get('svg'); }); it('v2 should render a long descriptions instead of id when available', () => { imgSnapshotTest( @@ -32,7 +30,6 @@ describe('State diagram', () => { `, { logLevel: 0, fontFamily: 'courier' } ); - cy.get('svg'); }); it('v2 should render a long descriptions with additional descriptions', () => { imgSnapshotTest( @@ -44,7 +41,6 @@ describe('State diagram', () => { `, { logLevel: 0, fontFamily: 'courier' } ); - cy.get('svg'); }); it('v2 should render a single state with short descriptions', () => { imgSnapshotTest( @@ -55,7 +51,6 @@ describe('State diagram', () => { `, { logLevel: 0, fontFamily: 'courier' } ); - cy.get('svg'); }); it('v2 should render a transition descriptions with new lines', () => { imgSnapshotTest( @@ -69,7 +64,6 @@ describe('State diagram', () => { `, { logLevel: 0, fontFamily: 'courier' } ); - cy.get('svg'); }); it('v2 should render a state with a note', () => { imgSnapshotTest( @@ -83,7 +77,6 @@ describe('State diagram', () => { `, { logLevel: 0, fontFamily: 'courier' } ); - cy.get('svg'); }); it('v2 should render a state with on the left side when so specified', () => { imgSnapshotTest( @@ -97,7 +90,6 @@ describe('State diagram', () => { `, { logLevel: 0, fontFamily: 'courier' } ); - cy.get('svg'); }); it('v2 should render a state with a note together with another state', () => { imgSnapshotTest( @@ -113,7 +105,6 @@ describe('State diagram', () => { `, { logLevel: 0, fontFamily: 'courier' } ); - cy.get('svg'); }); it('v2 should render a note with multiple lines in it', () => { imgSnapshotTest( @@ -156,7 +147,6 @@ describe('State diagram', () => { `, { logLevel: 0, fontFamily: 'courier' } ); - cy.get('svg'); }); it('v2 should render a simple state diagrams 2', () => { imgSnapshotTest( @@ -169,7 +159,6 @@ describe('State diagram', () => { `, { logLevel: 0, fontFamily: 'courier' } ); - cy.get('svg'); }); it('v2 should render a simple state diagrams with labels', () => { imgSnapshotTest( @@ -185,7 +174,6 @@ describe('State diagram', () => { `, { logLevel: 0, fontFamily: 'courier' } ); - cy.get('svg'); }); it('v2 should render state descriptions', () => { imgSnapshotTest( @@ -198,7 +186,6 @@ describe('State diagram', () => { `, { logLevel: 0, fontFamily: 'courier' } ); - cy.get('svg'); }); it('v2 should render composite states', () => { imgSnapshotTest( @@ -217,7 +204,6 @@ describe('State diagram', () => { `, { logLevel: 0, fontFamily: 'courier' } ); - cy.get('svg'); }); it('v2 should render multiple composite states', () => { imgSnapshotTest( @@ -287,7 +273,6 @@ describe('State diagram', () => { `, { logLevel: 0, fontFamily: 'courier' } ); - cy.get('svg'); }); it('v2 should render concurrency states', () => { imgSnapshotTest( @@ -311,7 +296,6 @@ describe('State diagram', () => { `, { logLevel: 0, fontFamily: 'courier' } ); - cy.get('svg'); }); it('v2 should render a state with states in it', () => { imgSnapshotTest( @@ -558,6 +542,43 @@ stateDiagram-v2 { logLevel: 0, fontFamily: 'courier' } ); }); + it(' can have styles applied ', () => { + imgSnapshotTest( + ` +stateDiagram-v2 +AState +style AState fill:#636,border:1px solid red,color:white; + `, + { logLevel: 0, fontFamily: 'courier' } + ); + }); + it(' should let styles take preceedence over classes', () => { + imgSnapshotTest( + ` +stateDiagram-v2 +AState: Should NOT be white +BState +classDef exampleStyleClass fill:#fff,color: blue; +class AState,BState exampleStyleClass +style AState fill:#636,border:1px solid red,color:white; + `, + { logLevel: 0, fontFamily: 'courier' } + ); + }); + it(' should allow styles to take effect in stubgraphs', () => { + imgSnapshotTest( + ` + stateDiagram + state roundWithTitle { + C: Black with white text + } + D: Black with white text + + style C,D stroke:#00f, fill:black, color:white + `, + { logLevel: 0, fontFamily: 'courier' } + ); + }); }); it('1433: should render a simple state diagram with a title', () => { imgSnapshotTest( @@ -567,6 +588,20 @@ title: simple state diagram stateDiagram-v2 [*] --> State1 State1 --> [*] +`, + {} + ); + }); + it('should align dividers correctly', () => { + imgSnapshotTest( + `stateDiagram-v2 + state s2 { + s3 + -- + s4 + -- + 55 + } `, {} ); diff --git a/cypress/integration/rendering/stateDiagram.spec.js b/cypress/integration/rendering/stateDiagram.spec.js index 01e7a2b44e..9be1f23224 100644 --- a/cypress/integration/rendering/stateDiagram.spec.js +++ b/cypress/integration/rendering/stateDiagram.spec.js @@ -10,7 +10,6 @@ describe('State diagram', () => { `, { logLevel: 0, fontFamily: 'courier' } ); - cy.get('svg'); }); it('should render a long descriptions instead of id when available', () => { imgSnapshotTest( @@ -22,7 +21,6 @@ describe('State diagram', () => { `, { logLevel: 0, fontFamily: 'courier' } ); - cy.get('svg'); }); it('should render a long descriptions with additional descriptions', () => { imgSnapshotTest( @@ -34,7 +32,6 @@ describe('State diagram', () => { `, { logLevel: 0, fontFamily: 'courier' } ); - cy.get('svg'); }); it('should render a single state with short descriptions', () => { imgSnapshotTest( @@ -45,7 +42,6 @@ describe('State diagram', () => { `, { logLevel: 0, fontFamily: 'courier' } ); - cy.get('svg'); }); it('should render a transition descriptions with new lines', () => { imgSnapshotTest( @@ -59,7 +55,6 @@ describe('State diagram', () => { `, { logLevel: 0, fontFamily: 'courier' } ); - cy.get('svg'); }); it('should render a state with a note', () => { imgSnapshotTest( @@ -73,7 +68,6 @@ describe('State diagram', () => { `, { logLevel: 0, fontFamily: 'courier' } ); - cy.get('svg'); }); it('should render a state with on the left side when so specified', () => { imgSnapshotTest( @@ -87,7 +81,6 @@ describe('State diagram', () => { `, { logLevel: 0, fontFamily: 'courier' } ); - cy.get('svg'); }); it('should render a state with a note together with another state', () => { imgSnapshotTest( @@ -103,7 +96,6 @@ describe('State diagram', () => { `, { logLevel: 0, fontFamily: 'courier' } ); - cy.get('svg'); }); it('should render a note with multiple lines in it', () => { imgSnapshotTest( @@ -146,7 +138,6 @@ describe('State diagram', () => { `, { logLevel: 0, fontFamily: 'courier' } ); - cy.get('svg'); }); it('should render a simple state diagrams 2', () => { imgSnapshotTest( @@ -159,7 +150,6 @@ describe('State diagram', () => { `, { logLevel: 0, fontFamily: 'courier' } ); - cy.get('svg'); }); it('should render a simple state diagrams with labels', () => { imgSnapshotTest( @@ -175,7 +165,6 @@ describe('State diagram', () => { `, { logLevel: 0, fontFamily: 'courier' } ); - cy.get('svg'); }); it('should render state descriptions', () => { imgSnapshotTest( @@ -188,7 +177,6 @@ describe('State diagram', () => { `, { logLevel: 0, fontFamily: 'courier' } ); - cy.get('svg'); }); it('should render composite states', () => { imgSnapshotTest( @@ -207,7 +195,6 @@ describe('State diagram', () => { `, { logLevel: 0, fontFamily: 'courier' } ); - cy.get('svg'); }); it('should render multiple composit states', () => { imgSnapshotTest( @@ -277,7 +264,6 @@ describe('State diagram', () => { `, { logLevel: 0, fontFamily: 'courier' } ); - cy.get('svg'); }); it('should render concurrency states', () => { imgSnapshotTest( @@ -301,7 +287,6 @@ describe('State diagram', () => { `, { logLevel: 0, fontFamily: 'courier' } ); - cy.get('svg'); }); it('should render a state with states in it', () => { imgSnapshotTest( diff --git a/cypress/integration/rendering/theme.spec.js b/cypress/integration/rendering/theme.spec.js index c84ad0c4b7..1965f8c99b 100644 --- a/cypress/integration/rendering/theme.spec.js +++ b/cypress/integration/rendering/theme.spec.js @@ -10,7 +10,6 @@ describe('themeCSS balancing, it', () => { `, {} ); - cy.get('svg'); }); it('should not allow unbalanced CSS definitions 2', () => { imgSnapshotTest( @@ -21,7 +20,6 @@ describe('themeCSS balancing, it', () => { `, {} ); - cy.get('svg'); }); }); @@ -45,7 +43,6 @@ describe('Pie Chart', () => { `, { theme } ); - cy.get('svg'); }); it('should render a flowchart diagram', () => { imgSnapshotTest( @@ -70,7 +67,6 @@ describe('Pie Chart', () => { `, { theme } ); - cy.get('svg'); }); it('should render a new flowchart diagram', () => { imgSnapshotTest( @@ -96,7 +92,6 @@ describe('Pie Chart', () => { `, { theme } ); - cy.get('svg'); }); it('should render a sequence diagram', () => { imgSnapshotTest( @@ -125,7 +120,6 @@ describe('Pie Chart', () => { `, { theme } ); - cy.get('svg'); }); it('should render a class diagram', () => { @@ -175,7 +169,6 @@ describe('Pie Chart', () => { `, { theme } ); - cy.get('svg'); }); it('should render a state diagram', () => { imgSnapshotTest( @@ -210,7 +203,6 @@ stateDiagram `, { theme } ); - cy.get('svg'); }); it('should render a state diagram (v2)', () => { imgSnapshotTest( @@ -245,7 +237,6 @@ stateDiagram-v2 `, { theme } ); - cy.get('svg'); }); it('should render a er diagram', () => { imgSnapshotTest( @@ -266,7 +257,6 @@ erDiagram `, { theme } ); - cy.get('svg'); }); it('should render a user journey diagram', () => { imgSnapshotTest( @@ -287,7 +277,6 @@ erDiagram `, { theme } ); - cy.get('svg'); }); it('should render a gantt diagram', () => { cy.clock(new Date('2014-01-06').getTime()); @@ -326,7 +315,6 @@ erDiagram `, { theme } ); - cy.get('svg'); }); }); }); diff --git a/cypress/integration/rendering/xyChart.spec.js b/cypress/integration/rendering/xyChart.spec.js index 85d998c50b..1245760e81 100644 --- a/cypress/integration/rendering/xyChart.spec.js +++ b/cypress/integration/rendering/xyChart.spec.js @@ -9,7 +9,6 @@ describe('XY Chart', () => { `, {} ); - cy.get('svg'); }); it('Should render a complete chart', () => { imgSnapshotTest( @@ -35,7 +34,6 @@ describe('XY Chart', () => { `, {} ); - cy.get('svg'); }); it('y-axis title not required', () => { imgSnapshotTest( @@ -48,7 +46,6 @@ describe('XY Chart', () => { `, {} ); - cy.get('svg'); }); it('Should render a chart without y-axis with different range', () => { imgSnapshotTest( @@ -60,7 +57,6 @@ describe('XY Chart', () => { `, {} ); - cy.get('svg'); }); it('x axis title not required', () => { imgSnapshotTest( @@ -72,7 +68,6 @@ describe('XY Chart', () => { `, {} ); - cy.get('svg'); }); it('Multiple plots can be rendered', () => { imgSnapshotTest( @@ -87,7 +82,6 @@ describe('XY Chart', () => { `, {} ); - cy.get('svg'); }); it('Decimals and negative numbers are supported', () => { imgSnapshotTest( @@ -98,7 +92,6 @@ describe('XY Chart', () => { `, {} ); - cy.get('svg'); }); it('Render spark line with "plotReservedSpacePercent"', () => { imgSnapshotTest( @@ -116,7 +109,6 @@ describe('XY Chart', () => { `, {} ); - cy.get('svg'); }); it('Render spark bar without displaying other property', () => { imgSnapshotTest( @@ -143,7 +135,6 @@ describe('XY Chart', () => { `, {} ); - cy.get('svg'); }); it('Should use all the config from directive', () => { imgSnapshotTest( @@ -158,7 +149,6 @@ describe('XY Chart', () => { `, {} ); - cy.get('svg'); }); it('Should use all the config from yaml', () => { imgSnapshotTest( @@ -199,7 +189,6 @@ describe('XY Chart', () => { `, {} ); - cy.get('svg'); }); it('Render with show axis title false', () => { imgSnapshotTest( @@ -221,7 +210,6 @@ describe('XY Chart', () => { `, {} ); - cy.get('svg'); }); it('Render with show axis label false', () => { imgSnapshotTest( @@ -243,7 +231,6 @@ describe('XY Chart', () => { `, {} ); - cy.get('svg'); }); it('Render with show axis tick false', () => { imgSnapshotTest( @@ -265,7 +252,6 @@ describe('XY Chart', () => { `, {} ); - cy.get('svg'); }); it('Render with show axis line false', () => { imgSnapshotTest( @@ -287,7 +273,6 @@ describe('XY Chart', () => { `, {} ); - cy.get('svg'); }); it('Render all the theme color', () => { imgSnapshotTest( @@ -317,6 +302,17 @@ describe('XY Chart', () => { `, {} ); + }); + it('should use the correct distances between data points', () => { + imgSnapshotTest( + ` + xychart-beta + x-axis 0 --> 2 + line [0, 1, 0, 1] + bar [1, 0, 1, 0] + `, + {} + ); cy.get('svg'); }); }); diff --git a/cypress/platform/ashish2.html b/cypress/platform/ashish2.html index bb0aba27ed..f9132d2e24 100644 --- a/cypress/platform/ashish2.html +++ b/cypress/platform/ashish2.html @@ -4,7 +4,7 @@ ) B(Bold text!)`; -if (location.href.match('test-html-escaping')) { +if (/test-html-escaping/.exec(location.href)) { code = code3; } diff --git a/cypress/platform/class.html b/cypress/platform/class.html index 6bf0822674..0b1a5729ad 100644 --- a/cypress/platform/class.html +++ b/cypress/platform/class.html @@ -3,7 +3,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DagreDagre with roughELKELK with rough
+ +
+
+
+              flowchart LR
+              id1([This is the text in the box])
+            
+
+
+
+
+flowchart LR
+    id1([This is the text in the box])
+
+      
+
+
+%%{init: {"look": "handDrawn"} }%%
+flowchart LR
+    id1([This is the text in the box])
+      
+
+
+%%{init: {"handDrawn": false, "layout": "elk"} }%%
+flowchart LR
+    id1([This is the text in the box])
+      
+
+
+%%{init: {"look": "handDrawn", "layout": "elk"} }%%
+flowchart LR
+    id1([This is the text in the box])
+      
+
+ +
+
+
+      flowchart LR
+    id1[[This is the text in the box]]
+    
+
+
+
+
+flowchart LR
+    id1[[This is the text in the box]]
+      
+
+
+%%{init: {"look": "handDrawn"} }%%
+flowchart LR
+    id1[[This is the text in the box]]
+      
+
+
+%%{init: {"handDrawn": false, "layout": "elk"} }%%
+flowchart LR
+    id1[[This is the text in the box]]
+      
+
+
+%%{init: {"look": "handDrawn", "layout": "elk"} }%%
+flowchart LR
+    id1[[This is the text in the box]]
+      
+
+ +
+
+
+              flowchart LR
+    id1[(Database)]
+    
+
+
+
+
+          flowchart LR
+    id1[(Database)]
+      
+
+
+          %%{init: {"look": "handDrawn"} }%%
+          flowchart LR
+    id1[(Database)]
+      
+
+
+          %%{init: {"handDrawn": false, "layout": "elk"} }%%
+          flowchart LR
+    id1[(Database)]
+      
+
+
+          %%{init: {"look": "handDrawn", "layout": "elk"} }%%
+          flowchart LR
+    id1[(Database)]
+      
+
+ +
+
+
+              flowchart LR
+    id1((This is the text in the circle))
+    
+
+
+
+
+          flowchart LR
+    id1((This is the text in the circle))
+      
+
+
+          %%{init: {"look": "handDrawn"} }%%
+          flowchart LR
+    id1((This is the text in the circle))
+      
+
+
+          %%{init: {"handDrawn": false, "layout": "elk"} }%%
+          flowchart LR
+    id1((This is the text in the circle))
+      
+
+
+          %%{init: {"look": "handDrawn", "layout": "elk"} }%%
+          flowchart LR
+    id1((This is the text in the circle))
+      
+
+ +
+
+
+              flowchart TD
+    id1(((This is the text in the circle)))
+    
+
+
+
+
+          flowchart TD
+    id1(((This is the text in the circle)))
+      
+
+
+          %%{init: {"look": "handDrawn"} }%%
+          flowchart TD
+    id1(((This is the text in the circle)))
+      
+
+
+          %%{init: {"handDrawn": false, "layout": "elk"} }%%
+          flowchart TD
+    id1(((This is the text in the circle)))
+      
+
+
+          %%{init: {"look": "handDrawn", "layout": "elk"} }%%
+          flowchart TD
+    id1(((This is the text in the circle)))
+      
+
+ +
+
+
+              flowchart LR
+    id1>This is the text in the box]
+    
+
+
+
+
+          flowchart LR
+    id1>This is the text in the box]
+      
+
+
+          %%{init: {"look": "handDrawn"} }%%
+          flowchart LR
+    id1>This is the text in the box]  
+      
+
+
+          %%{init: {"handDrawn": false, "layout": "elk"} }%%
+          flowchart LR
+    id1>This is the text in the box]  
+      
+
+
+          %%{init: {"look": "handDrawn", "layout": "elk"} }%%
+          flowchart LR
+    id1>This is the text in the box]
+      
+
+ +
+
+
+              flowchart LR
+    id1{This is the text in the box}
+    
+
+
+
+
+          flowchart LR
+    id1{This is the text in the box}
+      
+
+
+          %%{init: {"look": "handDrawn"} }%%
+          flowchart LR
+    id1{This is the text in the box}
+      
+
+
+          %%{init: {"handDrawn": false, "layout": "elk"} }%%
+          flowchart LR
+    id1{This is the text in the box}
+      
+
+
+          %%{init: {"look": "handDrawn", "layout": "elk"} }%%
+          flowchart LR
+    id1{This is the text in the box}
+      
+
+ +
+
+
+              flowchart LR
+    id1{{This is the text in the box}}
+    
+
+
+
+
+          flowchart LR
+    id1{{This is the text in the box}}
+      
+
+
+          %%{init: {"handDrawn": false, "layout": "elk"} }%%
+          flowchart LR
+    id1{{This is the text in the box}}
+      
+
+
+          %%{init: {"look": "handDrawn", "layout": "elk"} }%%
+          flowchart LR
+    id1{{This is the text in the box}}
+      
+
+ +
+
+
+              flowchart TD
+    id1[/This is the text in the box/]
+    
+
+
+
+
+          flowchart TD
+    id1[/This is the text in the box/]
+      
+
+
+          %%{init: {"look": "handDrawn"} }%%
+          flowchart TD
+    id1[/This is the text in the box/]  
+      
+
+
+          %%{init: {"handDrawn": false, "layout": "elk"} }%%
+          flowchart TD
+    id1[/This is the text in the box/] 
+      
+
+
+          %%{init: {"look": "handDrawn", "layout": "elk"} }%%
+          flowchart TD
+    id1[/This is the text in the box/]
+      
+
+ +
+
+
+              flowchart TD
+    id1[\This is the text in the box\]
+    
+
+
+
+
+          flowchart TD
+    id1[\This is the text in the box\]
+      
+
+
+          %%{init: {"look": "handDrawn"} }%%
+          flowchart TD
+    id1[\This is the text in the box\]
+      
+
+
+          %%{init: {"handDrawn": false, "layout": "elk"} }%%
+          flowchart TD
+    id1[\This is the text in the box\]
+      
+
+
+          %%{init: {"look": "handDrawn", "layout": "elk"} }%%
+          flowchart TD
+    id1[\This is the text in the box\]
+
+      
+
+ +
+
+
+              flowchart TD
+    A[/Christmas\]
+    
+
+
+
+
+          flowchart TD
+    A[/Christmas\]
+      
+
+
+          %%{init: {"look": "handDrawn"} }%%
+          flowchart TD
+    A[/Christmas\]
+      
+
+
+          %%{init: {"handDrawn": false, "layout": "elk"} }%%
+          flowchart TD
+    A[/Christmas\]
+      
+
+
+          %%{init: {"look": "handDrawn", "layout": "elk"} }%%
+          flowchart TD
+    A[/Christmas\]
+      
+
+ +
+
+
+              flowchart TD
+    A[\Christmas/]
+    
+
+
+
+
+          flowchart TD
+    A[\Christmas/]
+      
+
+
+          %%{init: {"look": "handDrawn"} }%%
+          flowchart TD
+    A[\Christmas/]
+      
+
+
+          %%{init: {"handDrawn": false, "layout": "elk"} }%%
+          flowchart TD
+    A[\Christmas/]
+      
+
+
+          %%{init: {"look": "handDrawn", "layout": "elk"} }%%
+          flowchart TD
+    A[\Christmas/]  
+      
+
+ +
+
+
+              flowchart LR
+    id1(This is the text in the box)
+    
+
+
+
+
+          flowchart LR
+    id1(This is the text in the box)
+      
+
+
+          %%{init: {"look": "handDrawn"} }%%
+          flowchart LR
+    id1(This is the text in the box)
+      
+
+
+          %%{init: {"handDrawn": false, "layout": "elk"} }%%
+          flowchart LR
+    id1(This is the text in the box)
+      
+
+
+          %%{init: {"look": "handDrawn", "layout": "elk"} }%%
+          flowchart LR
+    id1(This is the text in the box) 
+      
+
+ +
+
+
+              flowchart LR
+    id1[This is the text in the box]
+    
+
+
+
+
+          flowchart LR
+    id1[This is the text in the box]
+      
+
+
+          %%{init: {"look": "handDrawn"} }%%
+          flowchart LR
+    id1[This is the text in the box]
+      
+
+
+          %%{init: {"handDrawn": false, "layout": "elk"} }%%
+          flowchart LR
+    id1[This is the text in the box]
+      
+
+
+          %%{init: {"look": "handDrawn", "layout": "elk"} }%%
+          flowchart LR
+    id1[This is the text in the box]
+      
+
+ + + + diff --git a/cypress/platform/flowchart-sate.html b/cypress/platform/flowchart-sate.html new file mode 100644 index 0000000000..37cf4a8287 --- /dev/null +++ b/cypress/platform/flowchart-sate.html @@ -0,0 +1,191 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
State roughFlowchart rough
+ +
+
+
+      flowchart LR
+    id1([This is the text in the box])
+
+  
+
+
+
+
+%%{init: {"look": "handDrawn"} }%%
+stateDiagram-v2
+    stateA
+
+      
+
+
+%%{init: {"look": "handDrawn"} }%%
+flowchart LR
+    id1[[This is the text in the box]]
+
+
+      
+
+ + + + diff --git a/cypress/platform/ghsa3.html b/cypress/platform/ghsa3.html index 5c11457f6b..95436abff8 100644 --- a/cypress/platform/ghsa3.html +++ b/cypress/platform/ghsa3.html @@ -4,7 +4,7 @@ + + + + + + + + + +
+stateDiagram-v2
+    [*] --> Still
+    Still --> [*]
+    Still --> Moving
+    Moving --> Still
+    Moving --> Crash
+    Crash --> [*]    
+
+flowchart RL
+    subgraph "`one`"
+      a1 -- l1 --> a2
+      a1 -- l2 --> a2
+    end
+    
+
+flowchart RL
+    subgraph "`one`"
+      a1 -- l1 --> a2
+      a1 -- l2 --> a2
+    end
+    
+
+flowchart
+id["`A root with a long text that wraps to keep the node size in check. A root with a long text that wraps to keep the node size in check`"]
+
+flowchart LR
+    A[A text that needs to be wrapped wraps to another line]
+    B[A text that needs to be
wrapped wraps to another line] + C["`A text that needs to be wrapped to another line`"]
+
+flowchart LR
+    C["`A text
+        that needs
+        to be wrapped
+        in another
+        way`"]
+  
+
+      classDiagram-v2
+        note "I love this diagram!\nDo you love it?"
+    
+
+    stateDiagram-v2
+    State1: The state with a note with minus - and plus + in it
+    note left of State1
+      Important information! You can write
+      notes with . and  in them.
+    end note    
+
+mindmap
+root
+  Child3(A node with an icon and with a long text that wraps to keep the node size in check)
+
+
+      %%{init: {"theme": "forest"} }%%
+mindmap
+    id1[**Start2**
end] + id2[**Start2**
end] + %% Another comment + id3[**Start2**
end] %% Comment + id4[**Start2**
end
the very end] +
+
+mindmap
+    id1["`**Start2**
+    second line 😎 with long text that is wrapping to the next line`"]
+      id2["`Child **with bold** text`"]
+      id3["`Children of which some
+      is using *italic type of* text`"]
+      id4[Child]
+      id5["`Child
+      Row
+      and another
+      `"]
+    
+
+mindmap
+    id1("`**Root**`"]
+      id2["`A formatted text... with **bold** and *italics*`"]
+      id3[Regular labels works as usual]
+      id4["`Emojis and unicode works too: 🤓
+      शान्तिः سلام  和平 `"]
+
+    
+
+%%{init: {"flowchart": {"defaultRenderer": "elk"}} }%%
+flowchart TB
+  %% I could not figure out how to use double quotes in labels in Mermaid
+  subgraph ibm[IBM Espresso CPU]
+    core0[IBM PowerPC Broadway Core 0]
+    core1[IBM PowerPC Broadway Core 1]
+    core2[IBM PowerPC Broadway Core 2]
+
+    rom[16 KB ROM]
+
+    core0 --- core2
+
+    rom --> core2
+  end
+
+  subgraph amd["`**AMD** Latte GPU`"]
+    mem[Memory & I/O Bridge]
+    dram[DRAM Controller]
+    edram[32 MB EDRAM MEM1]
+    rom[512 B SEEPROM]
+
+    sata[SATA IF]
+    exi[EXI]
+
+    subgraph gx[GX]
+      sram[3 MB 1T-SRAM]
+    end
+
+    radeon[AMD Radeon R7xx GX2]
+
+    mem --- gx
+    mem --- radeon
+
+    rom --- mem
+
+    mem --- sata
+    mem --- exi
+
+    dram --- sata
+    dram --- exi
+  end
+
+  ddr3[2 GB DDR3 RAM MEM2]
+
+  mem --- ddr3
+  dram --- ddr3
+  edram --- ddr3
+
+  core1 --- mem
+
+  exi --- rtc
+  rtc{{rtc}}
+
+
+%%{init: {"flowchart": {"defaultRenderer": "elk", "htmlLabels": false}} }%%
+flowchart TB
+  %% I could not figure out how to use double quotes in labels in Mermaid
+  subgraph ibm[IBM Espresso CPU]
+    core0[IBM PowerPC Broadway Core 0]
+    core1[IBM PowerPC Broadway Core 1]
+    core2[IBM PowerPC Broadway Core 2]
+
+    rom[16 KB ROM]
+
+    core0 --- core2
+
+    rom --> core2
+  end
+
+  subgraph amd["`**AMD** Latte GPU`"]
+    mem[Memory & I/O Bridge]
+    dram[DRAM Controller]
+    edram[32 MB EDRAM MEM1]
+    rom[512 B SEEPROM]
+
+    sata[SATA IF]
+    exi[EXI]
+
+    subgraph gx[GX]
+      sram[3 MB 1T-SRAM]
+    end
+
+    radeon[AMD Radeon R7xx GX2]
+
+    mem --- gx
+    mem --- radeon
+
+    rom --- mem
+
+    mem --- sata
+    mem --- exi
+
+    dram --- sata
+    dram --- exi
+  end
+
+  ddr3[2 GB DDR3 RAM MEM2]
+
+  mem --- ddr3
+  dram --- ddr3
+  edram --- ddr3
+
+  core1 --- mem
+
+  exi --- rtc
+  rtc{{rtc}}
+
+ +
+
+flowchart TB
+  %% I could not figure out how to use double quotes in labels in Mermaid
+  subgraph ibm[IBM Espresso CPU]
+    core0[IBM PowerPC Broadway Core 0]
+    core1[IBM PowerPC Broadway Core 1]
+    core2[IBM PowerPC Broadway Core 2]
+
+    rom[16 KB ROM]
+
+    core0 --- core2
+
+    rom --> core2
+  end
+
+  subgraph amd[AMD Latte GPU]
+    mem[Memory & I/O Bridge]
+    dram[DRAM Controller]
+    edram[32 MB EDRAM MEM1]
+    rom[512 B SEEPROM]
+
+    sata[SATA IF]
+    exi[EXI]
+
+    subgraph gx[GX]
+      sram[3 MB 1T-SRAM]
+    end
+
+    radeon[AMD Radeon R7xx GX2]
+
+    mem --- gx
+    mem --- radeon
+
+    rom --- mem
+
+    mem --- sata
+    mem --- exi
+
+    dram --- sata
+    dram --- exi
+  end
+
+  ddr3[2 GB DDR3 RAM MEM2]
+
+  mem --- ddr3
+  dram --- ddr3
+  edram --- ddr3
+
+  core1 --- mem
+
+  exi --- rtc
+  rtc{{rtc}}
+
+
+   +
+      flowchart LR
+  B1 --be be--x B2
+  B1 --bo bo--o B3
+  subgraph Ugge
+      B2
+      B3
+      subgraph inner
+          B4
+          B5
+      end
+      subgraph inner2
+        subgraph deeper
+          C4
+          C5
+        end
+        C6
+      end
+
+      B4 --> C4
+
+      B3 -- X --> B4
+      B2 --> inner
+
+      C4 --> C5
+  end
+
+  subgraph outer
+      B6
+  end
+  B6 --> B5
+  
+
+sequenceDiagram
+    Customer->>+Stripe: Makes a payment request
+    Stripe->>+Bank: Forwards the payment request to the bank
+    Bank->>+Customer: Asks for authorization
+    Customer->>+Bank: Provides authorization
+    Bank->>+Stripe: Sends a response with payment details
+    Stripe->>+Merchant: Sends a notification of payment receipt
+    Merchant->>+Stripe: Confirms the payment
+    Stripe->>+Customer: Sends a confirmation of payment
+    Customer->>+Merchant: Receives goods or services
+        
+
+mindmap
+  root((mindmap))
+    Origins
+      Long history
+      ::icon(fa fa-book)
+      Popularisation
+        British popular psychology author Tony Buzan
+    Research
+      On effectiveness
and features + On Automatic creation + Uses + Creative techniques + Strategic planning + Argument mapping + Tools + Pen and paper + Mermaid +
+
+
+  example-diagram
+    
+ + + + + + + + + // import mindmap from '../../packages/mermaid-mindmap/src/detector'; // import example from + '../../packages/mermaid-example-diagram/src/mermaid-example-diagram.core.mjs'; import mermaid + from './mermaid.esm.mjs'; // await mermaid.registerExternalDiagrams([example]); + mermaid.parseError = function (err, hash) { // console.error('Mermaid error: ', err); }; + mermaid.initialize({ // theme: 'forest', startOnLoad: true, logLevel: 0, flowchart: { // + defaultRenderer: 'elk', useMaxWidth: false, // htmlLabels: false, htmlLabels: true, }, // + htmlLabels: false, gantt: { useMaxWidth: false, }, useMaxWidth: false, }); function callback() + { alert('It worked'); } mermaid.parseError = function (err, hash) { console.error('In parse + error:'); console.error(err); }; // mermaid.test1('first_slow', 1200).then((r) => + console.info(r)); // mermaid.test1('second_fast', 200).then((r) => console.info(r)); // + mermaid.test1('third_fast', 200).then((r) => console.info(r)); // mermaid.test1('forth_slow', + 1200).then((r) => console.info(r)); + + + + + diff --git a/cypress/platform/knsv.html b/cypress/platform/knsv.html index edecb55572..e0372f00c4 100644 --- a/cypress/platform/knsv.html +++ b/cypress/platform/knsv.html @@ -4,7 +4,7 @@ + + + + + + - -
-      block-beta
-  blockArrowId<["Label"]>(right)
-  blockArrowId2<["Label"]>(left)
-  blockArrowId3<["Label"]>(up)
-  blockArrowId4<["Label"]>(down)
-  blockArrowId5<["Label"]>(x)
-  blockArrowId6<["Label"]>(y)
-  blockArrowId6<["Label"]>(x, down)
-    
-
-block-beta
-  block:e:4
-    columns 2
-      f
-      g
-  end
-
-    
-
-block-beta
-  block:e:4
-    columns 2
-      f
-      g
-      h
-  end
-
-    
-
-block-beta
-  columns 4
-  a b c d
-  block:e:4
-    columns 2
-      f
-      g
-      h
-  end
-  i:4
 
-    
-
-flowchart LR
-  X-- "y" -->z
-    
-
-block-beta
-columns 5
-   A space B
-   A --x B
-    
-
-block-beta
-columns 3
-  a["A wide one"] b:2 c:2 d
-    
-
-block-beta
-  block:e
-      f
-  end
-    
-
-block-beta
-  columns 3
-  a:3
-  block:e:3
-      f
-  end
-  g
-    
-
-block-beta
-  columns 3
-  a:3
-  block:e:3
-      f
-      g
-  end
-  h
-  i
-  j
-
-    
-
-block-beta
-columns 3
-  a b:2
-  block:e:3
-      f
-  end
-  g h i
-    
-
-block-beta
-columns 3
-  a b c
-  e:3
-  f g h
-    
-
-block-beta
-columns 1
-  db(("DB"))
-  blockArrowId6<["   "]>(down)
-  block:ID
-    A
-    B["A wide one in the middle"]
-    C
-  end
-  space
-  D
-  ID --> D
-  C --> D
-  style B fill:#f9F,stroke:#333,stroke-width:4px
-    
-
-block-beta
-  columns 5
-  A1:3
-  A2:1
-  A3
-  B1 B2 B3:3
-    
-
-block-beta
-  block
-    D
-    E
-  end
-  db("This is the text in the box")
-    
-
-block-beta
-
-      block
-        D
-      end
-      A["A: I am a wide one"]
-    
-
-block-beta
-    A["square"]
-    B("rounded")
-    C(("circle"))
-    
-
-block-beta
-    A>"rect_left_inv_arrow"]
-    B{"diamond"}
-    C{{"hexagon"}}
-    
-
-block-beta
-    A(["stadium"])
-    
-
-block-beta
-    %% A[["subroutine"]]
-    %% B[("cylinder")]
-    C>"surprise"]
-    
-
-block-beta
-    A[/"lean right"/]
-    B[\"lean left"\]
-    C[/"trapezoid"\]
-    D[\"trapezoid"/]
-    
- -
+  
+    
+
+---
+config:
+  look: handDrawn
+  flowchart:
+    htmlLabels: false
+---
 flowchart
-      B
-      style B fill:#f9F,stroke:#333,stroke-width:4px
-    
- -
-      flowchart LR
-      a1 -- apa --> b1
-    
- -
-flowchart RL
-  subgraph "`one`"
-    id
-  end
-    
-
-flowchart RL
-    subgraph "`one`"
-      a1 -- l1 --> a2
-      a1 -- l2 --> a2
-    end
-    
-
+      A[I am a long text, where do I go??? handdrawn - false]
+
+
+---
+config:
+  look: handdrawn
+  flowchart:
+    htmlLabels: true
+---
 flowchart
-id["`A root with a long text that wraps to keep the node size in check. A root with a long text that wraps to keep the node size in check`"]
-
-flowchart LR
-    A[A text that needs to be wrapped wraps to another line]
-    B[A text that needs to be
wrapped wraps to another line] - C["`A text that needs to be wrapped to another line`"]
-
-flowchart LR
-    C["`A text
-        that needs
-        to be wrapped
-        in another
-        way`"]
-  
-
-      classDiagram-v2
-        note "I love this diagram!\nDo you love it?"
-    
-
-    stateDiagram-v2
-    State1: The state with a note with minus - and plus + in it
-    note left of State1
-      Important information! You can write
-      notes with . and  in them.
-    end note    
-
-mindmap
-root
-  Child3(A node with an icon and with a long text that wraps to keep the node size in check)
+      A[I am a long text, where do I go??? handdrawn - true]
 
-
-      %%{init: {"theme": "forest"} }%%
-mindmap
-    id1[**Start2**
end] - id2[**Start2**
end] - %% Another comment - id3[**Start2**
end] %% Comment - id4[**Start2**
end
the very end] -
-
-mindmap
-    id1["`**Start2**
-    second line 😎 with long text that is wrapping to the next line`"]
-      id2["`Child **with bold** text`"]
-      id3["`Children of which some
-      is using *italic type of* text`"]
-      id4[Child]
-      id5["`Child
-      Row
-      and another
-      `"]
-    
-
-mindmap
-    id1("`**Root**`"]
-      id2["`A formatted text... with **bold** and *italics*`"]
-      id3[Regular labels works as usual]
-      id4["`Emojis and unicode works too: 🤓
-      शान्तिः سلام  和平 `"]
-
-    
-
-%%{init: {"flowchart": {"defaultRenderer": "elk"}} }%%
-flowchart TB
-  %% I could not figure out how to use double quotes in labels in Mermaid
-  subgraph ibm[IBM Espresso CPU]
-    core0[IBM PowerPC Broadway Core 0]
-    core1[IBM PowerPC Broadway Core 1]
-    core2[IBM PowerPC Broadway Core 2]
-
-    rom[16 KB ROM]
-
-    core0 --- core2
-
-    rom --> core2
-  end
-
-  subgraph amd["`**AMD** Latte GPU`"]
-    mem[Memory & I/O Bridge]
-    dram[DRAM Controller]
-    edram[32 MB EDRAM MEM1]
-    rom[512 B SEEPROM]
-
-    sata[SATA IF]
-    exi[EXI]
-
-    subgraph gx[GX]
-      sram[3 MB 1T-SRAM]
-    end
-
-    radeon[AMD Radeon R7xx GX2]
-
-    mem --- gx
-    mem --- radeon
-
-    rom --- mem
-
-    mem --- sata
-    mem --- exi
-
-    dram --- sata
-    dram --- exi
-  end
-
-  ddr3[2 GB DDR3 RAM MEM2]
-
-  mem --- ddr3
-  dram --- ddr3
-  edram --- ddr3
-
-  core1 --- mem
-
-  exi --- rtc
-  rtc{{rtc}}
+      >
+    
+
+
+---
+config:
+  flowchart:
+    htmlLabels: false
+---
+flowchart
+      A[I am a long text, where do I go??? classic - false]
 
-
-%%{init: {"flowchart": {"defaultRenderer": "elk", "htmlLabels": false}} }%%
-flowchart TB
-  %% I could not figure out how to use double quotes in labels in Mermaid
-  subgraph ibm[IBM Espresso CPU]
-    core0[IBM PowerPC Broadway Core 0]
-    core1[IBM PowerPC Broadway Core 1]
-    core2[IBM PowerPC Broadway Core 2]
-
-    rom[16 KB ROM]
-
-    core0 --- core2
-
-    rom --> core2
-  end
-
-  subgraph amd["`**AMD** Latte GPU`"]
-    mem[Memory & I/O Bridge]
-    dram[DRAM Controller]
-    edram[32 MB EDRAM MEM1]
-    rom[512 B SEEPROM]
-
-    sata[SATA IF]
-    exi[EXI]
-
-    subgraph gx[GX]
-      sram[3 MB 1T-SRAM]
-    end
-
-    radeon[AMD Radeon R7xx GX2]
-
-    mem --- gx
-    mem --- radeon
-
-    rom --- mem
-
-    mem --- sata
-    mem --- exi
-
-    dram --- sata
-    dram --- exi
-  end
-
-  ddr3[2 GB DDR3 RAM MEM2]
-
-  mem --- ddr3
-  dram --- ddr3
-  edram --- ddr3
-
-  core1 --- mem
-
-  exi --- rtc
-  rtc{{rtc}}
+      >
+      
+---
+config:
+  flowchart:
+    htmlLabels: true
+---
+flowchart
+      A[I am a long text, where do I go??? classic - true]
 
- -
-
-flowchart TB
-  %% I could not figure out how to use double quotes in labels in Mermaid
-  subgraph ibm[IBM Espresso CPU]
-    core0[IBM PowerPC Broadway Core 0]
-    core1[IBM PowerPC Broadway Core 1]
-    core2[IBM PowerPC Broadway Core 2]
-
-    rom[16 KB ROM]
-
-    core0 --- core2
-
-    rom --> core2
-  end
-
-  subgraph amd[AMD Latte GPU]
-    mem[Memory & I/O Bridge]
-    dram[DRAM Controller]
-    edram[32 MB EDRAM MEM1]
-    rom[512 B SEEPROM]
-
-    sata[SATA IF]
-    exi[EXI]
-
-    subgraph gx[GX]
-      sram[3 MB 1T-SRAM]
-    end
-
-    radeon[AMD Radeon R7xx GX2]
-
-    mem --- gx
-    mem --- radeon
-
-    rom --- mem
-
-    mem --- sata
-    mem --- exi
-
-    dram --- sata
-    dram --- exi
-  end
-
-  ddr3[2 GB DDR3 RAM MEM2]
+      >
+    
+
+flowchart LR
+    id1(Start)-->id2(Stop)
+    style id1 fill:#f9f,stroke:#333,stroke-width:4px
+    style id2 fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5
 
-  mem --- ddr3
-  dram --- ddr3
-  edram --- ddr3
 
-  core1 --- mem
+    
- exi --- rtc - rtc{{rtc}} -
-
-   -
+    
       flowchart LR
-  B1 --be be--x B2
-  B1 --bo bo--o B3
-  subgraph Ugge
-      B2
-      B3
-      subgraph inner
-          B4
-          B5
-      end
-      subgraph inner2
-        subgraph deeper
-          C4
-          C5
-        end
-        C6
-      end
+    A:::foo & B:::bar --> C:::foobar
+    classDef foo stroke:#f00
+    classDef bar stroke:#0f0
+    classDef ash color:red
+    class C ash
+    style C stroke:#00f, fill:black
 
-      B4 --> C4
-
-      B3 -- X --> B4
-      B2 --> inner
+    
- C4 --> C5 - end +
+      stateDiagram
+    A:::foo
+    B:::bar --> C:::foobar
+    classDef foo stroke:#f00
+    classDef bar stroke:#0f0
+    style C stroke:#00f, fill:black, color:white
 
-  subgraph outer
-      B6
-  end
-  B6 --> B5
-  
-
-sequenceDiagram
-    Customer->>+Stripe: Makes a payment request
-    Stripe->>+Bank: Forwards the payment request to the bank
-    Bank->>+Customer: Asks for authorization
-    Customer->>+Bank: Provides authorization
-    Bank->>+Stripe: Sends a response with payment details
-    Stripe->>+Merchant: Sends a notification of payment receipt
-    Merchant->>+Stripe: Confirms the payment
-    Stripe->>+Customer: Sends a confirmation of payment
-    Customer->>+Merchant: Receives goods or services
-        
-
-mindmap
-  root((mindmap))
-    Origins
-      Long history
-      ::icon(fa fa-book)
-      Popularisation
-        British popular psychology author Tony Buzan
-    Research
-      On effectiveness
and features - On Automatic creation - Uses - Creative techniques - Strategic planning - Argument mapping - Tools - Pen and paper - Mermaid
-
-
-  example-diagram
-    
- - - - - - diff --git a/cypress/platform/knsv3.html b/cypress/platform/knsv3.html index 26368a62a5..1d65c2ddfb 100644 --- a/cypress/platform/knsv3.html +++ b/cypress/platform/knsv3.html @@ -1,4 +1,4 @@ - + diff --git a/cypress/platform/per.html b/cypress/platform/per.html index 902e7a8029..e84cea2d0c 100644 --- a/cypress/platform/per.html +++ b/cypress/platform/per.html @@ -4,7 +4,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DagreDagre with roughELKELK with rough
+ +
+
+
+      stateId
+  
+
+
+
+
+stateDiagram-v2
+    stateId
+      
+
+
+%%{init: {"look": "handDrawn"} }%%
+stateDiagram-v2
+    stateId
+
+      
+
+
+%%{init: {"handDrawn": false, "layout": "elk"} }%%
+stateDiagram-v2
+    stateId
+
+      
+
+
+%%{init: {"look": "handDrawn", "layout": "elk"} }%%
+stateDiagram-v2
+    stateId
+
+      
+
+ +
+
+
+
+    state "description text" as s2
+  
+
+
+
+
+stateDiagram-v2
+    state "This is a state description" as s2
+      
+
+
+%%{init: {"look": "handDrawn"} }%%
+stateDiagram-v2
+    state "This is a state description" as s3
+      
+
+
+%%{init: {"handDrawn": false, "layout": "elk"} }%%
+stateDiagram-v2
+    state "This is a state description" as s4
+      
+
+
+%%{init: {"look": "handDrawn", "layout": "elk"} }%%
+stateDiagram-v2
+    state "This is a state description" as s5
+      
+
+ +
+
+
+
+    s2 :  description text
+  
+
+
+
+
+stateDiagram-v2
+    s21 : This is a state description
+      
+
+
+%%{init: {"look": "handDrawn"} }%%
+stateDiagram-v2
+    s22 : This is a state description
+
+      
+
+
+%%{init: {"handDrawn": false, "layout": "elk"} }%%
+stateDiagram-v2
+    s23 : This is a state description
+
+      
+
+
+%%{init: {"look": "handDrawn", "layout": "elk"} }%%
+stateDiagram-v2
+    s24 : This is a state description
+
+      
+
+ +
+
+
+
+    s1 --> s2
+
+  
+
+
+
+
+
+    stateDiagram-v2
+    s31 --> s32
+
+      
+
+
+%%{init: {"look": "handDrawn"} }%%
+
+   stateDiagram-v2
+    s41 --> s42
+
+
+      
+
+
+%%{init: {"handDrawn": false, "layout": "elk"} }%%
+stateDiagram-v2
+    s51 --> s52
+
+
+      
+
+
+%%{init: {"look": "handDrawn", "layout": "elk"} }%%
+stateDiagram-v2
+    s61 --> s62
+
+
+      
+
+ +
+
+
+
+    s1 --> s2: A transition
+
+  
+
+
+
+
+
+    stateDiagram-v2
+    a1 --> a2: A transition
+
+      
+
+
+%%{init: {"look": "handDrawn"} }%%
+
+   stateDiagram-v2
+    a3 --> a4: A transition
+
+
+      
+
+
+%%{init: {"handDrawn": false, "layout": "elk"} }%%
+stateDiagram-v2
+    a5 --> a6: A transition
+
+
+      
+
+
+%%{init: {"look": "handDrawn", "layout": "elk"} }%%
+stateDiagram-v2
+   a7 --> a8: A transition
+
+
+      
+
+ +
+
+
+
+      [*] --> test
+    test --> [*]
+
+  
+
+
+
+
+
+    stateDiagram-v2
+       [*] --> test
+    test --> [*]
+
+      
+
+
+%%{init: {"look": "handDrawn"} }%%
+
+   stateDiagram-v2
+       [*] --> test
+    test --> [*]
+
+
+      
+
+
+%%{init: {"handDrawn": false, "layout": "elk"} }%%
+stateDiagram-v2
+       [*] --> test
+    test --> [*]
+
+
+      
+
+
+%%{init: {"look": "handDrawn", "layout": "elk"} }%%
+stateDiagram-v2
+      [*] --> test
+    test --> [*]
+
+
+      
+
+ +
+
+
+
+      [*] --> First
+    state First {
+        [*] --> second
+        second --> [*]
+    }
+
+  
+
+
+
+
+
+    stateDiagram-v2
+       [*] --> First
+    state First {
+        [*] --> second
+        second --> [*]
+    }
+
+      
+
+
+%%{init: {"look": "handDrawn"} }%%
+
+   stateDiagram-v2
+       [*] --> First
+    state First {
+        [*] --> second
+        second --> [*]
+    }
+
+
+      
+
+
+%%{init: {"handDrawn": false, "layout": "elk"} }%%
+stateDiagram-v2
+       [*] --> First
+    state First {
+        [*] --> second
+        second --> [*]
+    }
+
+
+      
+
+
+%%{init: {"look": "handDrawn", "layout": "elk"} }%%
+stateDiagram-v2
+      [*] --> First
+    state First {
+        [*] --> second
+        second --> [*]
+    }
+
+
+      
+
+ +
+
+
+
+
+    [*] --> Level1
+
+    state Level1 {
+        [*] --> Level2
+
+        state Level2 {
+            [*] --> level2
+            level2 --> Level3
+
+            state Level3 {
+                [*] --> level3
+                level3 --> [*]
+            }
+        }
+    }
+
+
+  
+
+
+
+
+
+    stateDiagram-v2
+    [*] --> Level1
+
+    state Level1 {
+        [*] --> Level2
+
+        state Level2 {
+            [*] --> level2
+            level2 --> Level3
+
+            state Level3 {
+                [*] --> level3
+                level3 --> [*]
+            }
+        }
+    }
+
+
+      
+
+
+%%{init: {"look": "handDrawn"} }%%
+
+   stateDiagram-v2
+    [*] --> Level1
+
+    state Level1 {
+        [*] --> Level2
+
+        state Level2 {
+            [*] --> level2
+            level2 --> Level3
+
+            state Level3 {
+                [*] --> level3
+                level3 --> [*]
+            }
+        }
+    }
+
+
+
+      
+
+
+%%{init: {"handDrawn": false, "layout": "elk"} }%%
+ stateDiagram-v2
+    [*] --> Level1
+
+    state Level1 {
+        [*] --> Level2
+
+        state Level2 {
+            [*] --> level2
+            level2 --> Level3
+
+            state Level3 {
+                [*] --> level3
+                level3 --> [*]
+            }
+        }
+    }
+
+
+      
+
+
+%%{init: {"look": "handDrawn", "layout": "elk"} }%%
+ stateDiagram-v2
+    [*] --> Level1
+
+    state Level1 {
+        [*] --> Level2
+
+        state Level2 {
+            [*] --> level2
+            level2 --> Level3
+
+            state Level3 {
+                [*] --> level3
+                level3 --> [*]
+            }
+        }
+    }
+
+      
+
+ +
+
+
+    [*] --> B1
+    B1 --> B2
+    B1 --> B3
+
+    state B1 {
+        [*] --> B11
+        B11 --> [*]
+    }
+    state B2 {
+        [*] --> B22
+        B22 --> [*]
+    }
+    state B3 {
+        [*] --> B33
+        B33 --> [*]
+    }
+
+
+
+  
+
+
+
+
+
+    stateDiagram-v2
+    [*] --> B1
+    B1 --> B2
+    B1 --> B3
+
+    state B1 {
+        [*] --> B11
+        B11 --> [*]
+    }
+    state B2 {
+        [*] --> B22
+        B22 --> [*]
+    }
+    state B3 {
+        [*] --> B33
+        B33 --> [*]
+    }
+      
+
+
+%%{init: {"look": "handDrawn"} }%%
+
+   stateDiagram-v2
+   [*] --> B1
+    B1 --> B2
+    B1 --> B3
+
+    state B1 {
+        [*] --> B11
+        B11 --> [*]
+    }
+    state B2 {
+        [*] --> B22
+        B22 --> [*]
+    }
+    state B3 {
+        [*] --> B33
+        B33 --> [*]
+    }
+      
+
+
+%%{init: {"handDrawn": false, "layout": "elk"} }%%
+ stateDiagram-v2
+  [*] --> B1
+    B1 --> B2
+    B1 --> B3
+
+    state B1 {
+        [*] --> B11
+        B11 --> [*]
+    }
+    state B2 {
+        [*] --> B22
+        B22 --> [*]
+    }
+    state B3 {
+        [*] --> B33
+        B33 --> [*]
+    }
+
+      
+
+
+%%{init: {"look": "handDrawn", "layout": "elk"} }%%
+ stateDiagram-v2
+[*] --> B1
+    B1 --> B2
+    B1 --> B3
+
+    state B1 {
+        [*] --> B11
+        B11 --> [*]
+    }
+    state B2 {
+        [*] --> B22
+        B22 --> [*]
+    }
+    state B3 {
+        [*] --> B33
+        B33 --> [*]
+    }
+      
+
+ +
+
+
+    state if_state <<choice>>
+    [*] --> IsPositive
+    IsPositive --> if_state
+    if_state --> False: if n < 0
+    if_state --> True : if n >= 0
+
+
+
+
+  
+
+
+
+
+
+    stateDiagram-v2
+    state if_state <>
+    [*] --> IsPositive
+    IsPositive --> if_state
+    if_state --> False: if n < 0
+    if_state --> True : if n >= 0
+      
+
+
+%%{init: {"look": "handDrawn"} }%%
+
+   stateDiagram-v2
+   state if_state <>
+    [*] --> IsPositive
+    IsPositive --> if_state
+    if_state --> False: if n < 0
+    if_state --> True : if n >= 0
+      
+
+
+%%{init: {"handDrawn": false, "layout": "elk"} }%%
+ stateDiagram-v2
+   state if_state <>
+    [*] --> IsPositive
+    IsPositive --> if_state
+    if_state --> False: if n < 0
+    if_state --> True : if n >= 0
+      
+
+
+%%{init: {"look": "handDrawn", "layout": "elk"} }%%
+ stateDiagram-v2
+ state if_state <>
+    [*] --> IsPositive
+    IsPositive --> if_state
+    if_state --> False: if n < 0
+    if_state --> True : if n >= 0
+      
+
+ +
+
+
+    state fork_state <<fork>>
+      [*] --> fork_state
+      fork_state --> State2
+      fork_state --> State3
+
+      state join_state <<join>>
+      State2 --> join_state
+      State3 --> join_state
+      join_state --> State4
+      State4 --> [*]
+
+
+
+  
+
+
+
+
+   stateDiagram-v2
+    state fork_state <>
+      [*] --> fork_state
+      fork_state --> State2
+      fork_state --> State3
+
+      state join_state <>
+      State2 --> join_state
+      State3 --> join_state
+      join_state --> State4
+      State4 --> [*]
+
+      
+
+
+%%{init: {"look": "handDrawn"} }%%
+   stateDiagram-v2
+    state fork_state <>
+      [*] --> fork_state
+      fork_state --> State2
+      fork_state --> State3
+
+      state join_state <>
+      State2 --> join_state
+      State3 --> join_state
+      join_state --> State4
+      State4 --> [*]
+
+      
+
+
+%%{init: {"handDrawn": false, "layout": "elk"} }%%
+   stateDiagram-v2
+    state fork_state <>
+      [*] --> fork_state
+      fork_state --> State2
+      fork_state --> State3
+
+      state join_state <>
+      State2 --> join_state
+      State3 --> join_state
+      join_state --> State4
+      State4 --> [*]
+
+      
+
+
+%%{init: {"look": "handDrawn", "layout": "elk"} }%%
+   stateDiagram-v2
+    state fork_state <>
+      [*] --> fork_state
+      fork_state --> State2
+      fork_state --> State3
+
+      state join_state <>
+      State2 --> join_state
+      State3 --> join_state
+      join_state --> State4
+      State4 --> [*]
+
+      
+
+ +
+
+
+
+  TN1: The state with a note
+  note right of TN1
+      note text
+  end note
+  TN1 --> TN2
+  note left of TN2 : note text
+
+  
+
+
+
+
+   stateDiagram-v2
+     TN1: The state with a note
+        note right of TN1
+            Important information! You can write
+            notes.
+        end note
+        TN1 --> TN2
+        note left of TN2 : This is the note to the left.
+
+      
+
+
+%%{init: {"look": "handDrawn"} }%%
+   stateDiagram-v2
+     TN3: The state with a note
+        note right of TN3
+            Important information! You can write
+            notes.
+        end note
+        TN3 --> TN4
+        note left of TN4 : This is the note to the left.
+      
+
+
+%%{init: {"handDrawn": false, "layout": "elk"} }%%
+   stateDiagram-v2
+     TN5: The state with a note
+        note right of TN5
+            Important information! You can write
+            notes.
+        end note
+        TN5 --> TN6
+        note left of TN6 : This is the note to the left.
+
+      
+
+
+%%{init: {"look": "handDrawn", "layout": "elk"} }%%
+   stateDiagram-v2
+     TN7: The state with a note
+        note right of TN7
+            Important information! You can write
+            notes.
+        end note
+        TN7 --> TN8
+        note left of TN8 : This is the note to the left.
+      
+
+ +
+
+
+[*] --> Active
+
+state Active {
+    [*] --> NumLockOff
+    NumLockOff --> NumLockOn : EvNumLockPressed
+    NumLockOn --> NumLockOff : EvNumLockPressed
+    --
+    [*] --> CapsLockOff
+    CapsLockOff --> CapsLockOn : EvCapsLockPressed
+    CapsLockOn --> CapsLockOff : EvCapsLockPressed
+    --
+    [*] --> ScrollLockOff
+    ScrollLockOff --> ScrollLockOn : EvScrollLockPressed
+    ScrollLockOn --> ScrollLockOff : EvScrollLockPressed
+}
+
+
+  
+
+
+
+
+     stateDiagram-v2
+    [*] --> Active
+
+    state Active {
+        [*] --> NumLockOff
+        NumLockOff --> NumLockOn : EvNumLockPressed
+        NumLockOn --> NumLockOff : EvNumLockPressed
+        --
+        [*] --> CapsLockOff
+        CapsLockOff --> CapsLockOn : EvCapsLockPressed
+        CapsLockOn --> CapsLockOff : EvCapsLockPressed
+        --
+        [*] --> ScrollLockOff
+        ScrollLockOff --> ScrollLockOn : EvScrollLockPressed
+        ScrollLockOn --> ScrollLockOff : EvScrollLockPressed
+    }
+
+      
+
+
+%%{init: {"look": "handDrawn"} }%%
+     stateDiagram-v2
+    [*] --> Active
+
+    state Active {
+        [*] --> NumLockOff
+        NumLockOff --> NumLockOn : EvNumLockPressed
+        NumLockOn --> NumLockOff : EvNumLockPressed
+        --
+        [*] --> CapsLockOff
+        CapsLockOff --> CapsLockOn : EvCapsLockPressed
+        CapsLockOn --> CapsLockOff : EvCapsLockPressed
+        --
+        [*] --> ScrollLockOff
+        ScrollLockOff --> ScrollLockOn : EvScrollLockPressed
+        ScrollLockOn --> ScrollLockOff : EvScrollLockPressed
+    }
+      
+
+
+%%{init: {"handDrawn": false, "layout": "elk"} }%%
+     stateDiagram-v2
+    [*] --> Active
+
+    state Active {
+        [*] --> NumLockOff
+        NumLockOff --> NumLockOn : EvNumLockPressed
+        NumLockOn --> NumLockOff : EvNumLockPressed
+        --
+        [*] --> CapsLockOff
+        CapsLockOff --> CapsLockOn : EvCapsLockPressed
+        CapsLockOn --> CapsLockOff : EvCapsLockPressed
+        --
+        [*] --> ScrollLockOff
+        ScrollLockOff --> ScrollLockOn : EvScrollLockPressed
+        ScrollLockOn --> ScrollLockOff : EvScrollLockPressed
+    }
+
+      
+
+
+%%{init: {"look": "handDrawn", "layout": "elk"} }%%
+     stateDiagram-v2
+    [*] --> Active
+
+    state Active {
+        [*] --> NumLockOff
+        NumLockOff --> NumLockOn : EvNumLockPressed
+        NumLockOn --> NumLockOff : EvNumLockPressed
+        --
+        [*] --> CapsLockOff
+        CapsLockOff --> CapsLockOn : EvCapsLockPressed
+        CapsLockOn --> CapsLockOff : EvCapsLockPressed
+        --
+        [*] --> ScrollLockOff
+        ScrollLockOff --> ScrollLockOn : EvScrollLockPressed
+        ScrollLockOn --> ScrollLockOff : EvScrollLockPressed
+    }
+      
+
+ +
+
+
+direction LR
+    [*] --> D1
+    D1 --> D2
+    D2 --> D3
+    state D3 {
+      direction TB
+      D11 --> D22
+    }
+    D2 --> D4
+  
+
+
+
+
+     stateDiagram-v2
+    direction LR
+    [*] --> D1
+    D1 --> D2
+    D2 --> D3
+    state D3 {
+      direction TB
+      D11 --> D22
+    }
+    D2 --> D4
+      
+
+
+%%{init: {"look": "handDrawn"} }%%
+     stateDiagram-v2
+   direction LR
+    [*] --> D1
+    D1 --> D2
+    D2 --> D3
+    state D3 {
+      direction TB
+      D11 --> D22
+    }
+    D2 --> D4
+      
+
+
+%%{init: {"handDrawn": false, "layout": "elk"} }%%
+     stateDiagram-v2
+    direction LR
+    [*] --> D1
+    D1 --> D2
+    D2 --> D3
+    state D3 {
+      direction TB
+      D11 --> D22
+    }
+    D2 --> D4
+      
+
+
+%%{init: {"look": "handDrawn", "layout": "elk"} }%%
+     stateDiagram-v2
+    direction LR
+    [*] --> D1
+    D1 --> D2
+    D2 --> D3
+    state D3 {
+      direction TB
+      D11 --> D22
+    }
+    D2 --> D4
+      
+
Additional ContentNew content 1New content 2New content 3New content 4
+ + + + + + \ No newline at end of file diff --git a/cypress/platform/viewer.js b/cypress/platform/viewer.js index 482a90646d..0b480b8bc3 100644 --- a/cypress/platform/viewer.js +++ b/cypress/platform/viewer.js @@ -1,5 +1,5 @@ import mermaid from './mermaid.esm.mjs'; -import flowchartELK from './mermaid-flowchart-elk.esm.mjs'; +import { layouts } from './mermaid-layout-elk.esm.mjs'; import externalExample from './mermaid-example-diagram.esm.mjs'; import zenUml from './mermaid-zenuml.esm.mjs'; @@ -46,7 +46,9 @@ const contentLoaded = async function () { document.getElementsByTagName('body')[0].appendChild(div); } - await mermaid.registerExternalDiagrams([externalExample, zenUml, flowchartELK]); + await mermaid.registerExternalDiagrams([externalExample, zenUml]); + + mermaid.registerLayoutLoaders(layouts); mermaid.initialize(graphObj.mermaid); await mermaid.run(); } @@ -132,7 +134,7 @@ if (typeof document !== 'undefined') { window.addEventListener( 'load', function () { - if (this.location.href.match('xss.html')) { + if (/xss.html/.exec(this.location.href)) { this.console.log('Using api'); void contentLoadedApi().finally(markRendered); } else { diff --git a/cypress/platform/xss10.html b/cypress/platform/xss10.html index b28a3c0a8a..91b0b94ac5 100644 --- a/cypress/platform/xss10.html +++ b/cypress/platform/xss10.html @@ -4,7 +4,7 @@ + + + + + + + + + +
Security check
+
+
+
+
+ + + diff --git a/cypress/platform/xss4.html b/cypress/platform/xss4.html index e90c9a6c5a..614fe09b35 100644 --- a/cypress/platform/xss4.html +++ b/cypress/platform/xss4.html @@ -4,7 +4,7 @@ Sequence diagram demos Alice-xJohn: Hello John, how are you? John--xAlice: Great!
+ +
+ +
+    sequenceDiagram
+      participant Alice
+      participant Bob
+      Alice<<->>Bob: Hello!
+      Alice<<->>Bob: Wow, we said that at the same time!
+      Bob<<-->>Alice: Bidirectional Arrows are so cool
+    
@@ -913,7 +913,7 @@ flowchart LR > **Success** The tooltip functionality and the ability to link to urls are available from version 0.5.2. -?> Due to limitations with how Docsify handles JavaScript callback functions, an alternate working demo for the above code can be viewed at [this jsfiddle](https://jsfiddle.net/Ogglas/2o73vdez/7). +?> Due to limitations with how Docsify handles JavaScript callback functions, an alternate working demo for the above code can be viewed at [this jsfiddle](https://jsfiddle.net/yk4h7qou/2/). Links are opened in the same browser tab/window by default. It is possible to change this by adding a link target to the click definition (`_self`, `_blank`, `_parent` and `_top` are supported): @@ -957,7 +957,7 @@ Beginner's tip—a full example using interactive links in a html context: ' ); let states = stateDb.getStates(); - expect(states[testStateId].descriptions[0]).toEqual('desc outside the script '); + expect(states.get(testStateId).descriptions[0]).toEqual('desc outside the script '); }); it('adds the description to the state with the given id', () => { stateDb.addDescription(testStateId, 'the description'); let states = stateDb.getStates(); - expect(states[testStateId].descriptions[0]).toEqual('the description'); + expect(states.get(testStateId).descriptions[0]).toEqual('the description'); }); }); }); diff --git a/packages/mermaid/src/diagrams/state/stateDiagram-v2.spec.js b/packages/mermaid/src/diagrams/state/stateDiagram-v2.spec.js index c387ff7b3d..53063f41a1 100644 --- a/packages/mermaid/src/diagrams/state/stateDiagram-v2.spec.js +++ b/packages/mermaid/src/diagrams/state/stateDiagram-v2.spec.js @@ -405,7 +405,7 @@ describe('state diagram V2, ', function () { stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2()); const states = stateDb.getStates(); - expect(states['Active'].doc[0].id).toEqual('Idle'); + expect(states.get('Active').doc[0].id).toEqual('Idle'); const rels = stateDb.getRelations(); const rel_Inactive_Idle = rels.find((rel) => rel.id1 === 'Inactive' && rel.id2 === 'Idle'); diff --git a/packages/mermaid/src/diagrams/state/stateDiagram-v2.ts b/packages/mermaid/src/diagrams/state/stateDiagram-v2.ts index 36fc95edd1..a27fc18791 100644 --- a/packages/mermaid/src/diagrams/state/stateDiagram-v2.ts +++ b/packages/mermaid/src/diagrams/state/stateDiagram-v2.ts @@ -3,7 +3,7 @@ import type { DiagramDefinition } from '../../diagram-api/types.js'; import parser from './parser/stateDiagram.jison'; import db from './stateDb.js'; import styles from './styles.js'; -import renderer from './stateRenderer-v2.js'; +import renderer from './stateRenderer-v3-unified.js'; export const diagram: DiagramDefinition = { parser, diff --git a/packages/mermaid/src/diagrams/state/stateRenderer-v2.js b/packages/mermaid/src/diagrams/state/stateRenderer-v2.js deleted file mode 100644 index 482e37caee..0000000000 --- a/packages/mermaid/src/diagrams/state/stateRenderer-v2.js +++ /dev/null @@ -1,473 +0,0 @@ -import * as graphlib from 'dagre-d3-es/src/graphlib/index.js'; -import { select } from 'd3'; -import { getConfig } from '../../diagram-api/diagramAPI.js'; -import { render } from '../../dagre-wrapper/index.js'; -import { log } from '../../logger.js'; -import { configureSvgSize } from '../../setupGraphViewbox.js'; -import common from '../common/common.js'; -import utils from '../../utils.js'; - -import { - DEFAULT_DIAGRAM_DIRECTION, - DEFAULT_NESTED_DOC_DIR, - STMT_STATE, - STMT_RELATION, - DEFAULT_STATE_TYPE, - DIVIDER_TYPE, -} from './stateCommon.js'; - -// -------------------------------------- -// Shapes -const SHAPE_STATE = 'rect'; -const SHAPE_STATE_WITH_DESC = 'rectWithTitle'; -const SHAPE_START = 'start'; -const SHAPE_END = 'end'; -const SHAPE_DIVIDER = 'divider'; -const SHAPE_GROUP = 'roundedWithTitle'; -const SHAPE_NOTE = 'note'; -const SHAPE_NOTEGROUP = 'noteGroup'; - -// -------------------------------------- -// CSS classes -const CSS_DIAGRAM = 'statediagram'; -const CSS_STATE = 'state'; -const CSS_DIAGRAM_STATE = `${CSS_DIAGRAM}-${CSS_STATE}`; -const CSS_EDGE = 'transition'; -const CSS_NOTE = 'note'; -const CSS_NOTE_EDGE = 'note-edge'; -const CSS_EDGE_NOTE_EDGE = `${CSS_EDGE} ${CSS_NOTE_EDGE}`; -const CSS_DIAGRAM_NOTE = `${CSS_DIAGRAM}-${CSS_NOTE}`; -const CSS_CLUSTER = 'cluster'; -const CSS_DIAGRAM_CLUSTER = `${CSS_DIAGRAM}-${CSS_CLUSTER}`; -const CSS_CLUSTER_ALT = 'cluster-alt'; -const CSS_DIAGRAM_CLUSTER_ALT = `${CSS_DIAGRAM}-${CSS_CLUSTER_ALT}`; - -// -------------------------------------- -// DOM and element IDs -const PARENT = 'parent'; -const NOTE = 'note'; -const DOMID_STATE = 'state'; -const DOMID_TYPE_SPACER = '----'; -const NOTE_ID = `${DOMID_TYPE_SPACER}${NOTE}`; -const PARENT_ID = `${DOMID_TYPE_SPACER}${PARENT}`; -// -------------------------------------- -// Graph edge settings -const G_EDGE_STYLE = 'fill:none'; -const G_EDGE_ARROWHEADSTYLE = 'fill: #333'; -const G_EDGE_LABELPOS = 'c'; -const G_EDGE_LABELTYPE = 'text'; -const G_EDGE_THICKNESS = 'normal'; - -// -------------------------------------- -// List of nodes created from the parsed diagram statement items -let nodeDb = {}; - -let graphItemCount = 0; // used to construct ids, etc. - -// Configuration -const conf = {}; - -// ----------------------------------------------------------------------- - -export const setConf = function (cnf) { - const keys = Object.keys(cnf); - for (const key of keys) { - conf[key] = cnf[key]; - } -}; - -/** - * Returns the all the classdef styles (a.k.a. classes) from classDef statements in the graph definition. - * - * @param {string} text - the diagram text to be parsed - * @param diagramObj - * @returns {Record} ClassDef styles (a Map with keys = strings, values = ) - */ -export const getClasses = function (text, diagramObj) { - diagramObj.db.extract(diagramObj.db.getRootDocV2()); - return diagramObj.db.getClasses(); -}; - -/** - * Get classes from the db for the info item. - * If there aren't any or if dbInfoItem isn't defined, return an empty string. - * Else create 1 string from the list of classes found - * - * @param {undefined | null | object} dbInfoItem - * @returns {string} - */ -function getClassesFromDbInfo(dbInfoItem) { - if (dbInfoItem === undefined || dbInfoItem === null) { - return ''; - } else { - if (dbInfoItem.classes) { - return dbInfoItem.classes.join(' '); - } else { - return ''; - } - } -} - -/** - * Create a standard string for the dom ID of an item. - * If a type is given, insert that before the counter, preceded by the type spacer - * - * @param itemId - * @param counter - * @param {string | null} type - * @param typeSpacer - * @returns {string} - */ -export function stateDomId(itemId = '', counter = 0, type = '', typeSpacer = DOMID_TYPE_SPACER) { - const typeStr = type !== null && type.length > 0 ? `${typeSpacer}${type}` : ''; - return `${DOMID_STATE}-${itemId}${typeStr}-${counter}`; -} - -/** - * Create a graph node based on the statement information - * - * @param g - graph - * @param {object} parent - * @param {object} parsedItem - parsed statement item - * @param {object[]} diagramStates - the list of all known states for the diagram - * @param {object} diagramDb - * @param {boolean} altFlag - for clusters, add the "statediagram-cluster-alt" CSS class - */ -const setupNode = (g, parent, parsedItem, diagramStates, diagramDb, altFlag) => { - const itemId = parsedItem.id; - const classStr = getClassesFromDbInfo(diagramStates[itemId]); - - if (itemId !== 'root') { - let shape = SHAPE_STATE; - if (parsedItem.start === true) { - shape = SHAPE_START; - } - if (parsedItem.start === false) { - shape = SHAPE_END; - } - if (parsedItem.type !== DEFAULT_STATE_TYPE) { - shape = parsedItem.type; - } - - // Add the node to our list (nodeDb) - if (!nodeDb[itemId]) { - nodeDb[itemId] = { - id: itemId, - shape, - description: common.sanitizeText(itemId, getConfig()), - classes: `${classStr} ${CSS_DIAGRAM_STATE}`, - }; - } - - const newNode = nodeDb[itemId]; - - // Save data for description and group so that for instance a statement without description overwrites - // one with description @todo TODO What does this mean? If important, add a test for it - - // Build of the array of description strings - if (parsedItem.description) { - if (Array.isArray(newNode.description)) { - // There already is an array of strings,add to it - newNode.shape = SHAPE_STATE_WITH_DESC; - newNode.description.push(parsedItem.description); - } else { - if (newNode.description.length > 0) { - // if there is a description already transform it to an array - newNode.shape = SHAPE_STATE_WITH_DESC; - if (newNode.description === itemId) { - // If the previous description was this, remove it - newNode.description = [parsedItem.description]; - } else { - newNode.description = [newNode.description, parsedItem.description]; - } - } else { - newNode.shape = SHAPE_STATE; - newNode.description = parsedItem.description; - } - } - newNode.description = common.sanitizeTextOrArray(newNode.description, getConfig()); - } - - // If there's only 1 description entry, just use a regular state shape - if (newNode.description.length === 1 && newNode.shape === SHAPE_STATE_WITH_DESC) { - newNode.shape = SHAPE_STATE; - } - - // group - if (!newNode.type && parsedItem.doc) { - log.info('Setting cluster for ', itemId, getDir(parsedItem)); - newNode.type = 'group'; - newNode.dir = getDir(parsedItem); - newNode.shape = parsedItem.type === DIVIDER_TYPE ? SHAPE_DIVIDER : SHAPE_GROUP; - newNode.classes = - newNode.classes + - ' ' + - CSS_DIAGRAM_CLUSTER + - ' ' + - (altFlag ? CSS_DIAGRAM_CLUSTER_ALT : ''); - } - - // This is what will be added to the graph - const nodeData = { - labelStyle: '', - shape: newNode.shape, - labelText: newNode.description, - // typeof newNode.description === 'object' - // ? newNode.description[0] - // : newNode.description, - classes: newNode.classes, - style: '', //styles.style, - id: itemId, - dir: newNode.dir, - domId: stateDomId(itemId, graphItemCount), - type: newNode.type, - padding: 15, //getConfig().flowchart.padding - }; - // if (useHtmlLabels) { - nodeData.centerLabel = true; - // } - - if (parsedItem.note) { - // Todo: set random id - const noteData = { - labelStyle: '', - shape: SHAPE_NOTE, - labelText: parsedItem.note.text, - classes: CSS_DIAGRAM_NOTE, - // useHtmlLabels: false, - style: '', // styles.style, - id: itemId + NOTE_ID + '-' + graphItemCount, - domId: stateDomId(itemId, graphItemCount, NOTE), - type: newNode.type, - padding: 15, //getConfig().flowchart.padding - }; - const groupData = { - labelStyle: '', - shape: SHAPE_NOTEGROUP, - labelText: parsedItem.note.text, - classes: newNode.classes, - style: '', // styles.style, - id: itemId + PARENT_ID, - domId: stateDomId(itemId, graphItemCount, PARENT), - type: 'group', - padding: 0, //getConfig().flowchart.padding - }; - graphItemCount++; - - const parentNodeId = itemId + PARENT_ID; - g.setNode(parentNodeId, groupData); - - g.setNode(noteData.id, noteData); - g.setNode(itemId, nodeData); - - g.setParent(itemId, parentNodeId); - g.setParent(noteData.id, parentNodeId); - - let from = itemId; - let to = noteData.id; - - if (parsedItem.note.position === 'left of') { - from = noteData.id; - to = itemId; - } - g.setEdge(from, to, { - arrowhead: 'none', - arrowType: '', - style: G_EDGE_STYLE, - labelStyle: '', - classes: CSS_EDGE_NOTE_EDGE, - arrowheadStyle: G_EDGE_ARROWHEADSTYLE, - labelpos: G_EDGE_LABELPOS, - labelType: G_EDGE_LABELTYPE, - thickness: G_EDGE_THICKNESS, - }); - } else { - g.setNode(itemId, nodeData); - } - } - - if (parent && parent.id !== 'root') { - log.trace('Setting node ', itemId, ' to be child of its parent ', parent.id); - g.setParent(itemId, parent.id); - } - if (parsedItem.doc) { - log.trace('Adding nodes children '); - setupDoc(g, parsedItem, parsedItem.doc, diagramStates, diagramDb, !altFlag); - } -}; - -/** - * Turn parsed statements (item.stmt) into nodes, relationships, etc. for a document. - * (A document may be nested within others.) - * - * @param g - * @param parentParsedItem - parsed Item that is the parent of this document (doc) - * @param doc - the document to set up; it is a list of parsed statements - * @param {object[]} diagramStates - the list of all known states for the diagram - * @param diagramDb - * @param {boolean} altFlag - * @todo This duplicates some of what is done in stateDb.js extract method - */ -const setupDoc = (g, parentParsedItem, doc, diagramStates, diagramDb, altFlag) => { - // graphItemCount = 0; - log.trace('items', doc); - doc.forEach((item) => { - switch (item.stmt) { - case STMT_STATE: - setupNode(g, parentParsedItem, item, diagramStates, diagramDb, altFlag); - break; - case DEFAULT_STATE_TYPE: - setupNode(g, parentParsedItem, item, diagramStates, diagramDb, altFlag); - break; - case STMT_RELATION: - { - setupNode(g, parentParsedItem, item.state1, diagramStates, diagramDb, altFlag); - setupNode(g, parentParsedItem, item.state2, diagramStates, diagramDb, altFlag); - const edgeData = { - id: 'edge' + graphItemCount, - arrowhead: 'normal', - arrowTypeEnd: 'arrow_barb', - style: G_EDGE_STYLE, - labelStyle: '', - label: common.sanitizeText(item.description, getConfig()), - arrowheadStyle: G_EDGE_ARROWHEADSTYLE, - labelpos: G_EDGE_LABELPOS, - labelType: G_EDGE_LABELTYPE, - thickness: G_EDGE_THICKNESS, - classes: CSS_EDGE, - }; - g.setEdge(item.state1.id, item.state2.id, edgeData, graphItemCount); - graphItemCount++; - } - break; - } - }); -}; - -/** - * Get the direction from the statement items. - * Look through all of the documents (docs) in the parsedItems - * Because is a _document_ direction, the default direction is not necessarily the same as the overall default _diagram_ direction. - * @param {object[]} parsedItem - the parsed statement item to look through - * @param [defaultDir] - the direction to use if none is found - * @returns {string} - */ -const getDir = (parsedItem, defaultDir = DEFAULT_NESTED_DOC_DIR) => { - let dir = defaultDir; - if (parsedItem.doc) { - for (let i = 0; i < parsedItem.doc.length; i++) { - const parsedItemDoc = parsedItem.doc[i]; - if (parsedItemDoc.stmt === 'dir') { - dir = parsedItemDoc.value; - } - } - } - return dir; -}; - -/** - * Draws a state diagram in the tag with id: id based on the graph definition in text. - * - * @param {any} text - * @param {any} id - * @param _version - * @param diag - */ -export const draw = async function (text, id, _version, diag) { - log.info('Drawing state diagram (v2)', id); - nodeDb = {}; - // Fetch the default direction, use TD if none was found - let dir = diag.db.getDirection(); - if (dir === undefined) { - dir = DEFAULT_DIAGRAM_DIRECTION; - } - - const { securityLevel, state: conf } = getConfig(); - const nodeSpacing = conf.nodeSpacing || 50; - const rankSpacing = conf.rankSpacing || 50; - - log.info(diag.db.getRootDocV2()); - - // This parses the diagram text and sets the classes, relations, styles, classDefs, etc. - diag.db.extract(diag.db.getRootDocV2()); - log.info(diag.db.getRootDocV2()); - - const diagramStates = diag.db.getStates(); - - // Create the input mermaid.graph - const g = new graphlib.Graph({ - multigraph: true, - compound: true, - }) - .setGraph({ - rankdir: getDir(diag.db.getRootDocV2()), - nodesep: nodeSpacing, - ranksep: rankSpacing, - marginx: 8, - marginy: 8, - }) - .setDefaultEdgeLabel(function () { - return {}; - }); - - setupNode(g, undefined, diag.db.getRootDocV2(), diagramStates, diag.db, true); - - // Set up an SVG group so that we can translate the final graph. - let sandboxElement; - if (securityLevel === 'sandbox') { - sandboxElement = select('#i' + id); - } - const root = - securityLevel === 'sandbox' - ? select(sandboxElement.nodes()[0].contentDocument.body) - : select('body'); - const svg = root.select(`[id="${id}"]`); - - // Run the renderer. This is what draws the final graph. - - const element = root.select('#' + id + ' g'); - await render(element, g, ['barb'], CSS_DIAGRAM, id); - - const padding = 8; - - utils.insertTitle(svg, 'statediagramTitleText', conf.titleTopMargin, diag.db.getDiagramTitle()); - - const bounds = svg.node().getBBox(); - const width = bounds.width + padding * 2; - const height = bounds.height + padding * 2; - - // Zoom in a bit - svg.attr('class', CSS_DIAGRAM); - - const svgBounds = svg.node().getBBox(); - - configureSvgSize(svg, height, width, conf.useMaxWidth); - - // Ensure the viewBox includes the whole svgBounds area with extra space for padding - const vBox = `${svgBounds.x - padding} ${svgBounds.y - padding} ${width} ${height}`; - log.debug(`viewBox ${vBox}`); - svg.attr('viewBox', vBox); - - // Add label rects for non html labels - // if (!evaluate(conf.htmlLabels) || true) { - const labels = document.querySelectorAll('[id="' + id + '"] .edgeLabel .label'); - for (const label of labels) { - // Get dimensions of label - const dim = label.getBBox(); - - const rect = document.createElementNS('http://www.w3.org/2000/svg', SHAPE_STATE); - rect.setAttribute('rx', 0); - rect.setAttribute('ry', 0); - rect.setAttribute('width', dim.width); - rect.setAttribute('height', dim.height); - - label.insertBefore(rect, label.firstChild); - // } - } -}; - -export default { - setConf, - getClasses, - draw, -}; diff --git a/packages/mermaid/src/diagrams/state/stateRenderer-v2.spec.js b/packages/mermaid/src/diagrams/state/stateRenderer-v2.spec.js deleted file mode 100644 index a190fe05be..0000000000 --- a/packages/mermaid/src/diagrams/state/stateRenderer-v2.spec.js +++ /dev/null @@ -1,31 +0,0 @@ -import { expectTypeOf } from 'vitest'; - -import { parser } from './parser/stateDiagram.jison'; -import stateDb from './stateDb.js'; -import stateRendererV2 from './stateRenderer-v2.js'; - -// Can use this instead of having to register diagrams and load/orchestrate them, etc. -class FauxDiagramObj { - db = stateDb; - parser = parser; - renderer = stateRendererV2; - - constructor(options = { db: stateDb, parser: parser, renderer: stateRendererV2 }) { - this.db = options.db; - this.parser = options.parser; - this.renderer = options.renderer; - this.parser.yy = this.db; - } -} - -describe('stateRenderer-v2', () => { - describe('getClasses', () => { - const diagramText = 'statediagram-v2\n'; - const fauxStateDiagram = new FauxDiagramObj(); - - it('returns a {}', () => { - const result = stateRendererV2.getClasses(diagramText, fauxStateDiagram); - expectTypeOf(result).toBeObject(); - }); - }); -}); diff --git a/packages/mermaid/src/diagrams/state/stateRenderer-v3-unified.ts b/packages/mermaid/src/diagrams/state/stateRenderer-v3-unified.ts new file mode 100644 index 0000000000..1f1da6cf2a --- /dev/null +++ b/packages/mermaid/src/diagrams/state/stateRenderer-v3-unified.ts @@ -0,0 +1,85 @@ +import { getConfig } from '../../diagram-api/diagramAPI.js'; +import type { DiagramStyleClassDef } from '../../diagram-api/types.js'; +import { log } from '../../logger.js'; +import { getDiagramElements } from '../../rendering-util/insertElementsForSize.js'; +import { render } from '../../rendering-util/render.js'; +import { setupViewPortForSVG } from '../../rendering-util/setupViewPortForSVG.js'; +import type { LayoutData } from '../../rendering-util/types.js'; +import utils from '../../utils.js'; +import { CSS_DIAGRAM, DEFAULT_NESTED_DOC_DIR } from './stateCommon.js'; + +/** + * Get the direction from the statement items. + * Look through all of the documents (docs) in the parsedItems + * Because is a _document_ direction, the default direction is not necessarily the same as the overall default _diagram_ direction. + * @param parsedItem - the parsed statement item to look through + * @param defaultDir - the direction to use if none is found + * @returns The direction to use + */ +export const getDir = (parsedItem: any, defaultDir = DEFAULT_NESTED_DOC_DIR) => { + if (!parsedItem.doc) { + return defaultDir; + } + + let dir = defaultDir; + + for (const parsedItemDoc of parsedItem.doc) { + if (parsedItemDoc.stmt === 'dir') { + dir = parsedItemDoc.value; + } + } + + return dir; +}; + +export const getClasses = function ( + text: string, + diagramObj: any +): Map { + diagramObj.db.extract(diagramObj.db.getRootDocV2()); + return diagramObj.db.getClasses(); +}; + +export const draw = async function (text: string, id: string, _version: string, diag: any) { + log.info('REF0:'); + log.info('Drawing state diagram (v2)', id); + const { securityLevel, state: conf, layout } = getConfig(); + // Extracting the data from the parsed structure into a more usable form + // Not related to the refactoring, but this is the first step in the rendering process + diag.db.extract(diag.db.getRootDocV2()); + + //const DIR = getDir(diag.db.getRootDocV2()); + + // The getData method provided in all supported diagrams is used to extract the data from the parsed structure + // into the Layout data format + const data4Layout = diag.db.getData() as LayoutData; + + // Create the root SVG - the element is the div containing the SVG element + const { element, svg } = getDiagramElements(id, securityLevel); + + data4Layout.type = diag.type; + data4Layout.layoutAlgorithm = layout; + + // TODO: Should we move these two to baseConfig? These types are not there in StateConfig. + + data4Layout.nodeSpacing = conf?.nodeSpacing || 50; + data4Layout.rankSpacing = conf?.rankSpacing || 50; + data4Layout.markers = ['barb']; + data4Layout.diagramId = id; + // console.log('REF1:', data4Layout); + await render(data4Layout, svg, element); + const padding = 8; + utils.insertTitle( + element, + 'statediagramTitleText', + conf?.titleTopMargin ?? 25, + diag.db.getDiagramTitle() + ); + setupViewPortForSVG(svg, padding, CSS_DIAGRAM, conf?.useMaxWidth ?? true); +}; + +export default { + getClasses, + draw, + getDir, +}; diff --git a/packages/mermaid/src/diagrams/state/styles.js b/packages/mermaid/src/diagrams/state/styles.js index fe3d7078b1..05d530ee36 100644 --- a/packages/mermaid/src/diagrams/state/styles.js +++ b/packages/mermaid/src/diagrams/state/styles.js @@ -68,6 +68,18 @@ g.stateGroup line { fill: ${options.labelBackgroundColor}; opacity: 0.5; } +.edgeLabel { + background-color: ${options.edgeLabelBackground}; + p { + background-color: ${options.edgeLabelBackground}; + } + rect { + opacity: 0.5; + background-color: ${options.edgeLabelBackground}; + fill: ${options.edgeLabelBackground}; + } + text-align: center; +} .edgeLabel .label text { fill: ${options.transitionLabelColor || options.tertiaryTextColor}; } @@ -124,6 +136,7 @@ g.stateGroup line { .cluster-label, .nodeLabel { color: ${options.stateLabelColor}; + // line-height: 1; } .statediagram-cluster rect.outer { diff --git a/packages/mermaid/src/diagrams/timeline/parser/timeline.jison b/packages/mermaid/src/diagrams/timeline/parser/timeline.jison index 136654a7f2..89bfd06f45 100644 --- a/packages/mermaid/src/diagrams/timeline/parser/timeline.jison +++ b/packages/mermaid/src/diagrams/timeline/parser/timeline.jison @@ -18,7 +18,7 @@ \#[^\n]* /* skip comments */ "timeline" return 'timeline'; -"title"\s[^#\n]+ return 'title'; +"title"\s[^\n]+ return 'title'; accTitle\s*":"\s* { this.begin("acc_title");return 'acc_title'; } (?!\n|;|#)*[^\n]* { this.popState(); return "acc_title_value"; } accDescr\s*":"\s* { this.begin("acc_descr");return 'acc_descr'; } @@ -26,10 +26,10 @@ accDescr\s*":"\s* { this.begin("ac accDescr\s*"{"\s* { this.begin("acc_descr_multiline");} [\}] { this.popState(); } [^\}]* return "acc_descr_multiline_value"; -"section"\s[^#:\n]+ return 'section'; +"section"\s[^:\n]+ return 'section'; // event starting with "==>" keyword -":"\s[^#:\n]+ return 'event'; +":"\s[^:\n]+ return 'event'; [^#:\n]+ return 'period'; diff --git a/packages/mermaid/src/diagrams/timeline/svgDraw.js b/packages/mermaid/src/diagrams/timeline/svgDraw.js index 874ac62ef0..723dc46f17 100644 --- a/packages/mermaid/src/diagrams/timeline/svgDraw.js +++ b/packages/mermaid/src/diagrams/timeline/svgDraw.js @@ -258,24 +258,6 @@ export const drawTask = function (elem, task, conf) { rect.ry = 3; drawRect(g, rect); - let xPos = task.x + 14; - // task.people.forEach((person) => { - // const colour = task.actors[person].color; - - // const circle = { - // cx: xPos, - // cy: task.y, - // r: 7, - // fill: colour, - // stroke: '#000', - // title: person, - // pos: task.actors[person].position, - // }; - - // drawCircle(g, circle); - // xPos += 10; - // }); - _drawTextCandidateFunc(conf)( task.task, g, @@ -533,8 +515,7 @@ export const drawNode = function (elem, node, fullSection, conf) { .attr('text-anchor', 'middle') .call(wrap, node.width); const bbox = txt.node().getBBox(); - const fontSize = - conf.fontSize && conf.fontSize.replace ? conf.fontSize.replace('px', '') : conf.fontSize; + const fontSize = conf.fontSize?.replace ? conf.fontSize.replace('px', '') : conf.fontSize; node.height = bbox.height + fontSize * 1.1 * 0.5 + node.padding; node.height = Math.max(node.height, node.maxHeight); node.width = node.width + 2 * node.padding; @@ -558,8 +539,7 @@ export const getVirtualNodeHeight = function (elem, node, conf) { .attr('text-anchor', 'middle') .call(wrap, node.width); const bbox = txt.node().getBBox(); - const fontSize = - conf.fontSize && conf.fontSize.replace ? conf.fontSize.replace('px', '') : conf.fontSize; + const fontSize = conf.fontSize?.replace ? conf.fontSize.replace('px', '') : conf.fontSize; textElem.remove(); return bbox.height + fontSize * 1.1 * 0.5 + node.padding; }; diff --git a/packages/mermaid/src/diagrams/timeline/timeline.spec.js b/packages/mermaid/src/diagrams/timeline/timeline.spec.js index 0cb227fa6b..8cc990dcf9 100644 --- a/packages/mermaid/src/diagrams/timeline/timeline.spec.js +++ b/packages/mermaid/src/diagrams/timeline/timeline.spec.js @@ -1,7 +1,7 @@ +import { setLogLevel } from '../../diagram-api/diagramAPI.js'; +import * as commonDb from '../common/commonDb.js'; import { parser as timeline } from './parser/timeline.jison'; import * as timelineDB from './timelineDb.js'; -import * as commonDb from '../common/commonDb.js'; -import { setLogLevel } from '../../diagram-api/diagramAPI.js'; describe('when parsing a timeline ', function () { beforeEach(function () { @@ -10,7 +10,7 @@ describe('when parsing a timeline ', function () { setLogLevel('trace'); }); describe('Timeline', function () { - it('TL-1 should handle a simple section definition abc-123', function () { + it('should handle a simple section definition abc-123', function () { let str = `timeline section abc-123`; @@ -18,7 +18,7 @@ describe('when parsing a timeline ', function () { expect(timelineDB.getSections()).to.deep.equal(['abc-123']); }); - it('TL-2 should handle a simple section and only two tasks', function () { + it('should handle a simple section and only two tasks', function () { let str = `timeline section abc-123 task1 @@ -30,7 +30,7 @@ describe('when parsing a timeline ', function () { }); }); - it('TL-3 should handle a two section and two coressponding tasks', function () { + it('should handle a two section and two coressponding tasks', function () { let str = `timeline section abc-123 task1 @@ -51,7 +51,7 @@ describe('when parsing a timeline ', function () { }); }); - it('TL-4 should handle a section, and task and its events', function () { + it('should handle a section, and task and its events', function () { let str = `timeline section abc-123 task1: event1 @@ -75,7 +75,7 @@ describe('when parsing a timeline ', function () { }); }); - it('TL-5 should handle a section, and task and its multi line events', function () { + it('should handle a section, and task and its multi line events', function () { let str = `timeline section abc-123 task1: event1 @@ -100,7 +100,7 @@ describe('when parsing a timeline ', function () { }); }); - it('TL-6 should handle a title, section, task, and events with semicolons', function () { + it('should handle a title, section, task, and events with semicolons', function () { let str = `timeline title ;my;title; section ;a;bc-123; @@ -114,5 +114,20 @@ describe('when parsing a timeline ', function () { expect(timelineDB.getTasks()[0].events[1]).equal(';ev;ent2; '); expect(timelineDB.getTasks()[0].events[2]).equal(';ev;ent3;'); }); + + it('should handle a title, section, task, and events with hashtags', function () { + let str = `timeline + title #my#title# + section #a#bc-123# + task1: #ev#ent1# : #ev#ent2# : #ev#ent3# + `; + timeline.parse(str); + expect(commonDb.getDiagramTitle()).equal('#my#title#'); + expect(timelineDB.getSections()).to.deep.equal(['#a#bc-123#']); + expect(timelineDB.getTasks()[0].task).equal('task1'); + expect(timelineDB.getTasks()[0].events[0]).equal('#ev#ent1# '); + expect(timelineDB.getTasks()[0].events[1]).equal('#ev#ent2# '); + expect(timelineDB.getTasks()[0].events[2]).equal('#ev#ent3#'); + }); }); }); diff --git a/packages/mermaid/src/diagrams/timeline/timelineRenderer.ts b/packages/mermaid/src/diagrams/timeline/timelineRenderer.ts index 2f1f156899..b3405bc1bf 100644 --- a/packages/mermaid/src/diagrams/timeline/timelineRenderer.ts +++ b/packages/mermaid/src/diagrams/timeline/timelineRenderer.ts @@ -115,8 +115,7 @@ export const draw = function (text: string, id: string, version: string, diagObj maxEventCount = Math.max(maxEventCount, task.events.length); //calculate maxEventLineLength let maxEventLineLengthTemp = 0; - for (let j = 0; j < task.events.length; j++) { - const event = task.events[j]; + for (const event of task.events) { const eventNode = { descr: event, section: task.section, diff --git a/packages/mermaid/src/diagrams/xychart/chartBuilder/components/axis/bandAxis.ts b/packages/mermaid/src/diagrams/xychart/chartBuilder/components/axis/bandAxis.ts index 864ef1316e..98eb31235d 100644 --- a/packages/mermaid/src/diagrams/xychart/chartBuilder/components/axis/bandAxis.ts +++ b/packages/mermaid/src/diagrams/xychart/chartBuilder/components/axis/bandAxis.ts @@ -40,6 +40,6 @@ export class BandAxis extends BaseAxis { } getScaleValue(value: string): number { - return this.scale(value) || this.getRange()[0]; + return this.scale(value) ?? this.getRange()[0]; } } diff --git a/packages/mermaid/src/diagrams/xychart/chartBuilder/components/axis/baseAxis.ts b/packages/mermaid/src/diagrams/xychart/chartBuilder/components/axis/baseAxis.ts index c3240a4a7b..ef60cc85fd 100644 --- a/packages/mermaid/src/diagrams/xychart/chartBuilder/components/axis/baseAxis.ts +++ b/packages/mermaid/src/diagrams/xychart/chartBuilder/components/axis/baseAxis.ts @@ -58,7 +58,7 @@ export abstract class BaseAxis implements Axis { abstract recalculateScale(): void; - abstract getTickValues(): Array; + abstract getTickValues(): (string | number)[]; getTickDistance(): number { const range = this.getRange(); diff --git a/packages/mermaid/src/diagrams/xychart/xychartDb.ts b/packages/mermaid/src/diagrams/xychart/xychartDb.ts index 637477f28b..23b90724cd 100644 --- a/packages/mermaid/src/diagrams/xychart/xychartDb.ts +++ b/packages/mermaid/src/diagrams/xychart/xychartDb.ts @@ -143,7 +143,7 @@ function transformDataWithoutCategory(data: number[]): SimplePlotDataType { if (isLinearAxisData(xyChartData.xAxis)) { const min = xyChartData.xAxis.min; const max = xyChartData.xAxis.max; - const step = (max - min + 1) / data.length; + const step = (max - min) / (data.length - 1); const categories: string[] = []; for (let i = min; i <= max; i += step) { categories.push(`${i}`); diff --git a/packages/mermaid/src/docs/.vitepress/config.ts b/packages/mermaid/src/docs/.vitepress/config.ts index d937daf634..940fc6940a 100644 --- a/packages/mermaid/src/docs/.vitepress/config.ts +++ b/packages/mermaid/src/docs/.vitepress/config.ts @@ -1,4 +1,5 @@ -import { defineConfig, MarkdownOptions } from 'vitepress'; +import type { MarkdownOptions } from 'vitepress'; +import { defineConfig } from 'vitepress'; import { version } from '../../../package.json'; import MermaidExample from './mermaid-markdown-all.js'; @@ -8,8 +9,9 @@ const allMarkdownTransformers: MarkdownOptions = { light: 'github-light', dark: 'github-dark', }, - config: async (md) => { - await MermaidExample(md); + + config: (md) => { + MermaidExample(md); }, }; @@ -150,9 +152,9 @@ function sidebarSyntax() { { text: 'C4 Diagram 🦺⚠️', link: '/syntax/c4' }, { text: 'Mindmaps', link: '/syntax/mindmap' }, { text: 'Timeline', link: '/syntax/timeline' }, - { text: 'Zenuml', link: '/syntax/zenuml' }, + { text: 'ZenUML', link: '/syntax/zenuml' }, { text: 'Sankey 🔥', link: '/syntax/sankey' }, - { text: 'XYChart 🔥', link: '/syntax/xyChart' }, + { text: 'XY Chart 🔥', link: '/syntax/xyChart' }, { text: 'Block Diagram 🔥', link: '/syntax/block' }, { text: 'Packet 🔥', link: '/syntax/packet' }, { text: 'Other Examples', link: '/syntax/examples' }, @@ -228,8 +230,6 @@ function sidebarNews() { /** * Return a string that puts together the pagePage, a '#', then the given id - * @param pagePath - * @param id * @returns the fully formed path */ function pathToId(pagePath: string, id = ''): string { diff --git a/packages/mermaid/src/docs/.vitepress/contributors.ts b/packages/mermaid/src/docs/.vitepress/contributors.ts index 93eeee2e21..e61cf57e87 100644 --- a/packages/mermaid/src/docs/.vitepress/contributors.ts +++ b/packages/mermaid/src/docs/.vitepress/contributors.ts @@ -1,5 +1,6 @@ import contributorUsernamesJson from './contributor-names.json'; -import { CoreTeam, knut, plainTeamMembers } from './teamMembers.js'; +import type { CoreTeam } from './teamMembers.js'; +import { knut, plainTeamMembers } from './teamMembers.js'; const contributorUsernames: string[] = contributorUsernamesJson; diff --git a/packages/mermaid/src/docs/.vitepress/mermaid-markdown-all.ts b/packages/mermaid/src/docs/.vitepress/mermaid-markdown-all.ts index 64a069b4c2..d1aeee5ac2 100644 --- a/packages/mermaid/src/docs/.vitepress/mermaid-markdown-all.ts +++ b/packages/mermaid/src/docs/.vitepress/mermaid-markdown-all.ts @@ -1,6 +1,6 @@ import type { MarkdownRenderer } from 'vitepress'; -const MermaidExample = async (md: MarkdownRenderer) => { +const MermaidExample = (md: MarkdownRenderer) => { const defaultRenderer = md.renderer.rules.fence; if (!defaultRenderer) { diff --git a/packages/mermaid/src/docs/.vitepress/scripts/fetch-avatars.ts b/packages/mermaid/src/docs/.vitepress/scripts/fetch-avatars.ts index cd78be782a..23c3594440 100644 --- a/packages/mermaid/src/docs/.vitepress/scripts/fetch-avatars.ts +++ b/packages/mermaid/src/docs/.vitepress/scripts/fetch-avatars.ts @@ -32,11 +32,11 @@ async function fetchAvatars() { }); contributors = JSON.parse(await readFile(pathContributors, { encoding: 'utf-8' })); - let avatars = contributors.map((name) => { - download(`https://github.com/${name}.png?size=100`, getAvatarPath(name)); - }); + const avatars = contributors.map((name) => + download(`https://github.com/${name}.png?size=100`, getAvatarPath(name)) + ); await Promise.allSettled(avatars); } -fetchAvatars(); +void fetchAvatars(); diff --git a/packages/mermaid/src/docs/.vitepress/scripts/fetch-contributors.ts b/packages/mermaid/src/docs/.vitepress/scripts/fetch-contributors.ts index da7621b299..54144cf62e 100644 --- a/packages/mermaid/src/docs/.vitepress/scripts/fetch-contributors.ts +++ b/packages/mermaid/src/docs/.vitepress/scripts/fetch-contributors.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-console */ // Adapted from https://github.dev/vitest-dev/vitest/blob/991ff33ab717caee85ef6cbe1c16dc514186b4cc/scripts/update-contributors.ts#L6 import { writeFile } from 'node:fs/promises'; diff --git a/packages/mermaid/src/docs/.vitepress/teamMembers.ts b/packages/mermaid/src/docs/.vitepress/teamMembers.ts index d95f49ed87..e307b81c45 100644 --- a/packages/mermaid/src/docs/.vitepress/teamMembers.ts +++ b/packages/mermaid/src/docs/.vitepress/teamMembers.ts @@ -1,3 +1,4 @@ +/* eslint-disable @cspell/spellchecker */ export interface Contributor { name: string; avatar: string; diff --git a/packages/mermaid/src/docs/.vitepress/theme/index.ts b/packages/mermaid/src/docs/.vitepress/theme/index.ts index 3ebb7614a1..3ce3aea238 100644 --- a/packages/mermaid/src/docs/.vitepress/theme/index.ts +++ b/packages/mermaid/src/docs/.vitepress/theme/index.ts @@ -1,14 +1,16 @@ +/* eslint-disable no-console */ import DefaultTheme from 'vitepress/theme'; import './custom.css'; -// @ts-ignore +// @ts-ignore Type not available import Mermaid from './Mermaid.vue'; -// @ts-ignore +// @ts-ignore Type not available import Contributors from '../components/Contributors.vue'; -// @ts-ignore +// @ts-ignore Type not available import HomePage from '../components/HomePage.vue'; -// @ts-ignore +// @ts-ignore Type not available import TopBar from '../components/TopBar.vue'; import { getRedirect } from './redirect.js'; +// @ts-ignore Type not available import { h } from 'vue'; import Theme from 'vitepress/theme'; import '../style/main.css'; @@ -33,7 +35,7 @@ export default { const url = new URL(window.location.origin + to); const newPath = getRedirect(url); if (newPath) { - console.log(`Redirecting to ${newPath} from ${window.location}`); + console.log(`Redirecting to ${newPath} from ${window.location.toString()}`); // router.go isn't loading the ID properly. window.location.href = `/${newPath}`; } diff --git a/packages/mermaid/src/docs/.vitepress/theme/redirect.ts b/packages/mermaid/src/docs/.vitepress/theme/redirect.ts index 1b04e01d5f..8283951ac8 100644 --- a/packages/mermaid/src/docs/.vitepress/theme/redirect.ts +++ b/packages/mermaid/src/docs/.vitepress/theme/redirect.ts @@ -116,3 +116,5 @@ export const getRedirect = (url: URL): string | undefined => { return `${idRedirectMap[path]}.html${id ? `#${id}` : ''}`; } }; + +// cspell:ignore mermaidapi, breakingchanges, classdiagram, entityrelationshipdiagram, mermaidapi, mermaidcli, gettingstarted, syntaxreference, newdiagram, requirementdiagram, sequencediagram diff --git a/packages/mermaid/src/docs/community/contributing.md b/packages/mermaid/src/docs/community/contributing.md index 195146a612..71048d0952 100644 --- a/packages/mermaid/src/docs/community/contributing.md +++ b/packages/mermaid/src/docs/community/contributing.md @@ -52,7 +52,7 @@ The following commands must be sufficient enough to start with: ```bash curl -fsSL https://get.pnpm.io/install.sh | sh - -pnpm env use --global 18 +pnpm env use --global 20 ``` You may also need to reload `.shrc` or `.bashrc` afterwards. diff --git a/packages/mermaid/src/docs/config/img/mathMLDifferences.png b/packages/mermaid/src/docs/config/img/mathMLDifferences.png new file mode 100644 index 0000000000..6b7a86400f Binary files /dev/null and b/packages/mermaid/src/docs/config/img/mathMLDifferences.png differ diff --git a/packages/mermaid/src/docs/config/math.md b/packages/mermaid/src/docs/config/math.md index 22b398e087..a53dceaf2a 100644 --- a/packages/mermaid/src/docs/config/math.md +++ b/packages/mermaid/src/docs/config/math.md @@ -60,3 +60,13 @@ Example with legacy mode enabled (the latest version of KaTeX's stylesheet can b ``` + +## Handling Rendering Differences + +Due to differences between default fonts across operating systems and browser's MathML implementations, inconsistent results can be seen across platforms. If having consistent results are important, or the most optimal rendered results are desired, `forceLegacyMathML` can be enabled in the config. + +This option will always use KaTeX's stylesheet instead of only when MathML is not supported (as with `legacyMathML`). Note that only `forceLegacyMathML` needs to be set. + +If including KaTeX's stylesheet is not a concern, enabling this option is recommended to avoid scenarios where no MathML implementation within a browser provides the desired output (as seen below). + +![Image showing differences between Browsers](img/mathMLDifferences.png) diff --git a/packages/mermaid/src/docs/config/theming.md b/packages/mermaid/src/docs/config/theming.md index 3863202b42..5643dc7fbd 100644 --- a/packages/mermaid/src/docs/config/theming.md +++ b/packages/mermaid/src/docs/config/theming.md @@ -18,12 +18,12 @@ Themes can now be customized at the site-wide level, or on individual Mermaid di ## Site-wide Theme -To customize themes site-wide, call the `initialize` method on the `mermaidAPI`. +To customize themes site-wide, call the `initialize` method on the `mermaid`. Example of `initialize` call setting `theme` to `base`: ```javascript -mermaidAPI.initialize({ +mermaid.initialize({ securityLevel: 'loose', theme: 'base', }); diff --git a/packages/mermaid/src/docs/config/usage.md b/packages/mermaid/src/docs/config/usage.md index eec87e49f5..0886a0e442 100644 --- a/packages/mermaid/src/docs/config/usage.md +++ b/packages/mermaid/src/docs/config/usage.md @@ -188,7 +188,7 @@ await mermaid.run({ ### Calling `mermaid.init` - Deprecated ```warning -mermaid.init is deprecated in v10 and will be removed in v11. Please use mermaid.run instead. +mermaid.init is deprecated in v10 and will be removed in a future release. Please use mermaid.run instead. ``` By default, `mermaid.init` will be called when the document is ready, finding all elements with @@ -213,10 +213,6 @@ Or with no config object, and a jQuery selection: mermaid.init(undefined, $('#someId .yetAnotherClass')); ``` -```warning -This type of integration is deprecated. Instead the preferred way of handling more complex integration is to use the mermaidAPI instead. -``` - ## Usage with webpack mermaid fully supports webpack. Here is a [working demo](https://github.com/mermaidjs/mermaid-webpack-demo). diff --git a/packages/mermaid/src/docs/ecosystem/integrations-community.md b/packages/mermaid/src/docs/ecosystem/integrations-community.md index 95e71d626d..2d5972f208 100644 --- a/packages/mermaid/src/docs/ecosystem/integrations-community.md +++ b/packages/mermaid/src/docs/ecosystem/integrations-community.md @@ -37,6 +37,8 @@ To add an integration to this list, see the [Integrations - create page](./integ - [CloudScript.io Mermaid Addon](https://marketplace.atlassian.com/apps/1219878/cloudscript-io-mermaid-addon?hosting=cloud&tab=overview) - [Azure Devops](https://learn.microsoft.com/en-us/azure/devops/project/wiki/markdown-guidance?view=azure-devops#add-mermaid-diagrams-to-a-wiki-page) ✅ - [Deepdwn](https://billiam.itch.io/deepdwn) ✅ +- [Doctave](https://www.doctave.com/) ✅ + - [Mermaid in Markdown code blocks](https://docs.doctave.com/components/mermaid) ✅ - [GitBook](https://gitbook.com) - [Mermaid Plugin](https://github.com/JozoVilcek/gitbook-plugin-mermaid) - [Mermaid plugin for GitBook](https://github.com/wwformat/gitbook-plugin-mermaid-pdf) @@ -49,6 +51,7 @@ To add an integration to this list, see the [Integrations - create page](./integ - [SVG diagram generator](https://github.com/SimonKenyonShepard/mermaidjs-github-svg-generator) - [GitLab](https://docs.gitlab.com/ee/user/markdown.html#diagrams-and-flowcharts) ✅ - [Mermaid Plugin for JetBrains IDEs](https://plugins.jetbrains.com/plugin/20146-mermaid) +- [MonsterWriter](https://www.monsterwriter.com/) ✅ - [Joplin](https://joplinapp.org) ✅ - [LiveBook](https://livebook.dev) ✅ - [Tuleap](https://docs.tuleap.org/user-guide/writing-in-tuleap.html#graphs) ✅ @@ -201,6 +204,7 @@ Communication tools and platforms - [gatsby-remark-mermaid](https://github.com/remcohaszing/gatsby-remark-mermaid) - [JSDoc](https://jsdoc.app/) - [jsdoc-mermaid](https://github.com/Jellyvision/jsdoc-mermaid) +- [Madness](https://madness.dannyb.co/) - [mdBook](https://rust-lang.github.io/mdBook/index.html) - [mdbook-mermaid](https://github.com/badboy/mdbook-mermaid) - [MkDocs](https://www.mkdocs.org) @@ -235,6 +239,8 @@ Communication tools and platforms ### Other +- [Astro](https://astro.build/) + - [Adding diagrams to your Astro site with MermaidJS and Playwright](https://agramont.net/blog/diagraming-with-mermaidjs-astro/) - [Bisheng](https://www.npmjs.com/package/bisheng) - [bisheng-plugin-mermaid](https://github.com/yct21/bisheng-plugin-mermaid) - [Blazorade Mermaid: Render Mermaid diagrams in Blazor applications](https://github.com/Blazorade/Blazorade-Mermaid/wiki) @@ -244,6 +250,7 @@ Communication tools and platforms - [Jekyll](https://jekyllrb.com/) - [jekyll-mermaid](https://rubygems.org/gems/jekyll-mermaid) - [jekyll-mermaid-diagrams](https://github.com/fuzhibo/jekyll-mermaid-diagrams) +- [MarkChart: Preview Mermaid diagrams on macOS](https://markchart.app/) - [mermaid-isomorphic](https://github.com/remcohaszing/mermaid-isomorphic) - [mermaid-server: Generate diagrams using a HTTP request](https://github.com/TomWright/mermaid-server) - [NiceGUI: Let any browser be the frontend of your Python code](https://nicegui.io) ✅ diff --git a/packages/mermaid/src/docs/ecosystem/mermaid-chart.md b/packages/mermaid/src/docs/ecosystem/mermaid-chart.md index 94b6773e4b..732b9b68cd 100644 --- a/packages/mermaid/src/docs/ecosystem/mermaid-chart.md +++ b/packages/mermaid/src/docs/ecosystem/mermaid-chart.md @@ -1,5 +1,9 @@ # Mermaid Chart +The Future of Diagramming & Visual Collaboration + +Try the Ultimate AI, Mermaid, and Visual Diagramming Suite by creating an account at [Mermaid Chart](https://www.mermaidchart.com/app/sign-up). +
Mermaid Chart - A smarter way to create diagrams | Product Hunt @@ -12,22 +16,26 @@ - **Editor** - A web based editor for creating and editing Mermaid diagrams. -- **Presentation** - A presentation mode for viewing Mermaid diagrams in a slideshow format. +- **Visual Editor** - The Visual Editor enables users of all skill levels to create diagrams easily and efficiently, with both GUI and code-based editing options. -- **Collaboration** - A web based collaboration feature for multi-user editing on Mermaid diagrams in real-time (Pro plan). +- **AI Chat** - Use our embedded AI Chat to generate diagrams from natural language descriptions. - **Plugins** - A plugin system for extending the functionality of Mermaid. - Plugins are available for: + Official Mermaid Chart plugins: - - [ChatGPT](https://docs.mermaidchart.com/plugins/chatgpt) + - [Mermaid Chart GPT](https://chat.openai.com/g/g-1IRFKwq4G-mermaid-chart) + - [Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=MermaidChart.vscode-mermaid-chart) - [JetBrains IDE](https://plugins.jetbrains.com/plugin/23043-mermaid-chart) - [Microsoft PowerPoint and Word](https://appsource.microsoft.com/en-us/product/office/WA200006214?tab=Overview) - - [Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=MermaidChart.vscode-mermaid-chart) -- **AI diagramming** - A feature for generating Mermaid diagrams from text using AI (Pro plan). + Visit our [Plugins](https://www.mermaidchart.com/plugins) page for more information. -- **More** - To learn more, visit our [Product](https://www.mermaidchart.com/product) page. +- **Collaboration** - A web based collaboration feature for multi-user editing on Mermaid diagrams in real-time (Pro and Enterprise plans). + +- **Comments** - Enhance collaboration by adding comments to diagrams. + +- **Presentations** - A presentation mode for viewing Mermaid diagrams in a slideshow format. ## Plans @@ -37,11 +45,9 @@ - **Enterprise** - A paid plan for enterprise use that includes all Pro features, and more. -## Access - -Sign up for a free account at [Mermaid Chart](https://www.mermaidchart.com/app/sign-up). +To learn more, visit our [Pricing](https://mermaidchart.com/pricing) page. -Mermaid Chart is currently offering a 14-day free trial of our newly-launched Pro tier. To learn more, visit our [Pricing](https://mermaidchart.com/pricing) page. +Mermaid Chart is currently offering a 14-day free trial on our Pro and Enterprise tiers. Sign up for a free account at [Mermaid Chart](https://www.mermaidchart.com/app/sign-up). ## Mermaid JS contributions diff --git a/packages/mermaid/src/docs/intro/getting-started.md b/packages/mermaid/src/docs/intro/getting-started.md index 2bfa36bb74..574881c4fd 100644 --- a/packages/mermaid/src/docs/intro/getting-started.md +++ b/packages/mermaid/src/docs/intro/getting-started.md @@ -146,7 +146,7 @@ For a list of Mermaid Plugins and Integrations, visit the [Integrations page](.. Mermaid Chart plugins are available for: -- [ChatGPT](https://docs.mermaidchart.com/plugins/chatgpt) +- [ChatGPT](https://docs.mermaidchart.com/plugins/mermaid-chart-gpt) - [JetBrains IDE](https://docs.mermaidchart.com/plugins/jetbrains-ide) - [Microsoft PowerPoint](https://docs.mermaidchart.com/plugins/microsoft-powerpoint) - [Microsoft Word](https://docs.mermaidchart.com/plugins/microsoft-word) diff --git a/packages/mermaid/src/docs/news/announcements.md b/packages/mermaid/src/docs/news/announcements.md index 7191fa6174..6323c0f7d9 100644 --- a/packages/mermaid/src/docs/news/announcements.md +++ b/packages/mermaid/src/docs/news/announcements.md @@ -26,13 +26,23 @@ Thank you for being part of our story. Here's to creating, innovating, and colla Knut Sveidqvist 🧜‍♂️✨ -## Mermaid Chart's Visual Editor for Flowcharts +## Mermaid Chart's Visual Editor for Flowcharts and Sequence diagrams -The Mermaid Chart team is excited to introduce a new Visual Editor for flowcharts, enabling users of all skill levels to create diagrams easily and efficiently, with both GUI and code-based editing options. +The Mermaid Chart team is excited to introduce a new Visual Editor for Flowcharts and Sequence diagrams, enabling users of all skill levels to create diagrams easily and efficiently, with both GUI and code-based editing options. -Create flowchart nodes, connect them with edges, update shapes, change colors, and edit labels with just a few clicks that automatically reflect in your diagram’s code for easy customizability. +Learn more: -Read more about it in our latest [BLOG POST](https://www.mermaidchart.com/blog/posts/mermaid-chart-releases-new-visual-editor-for-flowcharts) and watch a [DEMO VIDEO](https://www.youtube.com/watch?v=5aja0gijoO0) on our YouTube page. +- Visual Editor For Flowcharts + + - [Blog post](https://www.mermaidchart.com/blog/posts/mermaid-chart-releases-new-visual-editor-for-flowcharts) + + - [Demo video](https://www.youtube.com/watch?v=5aja0gijoO0) + +- Visual Editor For Sequence diagrams + + - [Blog post](https://www.mermaidchart.com/blog/posts/mermaid-chart-unveils-visual-editor-for-sequence-diagrams) + + - [Demo video](https://youtu.be/imc2u5_N6Dc) ## 📖 Blog posts diff --git a/packages/mermaid/src/docs/news/blog.md b/packages/mermaid/src/docs/news/blog.md index 13d3312997..4ada1e05cd 100644 --- a/packages/mermaid/src/docs/news/blog.md +++ b/packages/mermaid/src/docs/news/blog.md @@ -1,5 +1,29 @@ # Blog +## [How to Choose the Right Documentation Software](https://www.mermaidchart.com/blog/posts/how-to-choose-the-right-documentation-software/) + +7 May 2024 · 5 mins + +How to Choose the Right Documentation Software. Reliable and efficient documentation software is crucial in the fast-paced world of software development. + +## [AI in software diagramming: What trends will define the future?](https://www.mermaidchart.com/blog/posts/ai-in-software-diagramming/) + +24 April 2024 · 5 mins + +Artificial intelligence (AI) tools are changing the way developers work. + +## [Mermaid Chart Unveils Visual Editor for Sequence Diagrams](https://www.mermaidchart.com/blog/posts/mermaid-chart-unveils-visual-editor-for-sequence-diagrams/) + +8 April 2024 · 5 mins + +Sequence diagrams are excellent tools for communication and documentation. + +## [Modeling system states: It starts with a Turing machine](https://www.mermaidchart.com/blog/posts/modeling-system-states/) + +27 March 2024 · 12 mins + +In computer science, there are a few fundamental papers that, without exaggeration, changed everything. + ## [Mermaid Chart Raises $7.5M to Reinvent Visual Collaboration for Enterprises](https://www.mermaidchart.com/blog/posts/mermaid-chart-raises-7.5m-to-reinvent-visual-collaoration-for-enterprises/) 20 March 2024 · 4 mins diff --git a/packages/mermaid/src/docs/package.json b/packages/mermaid/src/docs/package.json index 0834cf0f2d..146c4d2d88 100644 --- a/packages/mermaid/src/docs/package.json +++ b/packages/mermaid/src/docs/package.json @@ -24,17 +24,17 @@ }, "devDependencies": { "@iconify-json/carbon": "^1.1.31", - "@unocss/reset": "^0.58.6", + "@unocss/reset": "^0.59.0", "@vite-pwa/vitepress": "^0.4.0", "@vitejs/plugin-vue": "^5.0.0", "fast-glob": "^3.3.2", "https-localhost": "^4.7.1", "pathe": "^1.1.2", - "unocss": "^0.58.6", + "unocss": "^0.59.0", "unplugin-vue-components": "^0.26.0", "vite": "^5.0.0", "vite-plugin-pwa": "^0.19.7", - "vitepress": "1.0.0-rc.45", + "vitepress": "1.1.4", "workbox-window": "^7.0.0" } } diff --git a/packages/mermaid/src/docs/syntax/entityRelationshipDiagram.md b/packages/mermaid/src/docs/syntax/entityRelationshipDiagram.md index ca7cb79c35..3b874f6893 100644 --- a/packages/mermaid/src/docs/syntax/entityRelationshipDiagram.md +++ b/packages/mermaid/src/docs/syntax/entityRelationshipDiagram.md @@ -100,7 +100,7 @@ Cardinality is a property that describes how many elements of another entity can | 1+ | 1+ | One or more | | zero or more | zero or more | Zero or more | | zero or many | zero or many | Zero or more | -| many(0) | many(1) | Zero or more | +| many(0) | many(0) | Zero or more | | 0+ | 0+ | Zero or more | | only one | only one | Exactly one | | 1 | 1 | Exactly one | diff --git a/packages/mermaid/src/docs/syntax/flowchart.md b/packages/mermaid/src/docs/syntax/flowchart.md index 462a9aecc9..acffbc6931 100644 --- a/packages/mermaid/src/docs/syntax/flowchart.md +++ b/packages/mermaid/src/docs/syntax/flowchart.md @@ -567,7 +567,7 @@ Examples of tooltip usage below: ```html @@ -588,7 +588,7 @@ flowchart LR > **Success** The tooltip functionality and the ability to link to urls are available from version 0.5.2. -?> Due to limitations with how Docsify handles JavaScript callback functions, an alternate working demo for the above code can be viewed at [this jsfiddle](https://jsfiddle.net/Ogglas/2o73vdez/7). +?> Due to limitations with how Docsify handles JavaScript callback functions, an alternate working demo for the above code can be viewed at [this jsfiddle](https://jsfiddle.net/yk4h7qou/2/). Links are opened in the same browser tab/window by default. It is possible to change this by adding a link target to the click definition (`_self`, `_blank`, `_parent` and `_top` are supported): @@ -620,7 +620,7 @@ Beginner's tip—a full example using interactive links in a html context: