diff --git a/.build/common.ts b/.build/common.ts
new file mode 100644
index 000000000..274977fa2
--- /dev/null
+++ b/.build/common.ts
@@ -0,0 +1,30 @@
+/**
+ * Shared common options for both ESBuild and Vite
+ */
+export const packageOptions = {
+ parser: {
+ name: 'mermaid-parser',
+ packageName: 'parser',
+ file: 'index.ts',
+ },
+ mermaid: {
+ name: 'mermaid',
+ packageName: 'mermaid',
+ file: 'mermaid.ts',
+ },
+ 'mermaid-example-diagram': {
+ name: 'mermaid-example-diagram',
+ packageName: 'mermaid-example-diagram',
+ file: 'detector.ts',
+ },
+ 'mermaid-zenuml': {
+ name: 'mermaid-zenuml',
+ packageName: 'mermaid-zenuml',
+ file: 'detector.ts',
+ },
+ 'mermaid-flowchart-elk': {
+ name: 'mermaid-flowchart-elk',
+ packageName: 'mermaid-flowchart-elk',
+ file: 'detector.ts',
+ },
+} as const;
diff --git a/.build/generateLangium.ts b/.build/generateLangium.ts
new file mode 100644
index 000000000..e37e085a5
--- /dev/null
+++ b/.build/generateLangium.ts
@@ -0,0 +1,5 @@
+import { generate } from 'langium-cli';
+
+export async function generateLangium() {
+ await generate({ file: `./packages/parser/langium-config.json` });
+}
diff --git a/.vite/jisonTransformer.ts b/.build/jisonTransformer.ts
similarity index 100%
rename from .vite/jisonTransformer.ts
rename to .build/jisonTransformer.ts
diff --git a/.build/jsonSchema.ts b/.build/jsonSchema.ts
new file mode 100644
index 000000000..6fd8ca3f5
--- /dev/null
+++ b/.build/jsonSchema.ts
@@ -0,0 +1,124 @@
+import { load, JSON_SCHEMA } from 'js-yaml';
+import assert from 'node:assert';
+import Ajv2019, { type JSONSchemaType } from 'ajv/dist/2019.js';
+import type { MermaidConfig, BaseDiagramConfig } from '../packages/mermaid/src/config.type.js';
+
+/**
+ * All of the keys in the mermaid config that have a mermaid diagram config.
+ */
+const MERMAID_CONFIG_DIAGRAM_KEYS = [
+ 'flowchart',
+ 'sequence',
+ 'gantt',
+ 'journey',
+ 'class',
+ 'state',
+ 'er',
+ 'pie',
+ 'quadrantChart',
+ 'xyChart',
+ 'requirement',
+ 'mindmap',
+ 'timeline',
+ 'gitGraph',
+ 'c4',
+ 'sankey',
+ 'block',
+ 'packet',
+] as const;
+
+/**
+ * Generate default values from the JSON Schema.
+ *
+ * AJV does not support nested default values yet (or default values with $ref),
+ * so we need to manually find them (this may be fixed in ajv v9).
+ *
+ * @param mermaidConfigSchema - The Mermaid JSON Schema to use.
+ * @returns The default mermaid config object.
+ */
+function generateDefaults(mermaidConfigSchema: JSONSchemaType) {
+ const ajv = new Ajv2019({
+ useDefaults: true,
+ allowUnionTypes: true,
+ strict: true,
+ });
+
+ ajv.addKeyword({
+ keyword: 'meta:enum', // used by jsonschema2md
+ errors: false,
+ });
+ ajv.addKeyword({
+ keyword: 'tsType', // used by json-schema-to-typescript
+ errors: false,
+ });
+
+ // ajv currently doesn't support nested default values, see https://github.com/ajv-validator/ajv/issues/1718
+ // (may be fixed in v9) so we need to manually use sub-schemas
+ const mermaidDefaultConfig = {};
+
+ assert.ok(mermaidConfigSchema.$defs);
+ const baseDiagramConfig = mermaidConfigSchema.$defs.BaseDiagramConfig;
+
+ for (const key of MERMAID_CONFIG_DIAGRAM_KEYS) {
+ const subSchemaRef = mermaidConfigSchema.properties[key].$ref;
+ const [root, defs, defName] = subSchemaRef.split('/');
+ assert.strictEqual(root, '#');
+ assert.strictEqual(defs, '$defs');
+ const subSchema = {
+ $schema: mermaidConfigSchema.$schema,
+ $defs: mermaidConfigSchema.$defs,
+ ...mermaidConfigSchema.$defs[defName],
+ } as JSONSchemaType;
+
+ const validate = ajv.compile(subSchema);
+
+ mermaidDefaultConfig[key] = {};
+
+ for (const required of subSchema.required ?? []) {
+ if (subSchema.properties[required] === undefined && baseDiagramConfig.properties[required]) {
+ mermaidDefaultConfig[key][required] = baseDiagramConfig.properties[required].default;
+ }
+ }
+ if (!validate(mermaidDefaultConfig[key])) {
+ throw new Error(
+ `schema for subconfig ${key} does not have valid defaults! Errors were ${JSON.stringify(
+ validate.errors,
+ undefined,
+ 2
+ )}`
+ );
+ }
+ }
+
+ const validate = ajv.compile(mermaidConfigSchema);
+
+ if (!validate(mermaidDefaultConfig)) {
+ throw new Error(
+ `Mermaid config JSON Schema does not have valid defaults! Errors were ${JSON.stringify(
+ validate.errors,
+ undefined,
+ 2
+ )}`
+ );
+ }
+
+ return mermaidDefaultConfig;
+}
+
+export const loadSchema = (src: string, filename: string): JSONSchemaType => {
+ const jsonSchema = load(src, {
+ filename,
+ // only allow JSON types in our YAML doc (will probably be default in YAML 1.3)
+ // e.g. `true` will be parsed a boolean `true`, `True` will be parsed as string `"True"`.
+ schema: JSON_SCHEMA,
+ }) as JSONSchemaType;
+ return jsonSchema;
+};
+
+export const getDefaults = (schema: JSONSchemaType) => {
+ return `export default ${JSON.stringify(generateDefaults(schema), undefined, 2)};`;
+};
+
+export const getSchema = (schema: JSONSchemaType) => {
+ return `export default ${JSON.stringify(schema, undefined, 2)};`;
+};
diff --git a/.build/types.ts b/.build/types.ts
new file mode 100644
index 000000000..419240782
--- /dev/null
+++ b/.build/types.ts
@@ -0,0 +1,18 @@
+import { packageOptions } from './common.js';
+import { execSync } from 'child_process';
+
+const buildType = (packageName: string) => {
+ console.log(`Building types for ${packageName}`);
+ try {
+ const out = execSync(`tsc -p ./packages/${packageName}/tsconfig.json --emitDeclarationOnly`);
+ out.length > 0 && console.log(out.toString());
+ } catch (e) {
+ console.error(e);
+ e.stdout.length > 0 && console.error(e.stdout.toString());
+ e.stderr.length > 0 && console.error(e.stderr.toString());
+ }
+};
+
+for (const { packageName } of Object.values(packageOptions)) {
+ buildType(packageName);
+}
diff --git a/.cspell/code-terms.txt b/.cspell/code-terms.txt
new file mode 100644
index 000000000..fa063616a
--- /dev/null
+++ b/.cspell/code-terms.txt
@@ -0,0 +1,140 @@
+# This file contains coding related terms
+ALPHANUM
+antiscript
+APPLYCLASS
+ARROWHEADSTYLE
+ARROWTYPE
+autonumber
+axisl-line
+Bigdecimal
+birel
+BIREL
+bqstring
+BQUOTE
+bramp
+BRKT
+callbackargs
+callbackname
+classdef
+classdefid
+classentity
+classname
+COLONSEP
+COMPOSIT_STATE
+concat
+controlx
+controly
+CSSCLASS
+CYLINDEREND
+CYLINDERSTART
+datakey
+DEND
+descr
+distp
+distq
+divs
+docref
+DOMID
+doublecircle
+DOUBLECIRCLEEND
+DOUBLECIRCLESTART
+DQUOTE
+DSTART
+edgesep
+EMPTYSTR
+enddate
+ERDIAGRAM
+flatmap
+forwardable
+frontmatter
+funs
+gantt
+GENERICTYPE
+getBoundarys
+grammr
+graphtype
+iife
+interp
+introdcued
+INVTRAPEND
+INVTRAPSTART
+JDBC
+jison
+Kaufmann
+keyify
+LABELPOS
+LABELTYPE
+lcov
+LEFTOF
+Lexa
+linebreak
+LINETYPE
+LINKSTYLE
+LLABEL
+loglevel
+LOGMSG
+lookaheads
+mdast
+metafile
+minlen
+Mstartx
+MULT
+NODIR
+NSTR
+outdir
+Qcontrolx
+reinit
+rels
+reqs
+rewritelinks
+rgba
+RIGHTOF
+sankey
+sequencenumber
+shrc
+signaltype
+someclass
+SPACELINE
+SPACELIST
+STADIUMEND
+STADIUMSTART
+startdate
+startx
+starty
+STMNT
+stopx
+stopy
+strikethrough
+stringifying
+struct
+STYLECLASS
+STYLEOPTS
+subcomponent
+subcomponents
+SUBROUTINEEND
+SUBROUTINESTART
+Subschemas
+substr
+TAGEND
+TAGSTART
+techn
+TESTSTR
+TEXTDATA
+TEXTLENGTH
+titlevalue
+topbar
+TRAPEND
+TRAPSTART
+ts-nocheck
+tsdoc
+typeof
+typestr
+unshift
+verifymethod
+VERIFYMTHD
+WARN_DOCSDIR_DOESNT_MATCH
+xhost
+yaxis
+yfunc
+yytext
+zenuml
diff --git a/.cspell/contributors.txt b/.cspell/contributors.txt
new file mode 100644
index 000000000..bd3ad9da2
--- /dev/null
+++ b/.cspell/contributors.txt
@@ -0,0 +1,8 @@
+# Contributors to mermaidjs, one per line
+Ashish Jain
+cpettitt
+Dong Cai
+Nikolay Rozhkov
+Peng Xiao
+subhash-halder
+Vinod Sidharth
diff --git a/.cspell/cspell.config.yaml b/.cspell/cspell.config.yaml
new file mode 100644
index 000000000..33d690193
--- /dev/null
+++ b/.cspell/cspell.config.yaml
@@ -0,0 +1,52 @@
+# yaml-language-server: $schema=https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json
+
+$schema: https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json
+
+dictionaryDefinitions:
+ - name: code-terms
+ path: ./code-terms.txt
+ description: A list of coding related terms.
+ addWords: true
+ - name: mermaid-terms
+ path: ./mermaid-terms.txt
+ description: A list of terms related to the mermaid project.
+ addWords: true
+ - name: misc-terms
+ path: ./misc-terms.txt
+ description: A list of miscellaneous terms.
+ - name: 3rd-party-terms
+ path: ./libraries.txt
+ description: A list of 3rd party terms from dependencies.
+ addWords: true
+ - name: contributors
+ path: ./contributors.txt
+ description: A list of contributors to the mermaid project.
+ type: 'W'
+ addWords: true
+
+ # cspell:disable
+ - name: suggestions
+ words:
+ - none
+ suggestWords:
+ - seperator:separator
+ - vertice:vertex
+ # cspell:enable
+
+patterns:
+ - name: character-set-cyrillic
+ pattern: '/\p{Script_Extensions=Cyrillic}+/gu'
+ - name: svg-block
+ pattern: ''
+ - name: json-property
+ pattern: '/"[\w/@-]+":/g'
+
+dictionaries:
+ - mermaid-terms
+ - suggestions
+ - contributors
+
+ignorePaths:
+ - '*.txt' # do not spell check local dictionaries
+
+# cspell:dictionary misc-terms
diff --git a/.cspell/libraries.txt b/.cspell/libraries.txt
new file mode 100644
index 000000000..9d2926186
--- /dev/null
+++ b/.cspell/libraries.txt
@@ -0,0 +1,71 @@
+# Add third party library terms below
+acyclicer
+Antlr
+Appli
+applitools
+Asciidoctor
+Astah
+automerge
+bilkent
+bisheng
+Blazor
+codedoc
+Codemia
+codepaths
+csstree
+cytoscape
+cytoscape-cose-bilkent
+dagre
+dagre-d3
+Deepdwn
+Docsify
+Docsy
+DokuWiki
+dompurify
+elkjs
+fontawesome
+Foswiki
+Gitea
+graphlib
+Grav
+iconify
+Inkdrop
+jiti
+jsdocs
+jsfiddle
+jsonschema
+katex
+khroma
+langium
+mathml
+matplotlib
+mdbook
+Mermerd
+mkdocs
+Nextra
+nodenext
+npmjs
+pageview
+pathe
+phpbb
+pixelmatch
+Podlite
+presetAttributify
+pyplot
+redmine
+rehype
+rscratch
+sparkline
+sphinxcontrib
+ssim
+stylis
+Swimm
+tsbuildinfo
+Tuleap
+Typora
+unocss
+unplugin
+unstub
+vite
+vitest
+Zune
diff --git a/.cspell/mermaid-terms.txt b/.cspell/mermaid-terms.txt
new file mode 100644
index 000000000..3fa5eff26
--- /dev/null
+++ b/.cspell/mermaid-terms.txt
@@ -0,0 +1,39 @@
+Adamiecki
+arrowend
+bmatrix
+braintree
+catmull
+compositTitleSize
+doublecircle
+elems
+gantt
+gitgraph
+gzipped
+knsv
+Knut
+marginx
+marginy
+Markdownish
+mermaidjs
+mindmap
+mindmaps
+multigraph
+nodesep
+NOTEGROUP
+Pinterest
+rankdir
+ranksep
+rect
+rects
+sandboxed
+siebling
+statediagram
+substate
+Sveidqvist
+unfixable
+Viewbox
+viewports
+visio
+vitepress
+xlink
+xychart
diff --git a/.cspell/misc-terms.txt b/.cspell/misc-terms.txt
new file mode 100644
index 000000000..467e48891
--- /dev/null
+++ b/.cspell/misc-terms.txt
@@ -0,0 +1 @@
+newbranch
diff --git a/.esbuild/build.ts b/.esbuild/build.ts
new file mode 100644
index 000000000..3c87f9d62
--- /dev/null
+++ b/.esbuild/build.ts
@@ -0,0 +1,65 @@
+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';
+
+const shouldVisualize = process.argv.includes('--visualize');
+
+const buildPackage = async (entryName: keyof typeof packageOptions) => {
+ const commonOptions = { ...defaultOptions, entryName } as const;
+ const buildConfigs = [
+ // package.mjs
+ { ...commonOptions },
+ // package.min.mjs
+ {
+ ...commonOptions,
+ minify: true,
+ metafile: shouldVisualize,
+ },
+ // package.core.mjs
+ { ...commonOptions, core: true },
+ ];
+
+ if (entryName === 'mermaid') {
+ const iifeOptions: MermaidBuildOptions = { ...commonOptions, format: 'iife' };
+ buildConfigs.push(
+ // mermaid.js
+ { ...iifeOptions },
+ // mermaid.min.js
+ { ...iifeOptions, minify: true, metafile: shouldVisualize }
+ );
+ }
+
+ const results = await Promise.all(buildConfigs.map((option) => build(getBuildConfig(option))));
+
+ if (shouldVisualize) {
+ for (const { metafile } of results) {
+ if (!metafile) {
+ continue;
+ }
+ const fileName = Object.keys(metafile.outputs)
+ .filter((file) => !file.includes('chunks') && file.endsWith('js'))[0]
+ .replace('dist/', '');
+ // Upload metafile into https://esbuild.github.io/analyze/
+ await writeFile(`stats/${fileName}.meta.json`, JSON.stringify(metafile));
+ }
+ }
+};
+
+const handler = (e) => {
+ console.error(e);
+ process.exit(1);
+};
+
+const main = async () => {
+ await generateLangium();
+ await mkdir('stats').catch(() => {});
+ 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) {
+ await buildPackage(pkg).catch(handler);
+ }
+};
+
+void main();
diff --git a/.esbuild/jisonPlugin.ts b/.esbuild/jisonPlugin.ts
new file mode 100644
index 000000000..de801ea9f
--- /dev/null
+++ b/.esbuild/jisonPlugin.ts
@@ -0,0 +1,15 @@
+import { readFile } from 'node:fs/promises';
+import { transformJison } from '../.build/jisonTransformer.js';
+import { Plugin } from 'esbuild';
+
+export const jisonPlugin: Plugin = {
+ name: 'jison',
+ setup(build) {
+ build.onLoad({ filter: /\.jison$/ }, async (args) => {
+ // Load the file from the file system
+ const source = await readFile(args.path, 'utf8');
+ const contents = transformJison(source);
+ return { contents, warnings: [] };
+ });
+ },
+};
diff --git a/.esbuild/jsonSchemaPlugin.ts b/.esbuild/jsonSchemaPlugin.ts
new file mode 100644
index 000000000..e90c185ab
--- /dev/null
+++ b/.esbuild/jsonSchemaPlugin.ts
@@ -0,0 +1,35 @@
+import type { JSONSchemaType } from 'ajv/dist/2019.js';
+import type { MermaidConfig } from '../packages/mermaid/src/config.type.js';
+import { readFile } from 'node:fs/promises';
+import { getDefaults, getSchema, loadSchema } from '../.build/jsonSchema.js';
+
+/**
+ * ESBuild plugin that handles JSON Schemas saved as a `.schema.yaml` file.
+ *
+ * Use `my-example.schema.yaml?only-defaults=true` to only load the default values.
+ */
+
+export const jsonSchemaPlugin = {
+ name: 'json-schema-plugin',
+ setup(build) {
+ let schema: JSONSchemaType | undefined = undefined;
+ let content = '';
+
+ build.onLoad({ filter: /config\.schema\.yaml$/ }, async (args) => {
+ // Load the file from the file system
+ const source = await readFile(args.path, 'utf8');
+ const resolvedSchema: JSONSchemaType =
+ content === source && schema ? schema : loadSchema(source, args.path);
+ if (content !== source) {
+ content = source;
+ schema = resolvedSchema;
+ }
+ const contents = args.suffix.includes('only-defaults')
+ ? getDefaults(resolvedSchema)
+ : getSchema(resolvedSchema);
+ return { contents, warnings: [] };
+ });
+ },
+};
+
+export default jsonSchemaPlugin;
diff --git a/.esbuild/server.ts b/.esbuild/server.ts
new file mode 100644
index 000000000..9102c7de8
--- /dev/null
+++ b/.esbuild/server.ts
@@ -0,0 +1,102 @@
+import express from 'express';
+import type { NextFunction, Request, Response } from 'express';
+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 { packageOptions } from '../.build/common.js';
+
+const configs = Object.values(packageOptions).map(({ packageName }) =>
+ getBuildConfig({ ...defaultOptions, minify: false, core: false, entryName: packageName })
+);
+const mermaidIIFEConfig = getBuildConfig({
+ ...defaultOptions,
+ minify: false,
+ core: false,
+ entryName: 'mermaid',
+ format: 'iife',
+});
+configs.push(mermaidIIFEConfig);
+
+const contexts = await Promise.all(configs.map((config) => context(config)));
+
+const rebuildAll = async () => {
+ console.time('Rebuild time');
+ await Promise.all(contexts.map((ctx) => ctx.rebuild())).catch((e) => console.error(e));
+ console.timeEnd('Rebuild time');
+};
+
+let clients: { id: number; response: Response }[] = [];
+function eventsHandler(request: Request, response: Response, next: NextFunction) {
+ const headers = {
+ 'Content-Type': 'text/event-stream',
+ Connection: 'keep-alive',
+ 'Cache-Control': 'no-cache',
+ };
+ response.writeHead(200, headers);
+ const clientId = Date.now();
+ clients.push({
+ id: clientId,
+ response,
+ });
+ request.on('close', () => {
+ clients = clients.filter((client) => client.id !== clientId);
+ });
+}
+
+let timeoutId: NodeJS.Timeout | undefined = undefined;
+
+/**
+ * Debounce file change events to avoid rebuilding multiple times.
+ */
+function handleFileChange() {
+ if (timeoutId !== undefined) {
+ clearTimeout(timeoutId);
+ }
+ timeoutId = setTimeout(async () => {
+ await rebuildAll();
+ sendEventsToAll();
+ timeoutId = undefined;
+ }, 100);
+}
+
+function sendEventsToAll() {
+ clients.forEach(({ response }) => response.write(`data: ${Date.now()}\n\n`));
+}
+
+async function createServer() {
+ await generateLangium();
+ handleFileChange();
+ const app = express();
+ chokidar
+ .watch('**/src/**/*.{js,ts,langium,yaml,json}', {
+ ignoreInitial: true,
+ ignored: [/node_modules/, /dist/, /docs/, /coverage/],
+ })
+ .on('all', async (event, path) => {
+ // Ignore other events.
+ if (!['add', 'change'].includes(event)) {
+ return;
+ }
+ if (/\.langium$/.test(path)) {
+ await generateLangium();
+ }
+ console.log(`${path} changed. Rebuilding...`);
+ handleFileChange();
+ });
+
+ app.use(cors());
+ app.get('/events', eventsHandler);
+ for (const { packageName } of Object.values(packageOptions)) {
+ app.use(express.static(`./packages/${packageName}/dist`));
+ }
+ app.use(express.static('demos'));
+ app.use(express.static('cypress/platform'));
+
+ app.listen(9000, () => {
+ console.log(`Listening on http://localhost:9000`);
+ });
+}
+
+createServer();
diff --git a/.esbuild/util.ts b/.esbuild/util.ts
new file mode 100644
index 000000000..5c21cbf45
--- /dev/null
+++ b/.esbuild/util.ts
@@ -0,0 +1,101 @@
+import { resolve } from 'path';
+import { fileURLToPath } from 'url';
+import type { BuildOptions } from 'esbuild';
+import { readFileSync } from 'fs';
+import jsonSchemaPlugin from './jsonSchemaPlugin.js';
+import { packageOptions } from '../.build/common.js';
+import { jisonPlugin } from './jisonPlugin.js';
+
+const __dirname = fileURLToPath(new URL('.', import.meta.url));
+
+export interface MermaidBuildOptions {
+ minify: boolean;
+ core: boolean;
+ metafile: boolean;
+ format: 'esm' | 'iife';
+ entryName: keyof typeof packageOptions;
+}
+
+export const defaultOptions: Omit = {
+ minify: false,
+ metafile: false,
+ core: false,
+ format: 'esm',
+} as const;
+
+const buildOptions = (override: BuildOptions): BuildOptions => {
+ return {
+ bundle: true,
+ minify: true,
+ keepNames: true,
+ platform: 'browser',
+ tsconfig: 'tsconfig.json',
+ resolveExtensions: ['.ts', '.js', '.json', '.jison', '.yaml'],
+ external: ['require', 'fs', 'path'],
+ outdir: 'dist',
+ plugins: [jisonPlugin, jsonSchemaPlugin],
+ sourcemap: 'external',
+ ...override,
+ };
+};
+
+const getFileName = (fileName: string, { core, format, minify }: MermaidBuildOptions) => {
+ if (core) {
+ fileName += '.core';
+ } else if (format === 'esm') {
+ fileName += '.esm';
+ }
+ if (minify) {
+ fileName += '.min';
+ }
+ return fileName;
+};
+
+export const getBuildConfig = (options: MermaidBuildOptions): BuildOptions => {
+ const { core, entryName, metafile, format, minify } = options;
+ const external: string[] = ['require', 'fs', 'path'];
+ const { name, file, packageName } = packageOptions[entryName];
+ const outFileName = getFileName(name, options);
+ let output: BuildOptions = buildOptions({
+ absWorkingDir: resolve(__dirname, `../packages/${packageName}`),
+ entryPoints: {
+ [outFileName]: `src/${file}`,
+ },
+ metafile,
+ minify,
+ logLevel: 'info',
+ chunkNames: `chunks/${outFileName}/[name]-[hash]`,
+ define: {
+ 'import.meta.vitest': 'undefined',
+ },
+ });
+
+ if (core) {
+ const { dependencies } = JSON.parse(
+ readFileSync(resolve(__dirname, `../packages/${packageName}/package.json`), 'utf-8')
+ );
+ // Core build is used to generate file without bundled dependencies.
+ // This is used by downstream projects to bundle dependencies themselves.
+ // Ignore dependencies and any dependencies of dependencies
+ external.push(...Object.keys(dependencies));
+ output.external = external;
+ }
+
+ if (format === 'iife') {
+ output.format = 'iife';
+ output.splitting = false;
+ output.globalName = '__esbuild_esm_mermaid';
+ // Workaround for removing the .default access in esbuild IIFE.
+ // https://github.com/mermaid-js/mermaid/pull/4109#discussion_r1292317396
+ output.footer = {
+ js: 'globalThis.mermaid = globalThis.__esbuild_esm_mermaid.default;',
+ };
+ output.outExtension = { '.js': '.js' };
+ } else {
+ output.format = 'esm';
+ output.splitting = true;
+ output.outExtension = { '.js': '.mjs' };
+ }
+
+ return output;
+};
diff --git a/.eslintignore b/.eslintignore
index 1db5125d0..08b265ba0 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -6,3 +6,6 @@ cypress/plugins/index.js
coverage
*.json
node_modules
+
+# autogenereated by langium-cli
+generated/
diff --git a/.eslintrc.cjs b/.eslintrc.cjs
index 49e1aaaa6..ceff724bb 100644
--- a/.eslintrc.cjs
+++ b/.eslintrc.cjs
@@ -63,13 +63,24 @@ module.exports = {
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: false,
- checkStrings: false,
- checkStringTemplates: false,
+ checkIdentifiers: true,
+ checkStrings: true,
+ checkStringTemplates: true,
},
],
'no-empty': [
@@ -148,6 +159,19 @@ module.exports = {
'@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: {
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index fa15f39e1..6be6f3b5d 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -4,7 +4,7 @@ contact_links:
url: https://github.com/mermaid-js/mermaid/discussions
about: Ask the Community questions or share your own graphs in our discussions.
- name: Discord
- url: https://discord.gg/wwtabKgp8y
+ url: https://discord.gg/AgrbSrBer3
about: Join our Community on Discord for Help and a casual chat.
- name: Documentation
url: https://mermaid.js.org
diff --git a/.github/codecov.yaml b/.github/codecov.yaml
index 950edb6a9..945043085 100644
--- a/.github/codecov.yaml
+++ b/.github/codecov.yaml
@@ -15,3 +15,4 @@ coverage:
# Turing off for now as code coverage isn't stable and causes unnecessary build failures.
# default:
# threshold: 2%
+ patch: off
diff --git a/.github/lychee.toml b/.github/lychee.toml
index 4af304a99..c5a2f0e45 100644
--- a/.github/lychee.toml
+++ b/.github/lychee.toml
@@ -35,7 +35,13 @@ exclude = [
'packages/mermaid/src/docs/config/setup/*',
# Ignore Discord invite
-"https://discord.gg"
+"https://discord.gg",
+
+# BundlePhobia has frequent downtime
+"https://bundlephobia.com",
+
+# Chrome webstore migration issue. Temporary
+"https://chromewebstore.google.com"
]
# Exclude all private IPs from checking.
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index f20204a71..cfd22a293 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -12,7 +12,7 @@ Describe the way your implementation works or what design decisions you made if
Make sure you
-- [ ] :book: have read the [contribution guidelines](https://github.com/mermaid-js/mermaid/blob/develop/CONTRIBUTING.md)
+- [ ] :book: have read the [contribution guidelines](https://mermaid.js.org/community/contributing.html)
- [ ] :computer: have added necessary unit/e2e tests.
-- [ ] :notebook: have added documentation. Make sure [`MERMAID_RELEASE_VERSION`](https://github.com/mermaid-js/mermaid/blob/develop/packages/mermaid/src/docs/community/contributing.md#update-documentation) is used for all new features.
+- [ ] :notebook: have added documentation. Make sure [`MERMAID_RELEASE_VERSION`](https://mermaid.js.org/community/contributing.html#update-documentation) is used for all new features.
- [ ] :bookmark: targeted `develop` branch
diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml
index acfb1887e..87607bc2f 100644
--- a/.github/workflows/build-docs.yml
+++ b/.github/workflows/build-docs.yml
@@ -24,7 +24,7 @@ jobs:
uses: actions/setup-node@v4
with:
cache: pnpm
- node-version: 18
+ node-version-file: '.node-version'
- name: Install Packages
run: pnpm install --frozen-lockfile
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 605dea9ab..e0ab76607 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -15,20 +15,17 @@ permissions:
jobs:
build-mermaid:
runs-on: ubuntu-latest
- strategy:
- matrix:
- node-version: [18.x]
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
# uses version from "packageManager" field in package.json
- - name: Setup Node.js ${{ matrix.node-version }}
+ - name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
- node-version: ${{ matrix.node-version }}
+ node-version-file: '.node-version'
- name: Install Packages
run: |
diff --git a/.github/workflows/e2e-applitools.yml b/.github/workflows/e2e-applitools.yml
index fd32e59ad..1238fe371 100644
--- a/.github/workflows/e2e-applitools.yml
+++ b/.github/workflows/e2e-applitools.yml
@@ -21,9 +21,9 @@ env:
jobs:
e2e-applitools:
runs-on: ubuntu-latest
- strategy:
- matrix:
- node-version: [18.x]
+ container:
+ image: cypress/browsers:node-20.11.0-chrome-121.0.6167.85-1-ff-120.0-edge-121.0.2277.83-1
+ options: --user 1001
steps:
- if: ${{ ! env.USE_APPLI }}
name: Warn if not using Applitools
@@ -35,10 +35,10 @@ jobs:
- uses: pnpm/action-setup@v2
# uses version from "packageManager" field in package.json
- - name: Setup Node.js ${{ matrix.node-version }}
+ - name: Setup Node.js
uses: actions/setup-node@v4
with:
- node-version: ${{ matrix.node-version }}
+ node-version-file: '.node-version'
- if: ${{ env.USE_APPLI }}
name: Notify applitools of new batch
diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml
index b8232b8c0..4d3152d53 100644
--- a/.github/workflows/e2e.yml
+++ b/.github/workflows/e2e.yml
@@ -17,19 +17,32 @@ permissions:
contents: read
env:
- # For PRs and MergeQueues, the target commit is used, and for push events, github.event.previous is used.
- targetHash: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha || (github.event.before == '0000000000000000000000000000000000000000' && 'develop' || github.event.before) }}
-
+ # For PRs and MergeQueues, the target commit is used, and for push events to non-develop branches, github.event.previous is used if available. Otherwise, 'develop' is used.
+ targetHash: >-
+ ${{
+ github.event.pull_request.base.sha ||
+ github.event.merge_group.base_sha ||
+ (
+ (
+ (github.event_name == 'push' && github.ref == 'refs/heads/develop') ||
+ github.event.before == '0000000000000000000000000000000000000000'
+ ) && 'develop'
+ ) ||
+ github.event.before
+ }}
jobs:
cache:
runs-on: ubuntu-latest
+ container:
+ image: cypress/browsers:node-20.11.0-chrome-121.0.6167.85-1-ff-120.0-edge-121.0.2277.83-1
+ options: --user 1001
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
- name: Setup Node.js
uses: actions/setup-node@v4
with:
- node-version: 18.x
+ node-version-file: '.node-version'
- name: Cache snapshots
id: cache-snapshot
uses: actions/cache@v4
@@ -45,22 +58,39 @@ jobs:
with:
ref: ${{ env.targetHash }}
+ - name: Install dependencies
+ if: ${{ steps.cache-snapshot.outputs.cache-hit != 'true' }}
+ uses: cypress-io/github-action@v6
+ with:
+ # just perform install
+ runTests: false
+
+ - name: Calculate bundle size
+ if: ${{ steps.cache-snapshot.outputs.cache-hit != 'true'}}
+ run: |
+ pnpm run build:viz
+ mkdir -p cypress/snapshots/stats/base
+ mv stats cypress/snapshots/stats/base
+
- name: Cypress run
- uses: cypress-io/github-action@v4
+ 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:
+ image: cypress/browsers:node-20.11.0-chrome-121.0.6167.85-1-ff-120.0-edge-121.0.2277.83-1
+ options: --user 1001
needs: cache
strategy:
fail-fast: false
matrix:
- node-version: [18.x]
containers: [1, 2, 3, 4]
steps:
- uses: actions/checkout@v4
@@ -68,10 +98,10 @@ jobs:
- uses: pnpm/action-setup@v2
# uses version from "packageManager" field in package.json
- - name: Setup Node.js ${{ matrix.node-version }}
+ - name: Setup Node.js
uses: actions/setup-node@v4
with:
- node-version: ${{ matrix.node-version }}
+ node-version-file: '.node-version'
# These cached snapshots are downloaded, providing the reference snapshots.
- name: Cache snapshots
@@ -81,15 +111,30 @@ jobs:
path: ./cypress/snapshots
key: ${{ runner.os }}-snapshots-${{ env.targetHash }}
+ - name: Install dependencies
+ uses: cypress-io/github-action@v6
+ with:
+ runTests: false
+
+ - name: Output size diff
+ if: ${{ matrix.containers == 1 }}
+ run: |
+ pnpm run build:viz
+ mv stats cypress/snapshots/stats/head
+ echo '## Bundle size difference' >> "$GITHUB_STEP_SUMMARY"
+ echo '' >> "$GITHUB_STEP_SUMMARY"
+ npx tsx scripts/size.ts >> "$GITHUB_STEP_SUMMARY"
+
# Install NPM dependencies, cache them correctly
# and run all Cypress tests
- name: Cypress run
- uses: cypress-io/github-action@v4
+ uses: cypress-io/github-action@v6
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 ) }}
with:
+ install: false
start: pnpm run dev:coverage
wait-on: 'http://localhost:9000'
browser: chrome
diff --git a/.github/workflows/link-checker.yml b/.github/workflows/link-checker.yml
index 3d4956945..59d25b7c5 100644
--- a/.github/workflows/link-checker.yml
+++ b/.github/workflows/link-checker.yml
@@ -36,7 +36,7 @@ jobs:
restore-keys: cache-lychee-
- name: Link Checker
- uses: lycheeverse/lychee-action@v1.9.1
+ uses: lycheeverse/lychee-action@v1.9.3
with:
args: >-
--config .github/lychee.toml
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index f0c5560a1..8f5995d71 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -16,20 +16,17 @@ permissions:
jobs:
lint:
runs-on: ubuntu-latest
- strategy:
- matrix:
- node-version: [18.x]
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
# uses version from "packageManager" field in package.json
- - name: Setup Node.js ${{ matrix.node-version }}
+ - name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
- node-version: ${{ matrix.node-version }}
+ node-version-file: '.node-version'
- name: Install Packages
run: |
diff --git a/.github/workflows/publish-docs.yml b/.github/workflows/publish-docs.yml
index 05cd68aff..6efd90c7f 100644
--- a/.github/workflows/publish-docs.yml
+++ b/.github/workflows/publish-docs.yml
@@ -31,7 +31,7 @@ jobs:
uses: actions/setup-node@v4
with:
cache: pnpm
- node-version: 18
+ node-version-file: '.node-version'
- name: Install Packages
run: pnpm install --frozen-lockfile
diff --git a/.github/workflows/release-draft.yml b/.github/workflows/release-draft.yml
index db1dd1f48..8e9c0da99 100644
--- a/.github/workflows/release-draft.yml
+++ b/.github/workflows/release-draft.yml
@@ -12,7 +12,7 @@ jobs:
draft-release:
runs-on: ubuntu-latest
permissions:
- contents: write # write permission is required to create a github release
+ contents: write # write permission is required to create a GitHub release
pull-requests: read # required to read PR titles/labels
steps:
- name: Draft Release
diff --git a/.github/workflows/release-preview-publish.yml b/.github/workflows/release-preview-publish.yml
index c6503847d..c763430b0 100644
--- a/.github/workflows/release-preview-publish.yml
+++ b/.github/workflows/release-preview-publish.yml
@@ -19,7 +19,7 @@ jobs:
uses: actions/setup-node@v4
with:
cache: pnpm
- node-version: 18.x
+ node-version-file: '.node-version'
- name: Install Packages
run: |
diff --git a/.github/workflows/release-publish.yml b/.github/workflows/release-publish.yml
index 69ef74940..dce461cf5 100644
--- a/.github/workflows/release-publish.yml
+++ b/.github/workflows/release-publish.yml
@@ -14,11 +14,11 @@ jobs:
- uses: pnpm/action-setup@v2
# uses version from "packageManager" field in package.json
- - name: Setup Node.js v18
+ - name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
- node-version: 18.x
+ node-version-file: '.node-version'
- name: Install Packages
run: |
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index a18b31c9c..7160ecc5f 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -8,20 +8,17 @@ permissions:
jobs:
unit-test:
runs-on: ubuntu-latest
- strategy:
- matrix:
- node-version: [18.x]
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
# uses version from "packageManager" field in package.json
- - name: Setup Node.js ${{ matrix.node-version }}
+ - name: Setup Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
- node-version: ${{ matrix.node-version }}
+ node-version-file: '.node-version'
- name: Install Packages
run: |
diff --git a/.gitignore b/.gitignore
index e6728b03f..a0fd1c50b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -46,4 +46,8 @@ stats/
demos/dev/**
!/demos/dev/example.html
+!/demos/dev/reload.js
tsx-0/**
+
+# autogenereated by langium-cli
+generated/
\ No newline at end of file
diff --git a/.lintstagedrc.mjs b/.lintstagedrc.mjs
index 231c91f8f..86af4f513 100644
--- a/.lintstagedrc.mjs
+++ b/.lintstagedrc.mjs
@@ -6,6 +6,6 @@ export default {
// https://prettier.io/docs/en/cli.html#--cache
'prettier --write',
],
- 'cSpell.json': ['tsx scripts/fixCSpell.ts'],
+ '.cspell/*.txt': ['tsx scripts/fixCSpell.ts'],
'**/*.jison': ['pnpm -w run lint:jison'],
};
diff --git a/.node-version b/.node-version
new file mode 100644
index 000000000..ee09fac75
--- /dev/null
+++ b/.node-version
@@ -0,0 +1 @@
+v20.11.1
diff --git a/.npmrc b/.npmrc
index e72930ead..91750f557 100644
--- a/.npmrc
+++ b/.npmrc
@@ -1,3 +1,4 @@
registry=https://registry.npmjs.org
auto-install-peers=true
strict-peer-dependencies=false
+package-import-method=clone-or-copy
diff --git a/.prettierignore b/.prettierignore
index fb9b694b7..7da0646e3 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -1,6 +1,7 @@
dist
cypress/platform/xss3.html
.cache
+.pnpm-store
coverage
# Autogenerated by PNPM
pnpm-lock.yaml
@@ -10,6 +11,8 @@ stats
.nyc_output
# Autogenerated by `pnpm run --filter mermaid types:build-config`
packages/mermaid/src/config.type.ts
+# autogenereated by langium-cli
+generated/
# Ignore the files creates in /demos/dev except for example.html
demos/dev/**
-!/demos/dev/example.html
\ No newline at end of file
+!/demos/dev/example.html
diff --git a/.vite/build.ts b/.vite/build.ts
index bacc6bc6c..7ce93a497 100644
--- a/.vite/build.ts
+++ b/.vite/build.ts
@@ -3,11 +3,12 @@ import { resolve } from 'path';
import { fileURLToPath } from 'url';
import jisonPlugin from './jisonPlugin.js';
import jsonSchemaPlugin from './jsonSchemaPlugin.js';
-import { readFileSync } from 'fs';
import typescript from '@rollup/plugin-typescript';
import { visualizer } from 'rollup-plugin-visualizer';
import type { TemplateType } from 'rollup-plugin-visualizer/dist/plugin/template-types.js';
import istanbul from 'vite-plugin-istanbul';
+import { packageOptions } from '../.build/common.js';
+import { generateLangium } from '../.build/generateLangium.js';
const visualize = process.argv.includes('--visualize');
const watch = process.argv.includes('--watch');
@@ -36,24 +37,6 @@ const visualizerOptions = (packageName: string, core = false): PluginOption[] =>
);
};
-const packageOptions = {
- mermaid: {
- name: 'mermaid',
- packageName: 'mermaid',
- file: 'mermaid.ts',
- },
- 'mermaid-example-diagram': {
- name: 'mermaid-example-diagram',
- packageName: 'mermaid-example-diagram',
- file: 'detector.ts',
- },
- 'mermaid-zenuml': {
- name: 'mermaid-zenuml',
- packageName: 'mermaid-zenuml',
- file: 'detector.ts',
- },
-};
-
interface BuildOptions {
minify: boolean | 'esbuild';
core?: boolean;
@@ -72,34 +55,8 @@ export const getBuildConfig = ({ minify, core, watch, entryName }: BuildOptions)
sourcemap,
entryFileNames: `${name}.esm${minify ? '.min' : ''}.mjs`,
},
- {
- name,
- format: 'umd',
- sourcemap,
- entryFileNames: `${name}${minify ? '.min' : ''}.js`,
- },
];
- if (core) {
- const { dependencies } = JSON.parse(
- readFileSync(resolve(__dirname, `../packages/${packageName}/package.json`), 'utf-8')
- );
- // Core build is used to generate file without bundled dependencies.
- // This is used by downstream projects to bundle dependencies themselves.
- // Ignore dependencies and any dependencies of dependencies
- // Adapted from the RegEx used by `rollup-plugin-node`
- external.push(new RegExp('^(?:' + Object.keys(dependencies).join('|') + ')(?:/.+)?$'));
- // This needs to be an array. Otherwise vite will build esm & umd with same name and overwrite esm with umd.
- output = [
- {
- name,
- format: 'esm',
- sourcemap,
- entryFileNames: `${name}.core.mjs`,
- },
- ];
- }
-
const config: InlineConfig = {
configFile: false,
build: {
@@ -129,7 +86,7 @@ export const getBuildConfig = ({ minify, core, watch, entryName }: BuildOptions)
// @ts-expect-error According to the type definitions, rollup plugins are incompatible with vite
typescript({ compilerOptions: { declaration: false } }),
istanbul({
- exclude: ['node_modules', 'test/', '__mocks__'],
+ exclude: ['node_modules', 'test/', '__mocks__', 'generated'],
extension: ['.js', '.ts'],
requireEnv: true,
forceBuildInstrument: coverage,
@@ -149,24 +106,28 @@ export const getBuildConfig = ({ minify, core, watch, entryName }: BuildOptions)
const buildPackage = async (entryName: keyof typeof packageOptions) => {
await build(getBuildConfig({ minify: false, entryName }));
- await build(getBuildConfig({ minify: 'esbuild', entryName }));
- await build(getBuildConfig({ minify: false, core: true, entryName }));
};
const main = async () => {
const packageNames = Object.keys(packageOptions) as (keyof typeof packageOptions)[];
- for (const pkg of packageNames.filter((pkg) => !mermaidOnly || pkg === 'mermaid')) {
+ for (const pkg of packageNames.filter(
+ (pkg) => !mermaidOnly || pkg === 'mermaid' || pkg === 'parser'
+ )) {
await buildPackage(pkg);
}
};
+await generateLangium();
+
if (watch) {
+ await build(getBuildConfig({ minify: false, watch, core: false, entryName: 'parser' }));
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' }));
}
} else if (visualize) {
+ await build(getBuildConfig({ minify: false, watch, core: false, entryName: 'parser' }));
await build(getBuildConfig({ minify: false, core: true, entryName: 'mermaid' }));
await build(getBuildConfig({ minify: false, core: false, entryName: 'mermaid' }));
} else {
diff --git a/.vite/jisonPlugin.ts b/.vite/jisonPlugin.ts
index c21190784..32e567797 100644
--- a/.vite/jisonPlugin.ts
+++ b/.vite/jisonPlugin.ts
@@ -1,10 +1,10 @@
-import { transformJison } from './jisonTransformer.js';
+import { transformJison } from '../.build/jisonTransformer.js';
+
const fileRegex = /\.(jison)$/;
export default function jison() {
return {
name: 'jison',
-
transform(src: string, id: string) {
if (fileRegex.test(id)) {
return {
diff --git a/.vite/jsonSchemaPlugin.ts b/.vite/jsonSchemaPlugin.ts
index ad3d9863d..2e5b5cc0b 100644
--- a/.vite/jsonSchemaPlugin.ts
+++ b/.vite/jsonSchemaPlugin.ts
@@ -1,109 +1,5 @@
-import { load, JSON_SCHEMA } from 'js-yaml';
-import assert from 'node:assert';
-import Ajv2019, { type JSONSchemaType } from 'ajv/dist/2019.js';
import { PluginOption } from 'vite';
-
-import type { MermaidConfig, BaseDiagramConfig } from '../packages/mermaid/src/config.type.js';
-
-/**
- * All of the keys in the mermaid config that have a mermaid diagram config.
- */
-const MERMAID_CONFIG_DIAGRAM_KEYS = [
- 'flowchart',
- 'sequence',
- 'gantt',
- 'journey',
- 'class',
- 'state',
- 'er',
- 'pie',
- 'quadrantChart',
- 'xyChart',
- 'requirement',
- 'mindmap',
- 'timeline',
- 'gitGraph',
- 'c4',
- 'sankey',
-] as const;
-
-/**
- * Generate default values from the JSON Schema.
- *
- * AJV does not support nested default values yet (or default values with $ref),
- * so we need to manually find them (this may be fixed in ajv v9).
- *
- * @param mermaidConfigSchema - The Mermaid JSON Schema to use.
- * @returns The default mermaid config object.
- */
-function generateDefaults(mermaidConfigSchema: JSONSchemaType) {
- const ajv = new Ajv2019({
- useDefaults: true,
- allowUnionTypes: true,
- strict: true,
- });
-
- ajv.addKeyword({
- keyword: 'meta:enum', // used by jsonschema2md
- errors: false,
- });
- ajv.addKeyword({
- keyword: 'tsType', // used by json-schema-to-typescript
- errors: false,
- });
-
- // ajv currently doesn't support nested default values, see https://github.com/ajv-validator/ajv/issues/1718
- // (may be fixed in v9) so we need to manually use sub-schemas
- const mermaidDefaultConfig = {};
-
- assert.ok(mermaidConfigSchema.$defs);
- const baseDiagramConfig = mermaidConfigSchema.$defs.BaseDiagramConfig;
-
- for (const key of MERMAID_CONFIG_DIAGRAM_KEYS) {
- const subSchemaRef = mermaidConfigSchema.properties[key].$ref;
- const [root, defs, defName] = subSchemaRef.split('/');
- assert.strictEqual(root, '#');
- assert.strictEqual(defs, '$defs');
- const subSchema = {
- $schema: mermaidConfigSchema.$schema,
- $defs: mermaidConfigSchema.$defs,
- ...mermaidConfigSchema.$defs[defName],
- } as JSONSchemaType;
-
- const validate = ajv.compile(subSchema);
-
- mermaidDefaultConfig[key] = {};
-
- for (const required of subSchema.required ?? []) {
- if (subSchema.properties[required] === undefined && baseDiagramConfig.properties[required]) {
- mermaidDefaultConfig[key][required] = baseDiagramConfig.properties[required].default;
- }
- }
- if (!validate(mermaidDefaultConfig[key])) {
- throw new Error(
- `schema for subconfig ${key} does not have valid defaults! Errors were ${JSON.stringify(
- validate.errors,
- undefined,
- 2
- )}`
- );
- }
- }
-
- const validate = ajv.compile(mermaidConfigSchema);
-
- if (!validate(mermaidDefaultConfig)) {
- throw new Error(
- `Mermaid config JSON Schema does not have valid defaults! Errors were ${JSON.stringify(
- validate.errors,
- undefined,
- 2
- )}`
- );
- }
-
- return mermaidDefaultConfig;
-}
+import { getDefaults, getSchema, loadSchema } from '../.build/jsonSchema.js';
/**
* Vite plugin that handles JSON Schemas saved as a `.schema.yaml` file.
@@ -120,32 +16,13 @@ export default function jsonSchemaPlugin(): PluginOption {
return;
}
- if (idAsUrl.searchParams.get('only-defaults')) {
- const jsonSchema = load(src, {
- filename: idAsUrl.pathname,
- // only allow JSON types in our YAML doc (will probably be default in YAML 1.3)
- // e.g. `true` will be parsed a boolean `true`, `True` will be parsed as string `"True"`.
- schema: JSON_SCHEMA,
- }) as JSONSchemaType;
- return {
- code: `export default ${JSON.stringify(generateDefaults(jsonSchema), undefined, 2)};`,
- map: null, // no source map
- };
- } else {
- return {
- code: `export default ${JSON.stringify(
- load(src, {
- filename: idAsUrl.pathname,
- // only allow JSON types in our YAML doc (will probably be default in YAML 1.3)
- // e.g. `true` will be parsed a boolean `true`, `True` will be parsed as string `"True"`.
- schema: JSON_SCHEMA,
- }),
- undefined,
- 2
- )};`,
- map: null, // provide source map if available
- };
- }
+ const jsonSchema = loadSchema(src, idAsUrl.pathname);
+ return {
+ code: idAsUrl.searchParams.get('only-defaults')
+ ? getDefaults(jsonSchema)
+ : getSchema(jsonSchema),
+ map: null, // no source map
+ };
},
};
}
diff --git a/.vite/server.ts b/.vite/server.ts
index 41e510c83..99d16f6f2 100644
--- a/.vite/server.ts
+++ b/.vite/server.ts
@@ -1,6 +1,7 @@
import express from 'express';
import cors from 'cors';
import { createServer as createViteServer } from 'vite';
+import { packageOptions } from '../.build/common.js';
async function createServer() {
const app = express();
@@ -14,9 +15,9 @@ async function createServer() {
});
app.use(cors());
- app.use(express.static('./packages/mermaid/dist'));
- app.use(express.static('./packages/mermaid-zenuml/dist'));
- app.use(express.static('./packages/mermaid-example-diagram/dist'));
+ for (const { packageName } of Object.values(packageOptions)) {
+ app.use(express.static(`./packages/${packageName}/dist`));
+ }
app.use(vite.middlewares);
app.use(express.static('demos'));
app.use(express.static('cypress/platform'));
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
index 9633bed66..4923342e4 100644
--- a/.vscode/extensions.json
+++ b/.vscode/extensions.json
@@ -2,7 +2,7 @@
"recommendations": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
- "zixuanchen.vitest-explorer",
+ "vitest.explorer",
"luniclynx.bison"
]
}
diff --git a/Dockerfile b/Dockerfile
index a62800109..1cc9ef030 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,2 +1,2 @@
-FROM node:18.19.0-alpine3.18 AS base
+FROM node:20.11.1-alpine3.19 AS base
RUN wget -qO- https://get.pnpm.io/install.sh | ENV="$HOME/.shrc" SHELL="$(which sh)" sh -
diff --git a/README.md b/README.md
index 58287c634..d368a4349 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,7 @@ Generate diagrams from markdown-like text.
Live Editor!
- 📖 Documentation | 🚀 Getting Started | 🌐 CDN | 🙌 Join Us
+ 📖 Documentation | 🚀 Getting Started | 🌐 CDN | 🙌 Join Us
简体中文
@@ -33,7 +33,7 @@ Try Live Editor previews of future releases:
@@ -42,7 +42,7 @@ Try Live Editor previews of future releases:
+
## Table of content
@@ -53,7 +53,7 @@ Try Live Editor previews of future releases: docs - live editor ]
+### Flowchart [docs - live editor ]
```
flowchart LR
@@ -115,12 +115,12 @@ C -->|One| D[Result 1]
C -->|Two| E[Result 2]
```
-### Sequence diagram [docs - live editor ]
+### Sequence diagram [docs - live editor ]
```
sequenceDiagram
Alice->>John: Hello John, how are you?
-loop Healthcheck
+loop HealthCheck
John->>John: Fight against hypochondria
end
Note right of John: Rational thoughts!
@@ -132,7 +132,7 @@ Bob-->>John: Jolly good!
```mermaid
sequenceDiagram
Alice->>John: Hello John, how are you?
-loop Healthcheck
+loop HealthCheck
John->>John: Fight against hypochondria
end
Note right of John: Rational thoughts!
@@ -141,7 +141,7 @@ John->>Bob: How about you?
Bob-->>John: Jolly good!
```
-### Gantt chart [docs - live editor ]
+### Gantt chart [docs - live editor ]
```
gantt
@@ -165,7 +165,7 @@ gantt
Parallel 4 : des6, after des4, 1d
```
-### Class diagram [docs - live editor ]
+### Class diagram [docs - live editor ]
```
classDiagram
@@ -207,7 +207,7 @@ class Class10 {
```
-### State diagram [docs - live editor ]
+### State diagram [docs - live editor ]
```
stateDiagram-v2
@@ -229,7 +229,7 @@ Moving --> Crash
Crash --> [*]
```
-### Pie chart [docs - live editor ]
+### Pie chart [docs - live editor ]
```
pie
@@ -247,7 +247,7 @@ pie
### Git graph [experimental - live editor ]
-### Bar chart (using gantt chart) [docs - live editor ]
+### Bar chart (using gantt chart) [docs - live editor ]
```
gantt
@@ -285,7 +285,7 @@ gantt
5 : 0, 5
```
-### User Journey diagram [docs - live editor ]
+### User Journey diagram [docs - live editor ]
```
journey
@@ -311,7 +311,7 @@ gantt
Sit down: 3: Me
```
-### C4 diagram [docs ]
+### C4 diagram [docs ]
```
C4Context
@@ -405,7 +405,7 @@ The above command generates files into the `dist` folder and publishes them to <
Mermaid is a growing community and is always accepting new contributors. There's a lot of different ways to help out and we're always looking for extra hands! Look at [this issue](https://github.com/mermaid-js/mermaid/issues/866) if you want to know where to start helping out.
-Detailed information about how to contribute can be found in the [contribution guide](CONTRIBUTING.md)
+Detailed information about how to contribute can be found in the [contribution guide](https://mermaid.js.org/community/contributing.html)
## Security and safe diagrams
diff --git a/README.zh-CN.md b/README.zh-CN.md
index c468b2d9f..942f54bff 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -15,7 +15,7 @@ Mermaid
实时编辑器!
- 📖 文档 | 🚀 入门 | 🌐 CDN | 🙌 加入我们
+ 📖 文档 | 🚀 入门 | 🌐 CDN | 🙌 加入我们
English
@@ -34,7 +34,7 @@ Mermaid
[](https://app.codecov.io/github/mermaid-js/mermaid/tree/develop)
[](https://www.jsdelivr.com/package/npm/mermaid)
[](https://www.npmjs.com/package/mermaid)
-[](https://discord.gg/wwtabKgp8y)
+[](https://discord.gg/AgrbSrBer3)
[](https://twitter.com/mermaidjs_)
@@ -43,7 +43,7 @@ Mermaid
**感谢所有参与进来提交 PR,解答疑问的人们! 🙏**
-
+
## 关于 Mermaid
@@ -57,20 +57,20 @@ Mermaid 是一个基于 Javascript 的图表绘制工具,通过解析类 Markd
Mermaid 通过允许用户创建便于修改的图表来解决这一难题,它也可以作为生产脚本(或其他代码)的一部分。
Mermaid 甚至能让非程序员也能通过 [Mermaid Live Editor](https://mermaid.live/) 轻松创建详细的图表。
-你可以访问 [教程](./docs/ecosystem/tutorials.md) 来查看 Live Editor 的视频教程,也可以查看 [Mermaid 的集成和使用](./docs/ecosystem/integrations-community.md) 这个清单来检查你的文档工具是否已经集成了 Mermaid 支持。
+你可以访问 [教程](https://mermaid.js.org/ecosystem/tutorials.html) 来查看 Live Editor 的视频教程,也可以查看 [Mermaid 的集成和使用](https://mermaid.js.org/ecosystem/integrations-community.html) 这个清单来检查你的文档工具是否已经集成了 Mermaid 支持。
-如果想要查看关于 Mermaid 更详细的介绍及基础使用方式,可以查看 [入门指引](./docs/intro/getting-started.md), [用法](./docs/config/usage.md) 和 [教程](./docs/ecosystem/tutorials.md).
+如果想要查看关于 Mermaid 更详细的介绍及基础使用方式,可以查看 [入门指引](https://mermaid.js.org/intro/getting-started.html), [用法](https://mermaid.js.org/config/usage.html) 和 [教程](https://mermaid.js.org/ecosystem/tutorials.html).
## 示例
-**下面是一些可以使用 Mermaid 创建的图表示例。点击 [语法](https://mermaid-js.github.io/mermaid/#/n00b-syntaxReference) 查看详情。**
+**下面是一些可以使用 Mermaid 创建的图表示例。点击 [语法](https://mermaid.js.org/intro/syntax-reference.html) 查看详情。**
-### 流程图 [文档 - live editor ]
+### 流程图 [文档 - live editor ]
```
flowchart LR
@@ -88,12 +88,12 @@ C -->|One| D[Result 1]
C -->|Two| E[Result 2]
```
-### 时序图 [文档 - live editor ]
+### 时序图 [文档 - live editor ]
```
sequenceDiagram
Alice->>John: Hello John, how are you?
-loop Healthcheck
+loop HealthCheck
John->>John: Fight against hypochondria
end
Note right of John: Rational thoughts!
@@ -105,7 +105,7 @@ Bob-->>John: Jolly good!
```mermaid
sequenceDiagram
Alice->>John: Hello John, how are you?
-loop Healthcheck
+loop HealthCheck
John->>John: Fight against hypochondria
end
Note right of John: Rational thoughts!
@@ -114,7 +114,7 @@ John->>Bob: How about you?
Bob-->>John: Jolly good!
```
-### 甘特图 [文档 - live editor ]
+### 甘特图 [文档 - live editor ]
```
gantt
@@ -138,7 +138,7 @@ gantt
Parallel 4 : des6, after des4, 1d
```
-### 类图 [文档 - live editor ]
+### 类图 [文档 - live editor ]
```
classDiagram
@@ -178,7 +178,7 @@ class Class10 {
}
```
-### 状态图 [[docs - live editor ]
+### 状态图 [docs - live editor ]
```
stateDiagram-v2
@@ -200,7 +200,7 @@ Moving --> Crash
Crash --> [*]
```
-### 饼图 [文档 - live editor ]
+### 饼图 [文档 - live editor ]
```
pie
@@ -218,7 +218,7 @@ pie
### Git 图 [实验特性 - live editor ]
-### 用户体验旅程图 [文档 - live editor ]
+### 用户体验旅程图 [文档 - live editor ]
```
journey
@@ -244,7 +244,7 @@ pie
Sit down: 3: Me
```
-### C4 图 [文档 ]
+### C4 图 [文档 ]
```
C4Context
@@ -338,7 +338,7 @@ npm publish
Mermaid 是一个不断发展中的社区,并且还在接收新的贡献者。有很多不同的方式可以参与进来,而且我们还在寻找额外的帮助。如果你想知道如何开始贡献,请查看 [这个 issue](https://github.com/mermaid-js/mermaid/issues/866)。
-关于如何贡献的详细信息可以在 [贡献指南](CONTRIBUTING.md) 中找到。
+关于如何贡献的详细信息可以在 [贡献指南](https://mermaid.js.org/community/contributing.html) 中找到。
## 安全
diff --git a/__mocks__/c4Renderer.js b/__mocks__/c4Renderer.js
deleted file mode 100644
index 576d5d863..000000000
--- a/__mocks__/c4Renderer.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/**
- * Mocked C4Context diagram renderer
- */
-
-import { vi } from 'vitest';
-
-export const drawPersonOrSystemArray = vi.fn();
-export const drawBoundary = vi.fn();
-
-export const setConf = vi.fn();
-
-export const draw = vi.fn().mockImplementation(() => {
- return '';
-});
-
-export default {
- drawPersonOrSystemArray,
- drawBoundary,
- setConf,
- draw,
-};
diff --git a/__mocks__/classRenderer-v2.js b/__mocks__/classRenderer-v2.js
deleted file mode 100644
index 1ad95806f..000000000
--- a/__mocks__/classRenderer-v2.js
+++ /dev/null
@@ -1,16 +0,0 @@
-/**
- * Mocked class diagram v2 renderer
- */
-
-import { vi } from 'vitest';
-
-export const setConf = vi.fn();
-
-export const draw = vi.fn().mockImplementation(() => {
- return '';
-});
-
-export default {
- setConf,
- draw,
-};
diff --git a/__mocks__/classRenderer.js b/__mocks__/classRenderer.js
deleted file mode 100644
index 1c20de4b1..000000000
--- a/__mocks__/classRenderer.js
+++ /dev/null
@@ -1,13 +0,0 @@
-/**
- * Mocked class diagram renderer
- */
-
-import { vi } from 'vitest';
-
-export const draw = vi.fn().mockImplementation(() => {
- return '';
-});
-
-export default {
- draw,
-};
diff --git a/__mocks__/dagre-d3.ts b/__mocks__/dagre-d3.ts
deleted file mode 100644
index bf6d341dc..000000000
--- a/__mocks__/dagre-d3.ts
+++ /dev/null
@@ -1 +0,0 @@
-// DO NOT delete this file. It is used by vitest to mock the dagre-d3 module.
diff --git a/__mocks__/entity-decode/browser.ts b/__mocks__/entity-decode/browser.ts
deleted file mode 100644
index bd82d79fd..000000000
--- a/__mocks__/entity-decode/browser.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-module.exports = function (txt: string) {
- return txt;
-};
diff --git a/__mocks__/erRenderer.js b/__mocks__/erRenderer.js
deleted file mode 100644
index 845d641f7..000000000
--- a/__mocks__/erRenderer.js
+++ /dev/null
@@ -1,16 +0,0 @@
-/**
- * Mocked er diagram renderer
- */
-
-import { vi } from 'vitest';
-
-export const setConf = vi.fn();
-
-export const draw = vi.fn().mockImplementation(() => {
- return '';
-});
-
-export default {
- setConf,
- draw,
-};
diff --git a/__mocks__/flowRenderer-v2.js b/__mocks__/flowRenderer-v2.js
deleted file mode 100644
index 89cc86031..000000000
--- a/__mocks__/flowRenderer-v2.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/**
- * Mocked flow (flowchart) diagram v2 renderer
- */
-
-import { vi } from 'vitest';
-
-export const setConf = vi.fn();
-export const addVertices = vi.fn();
-export const addEdges = vi.fn();
-export const getClasses = vi.fn().mockImplementation(() => {
- return {};
-});
-
-export const draw = vi.fn().mockImplementation(() => {
- return '';
-});
-
-export default {
- setConf,
- addVertices,
- addEdges,
- getClasses,
- draw,
-};
diff --git a/__mocks__/ganttRenderer.js b/__mocks__/ganttRenderer.js
deleted file mode 100644
index 957249832..000000000
--- a/__mocks__/ganttRenderer.js
+++ /dev/null
@@ -1,16 +0,0 @@
-/**
- * Mocked gantt diagram renderer
- */
-
-import { vi } from 'vitest';
-
-export const setConf = vi.fn();
-
-export const draw = vi.fn().mockImplementation(() => {
- return '';
-});
-
-export default {
- setConf,
- draw,
-};
diff --git a/__mocks__/gitGraphRenderer.js b/__mocks__/gitGraphRenderer.js
deleted file mode 100644
index 1daa82ca4..000000000
--- a/__mocks__/gitGraphRenderer.js
+++ /dev/null
@@ -1,13 +0,0 @@
-/**
- * Mocked git (graph) diagram renderer
- */
-
-import { vi } from 'vitest';
-
-export const draw = vi.fn().mockImplementation(() => {
- return '';
-});
-
-export default {
- draw,
-};
diff --git a/__mocks__/journeyRenderer.js b/__mocks__/journeyRenderer.js
deleted file mode 100644
index 2bc77c0b1..000000000
--- a/__mocks__/journeyRenderer.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * Mocked pie (picChart) diagram renderer
- */
-
-import { vi } from 'vitest';
-export const setConf = vi.fn();
-
-export const draw = vi.fn().mockImplementation(() => {
- return '';
-});
-
-export default {
- setConf,
- draw,
-};
diff --git a/__mocks__/pieRenderer.ts b/__mocks__/pieRenderer.ts
deleted file mode 100644
index 439800f8c..000000000
--- a/__mocks__/pieRenderer.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-/**
- * Mocked pie (picChart) diagram renderer
- */
-import { vi } from 'vitest';
-
-const draw = vi.fn().mockImplementation(() => '');
-
-export const renderer = { draw };
diff --git a/__mocks__/requirementRenderer.js b/__mocks__/requirementRenderer.js
deleted file mode 100644
index 48d8997ac..000000000
--- a/__mocks__/requirementRenderer.js
+++ /dev/null
@@ -1,13 +0,0 @@
-/**
- * Mocked requirement diagram renderer
- */
-
-import { vi } from 'vitest';
-
-export const draw = vi.fn().mockImplementation(() => {
- return '';
-});
-
-export default {
- draw,
-};
diff --git a/__mocks__/sankeyRenderer.js b/__mocks__/sankeyRenderer.js
deleted file mode 100644
index 76324c93f..000000000
--- a/__mocks__/sankeyRenderer.js
+++ /dev/null
@@ -1,13 +0,0 @@
-/**
- * Mocked Sankey diagram renderer
- */
-
-import { vi } from 'vitest';
-
-export const draw = vi.fn().mockImplementation(() => {
- return '';
-});
-
-export default {
- draw,
-};
diff --git a/__mocks__/sequenceRenderer.js b/__mocks__/sequenceRenderer.js
deleted file mode 100644
index 11080c6bb..000000000
--- a/__mocks__/sequenceRenderer.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/**
- * Mocked sequence diagram renderer
- */
-
-import { vi } from 'vitest';
-
-export const bounds = vi.fn();
-export const drawActors = vi.fn();
-export const drawActorsPopup = vi.fn();
-
-export const setConf = vi.fn();
-
-export const draw = vi.fn().mockImplementation(() => {
- return '';
-});
-
-export default {
- bounds,
- drawActors,
- drawActorsPopup,
- setConf,
- draw,
-};
diff --git a/__mocks__/stateRenderer-v2.js b/__mocks__/stateRenderer-v2.js
deleted file mode 100644
index a2d103b50..000000000
--- a/__mocks__/stateRenderer-v2.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/**
- * Mocked state diagram v2 renderer
- */
-
-import { vi } from 'vitest';
-
-export const setConf = vi.fn();
-export const getClasses = vi.fn().mockImplementation(() => {
- return {};
-});
-export const stateDomId = vi.fn().mockImplementation(() => {
- return 'mocked-stateDiagram-stateDomId';
-});
-export const draw = vi.fn().mockImplementation(() => {
- return '';
-});
-
-export default {
- setConf,
- getClasses,
- draw,
-};
diff --git a/cSpell.json b/cSpell.json
deleted file mode 100644
index 4b8772347..000000000
--- a/cSpell.json
+++ /dev/null
@@ -1,209 +0,0 @@
-{
- "version": "0.2",
- "language": "en",
- "words": [
- "acyclicer",
- "adamiecki",
- "alois",
- "aloisklink",
- "antiscript",
- "antlr",
- "appli",
- "applitools",
- "asciidoctor",
- "ashish",
- "ashishjain",
- "astah",
- "bbox",
- "bilkent",
- "bisheng",
- "blrs",
- "braintree",
- "brkt",
- "brolin",
- "brotli",
- "catmull",
- "città",
- "classdef",
- "codedoc",
- "codemia",
- "colour",
- "commitlint",
- "cpettitt",
- "customizability",
- "cuzon",
- "cytoscape",
- "dagre",
- "deepdwn",
- "descr",
- "docsify",
- "docsy",
- "doku",
- "dompurify",
- "dont",
- "doublecircle",
- "edgechromium",
- "elems",
- "elkjs",
- "elle",
- "faber",
- "flatmap",
- "foswiki",
- "frontmatter",
- "ftplugin",
- "gantt",
- "gitea",
- "gitgraph",
- "globby",
- "graphlib",
- "graphviz",
- "grav",
- "greywolf",
- "gzipped",
- "huynh",
- "huynhicode",
- "inkdrop",
- "jaoude",
- "jgreywolf",
- "jison",
- "jiti",
- "kaufmann",
- "khroma",
- "klemm",
- "klink",
- "knsv",
- "knut",
- "knutsveidqvist",
- "laganeckas",
- "linetype",
- "lintstagedrc",
- "logmsg",
- "lucida",
- "markdownish",
- "matthieu",
- "matthieumorel",
- "mdast",
- "mdbook",
- "mermaidjs",
- "mermerd",
- "mindaugas",
- "mindmap",
- "mindmaps",
- "mitigations",
- "mkdocs",
- "mmorel",
- "mult",
- "neurodiverse",
- "nextra",
- "nikolay",
- "nirname",
- "npmjs",
- "orlandoni",
- "pathe",
- "pbrolin",
- "phpbb",
- "pixelmatch",
- "plantuml",
- "playfair",
- "pnpm",
- "podlite",
- "quence",
- "radious",
- "ranksep",
- "rect",
- "rects",
- "reda",
- "redmine",
- "regexes",
- "rehype",
- "roledescription",
- "rozhkov",
- "sandboxed",
- "sankey",
- "setupgraphviewbox",
- "shiki",
- "sidharth",
- "sidharthv",
- "sphinxcontrib",
- "ssim",
- "startx",
- "starty",
- "statediagram",
- "steph",
- "stopx",
- "stopy",
- "stylis",
- "subhash-halder",
- "substate",
- "sulais",
- "sveidqvist",
- "swimm",
- "techn",
- "teststr",
- "textlength",
- "treemap",
- "ts-nocheck",
- "tsdoc",
- "tuleap",
- "tylerlong",
- "typora",
- "ugge",
- "unist",
- "unocss",
- "upvoting",
- "valign",
- "verdana",
- "viewports",
- "vinod",
- "visio",
- "vitepress",
- "vueuse",
- "xlink",
- "xychart",
- "yash",
- "yokozuna",
- "zenuml",
- "zune"
- ],
- "patterns": [
- { "name": "Markdown links", "pattern": "\\((.*)\\)", "description": "" },
- {
- "name": "Markdown code blocks",
- "pattern": "/^(\\s*`{3,}).*[\\s\\S]*?^\\1/gmx",
- "description": "Taken from the cSpell example at https://cspell.org/configuration/patterns/#verbose-regular-expressions"
- },
- {
- "name": "Inline code blocks",
- "pattern": "\\`([^\\`\\r\\n]+?)\\`",
- "description": "https://stackoverflow.com/questions/41274241/how-to-capture-inline-markdown-code-but-not-a-markdown-code-fence-with-regex"
- },
- { "name": "Link contents", "pattern": "\\", "description": "" },
- { "name": "Snippet references", "pattern": "-- snippet:(.*)", "description": "" },
- {
- "name": "Snippet references 2",
- "pattern": "\\<\\[sample:(.*)",
- "description": "another kind of snippet reference"
- },
- { "name": "Multi-line code blocks", "pattern": "/^\\s*```[\\s\\S]*?^\\s*```/gm" },
- {
- "name": "HTML Tags",
- "pattern": "<[^>]*>",
- "description": "Reference: https://stackoverflow.com/questions/11229831/regular-expression-to-remove-html-tags-from-a-string"
- }
- ],
- "ignoreRegExpList": [
- "Markdown links",
- "Markdown code blocks",
- "Inline code blocks",
- "Link contents",
- "Snippet references",
- "Snippet references 2",
- "Multi-line code blocks",
- "HTML Tags"
- ],
- "ignorePaths": [
- "packages/mermaid/src/docs/CHANGELOG.md",
- "packages/mermaid/src/docs/.vitepress/redirect.ts",
- "packages/mermaid/src/docs/.vitepress/contributor-names.json"
- ]
-}
diff --git a/cspell.config.yaml b/cspell.config.yaml
new file mode 100644
index 000000000..885a41afd
--- /dev/null
+++ b/cspell.config.yaml
@@ -0,0 +1,45 @@
+# yaml-language-server: $schema=https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json
+
+$schema: https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json
+version: '0.2'
+language: en-US,en-GB
+
+import:
+ - ./.cspell/cspell.config.yaml
+
+ignoreRegExpList:
+ - character-set-cyrillic
+ - svg-block
+ignorePaths:
+ - '*lock.{yaml,json}'
+ - dist
+ - CHANGELOG.md
+ - packages/mermaid/src/docs/.vitepress/redirect.ts
+ - packages/mermaid/src/docs/.vitepress/contributor-names.json
+ - backup
+ - '**/*.spec.{js,ts}' # checked by eslint
+ - 'tests/webpack/src/index.js' # checked by eslint
+ - 'cypress/**/*.js' # checked by eslint
+ - '*.csv'
+ - '*.patch'
+ - 'docs/**/*.html'
+ - 'cypress/platform/**'
+dictionaries:
+ - misc-terms
+overrides:
+ - filename:
+ - '**/*.{jison,ts,mts,cjs,mjs,js,json,yaml,yml,md,html}'
+ - 'run'
+ - Dockerfile
+ ignoreRegExpList:
+ - js-unicode-escape
+ dictionaries:
+ - code-terms
+ - 3rd-party-terms
+ - fonts
+ - html
+ - lorem-ipsum
+ - filename: '**/package.json'
+ ignoreRegExpList:
+ - json-property
+# cspell:dictionaries code-terms
diff --git a/cypress/integration/other/flowchart-elk.spec.js b/cypress/integration/other/flowchart-elk.spec.js
new file mode 100644
index 000000000..22a6efc0f
--- /dev/null
+++ b/cypress/integration/other/flowchart-elk.spec.js
@@ -0,0 +1,14 @@
+import { urlSnapshotTest, openURLAndVerifyRendering } from '../../helpers/util.ts';
+
+describe('Flowchart elk', () => {
+ it('should use dagre as fallback', () => {
+ urlSnapshotTest('http://localhost:9000/flow-elk.html', {
+ name: 'flow-elk fallback to dagre',
+ });
+ });
+ it('should allow overriding with external package', () => {
+ urlSnapshotTest('http://localhost:9000/flow-elk.html?elk=true', {
+ name: 'flow-elk overriding dagre with elk',
+ });
+ });
+});
diff --git a/cypress/integration/other/iife.spec.js b/cypress/integration/other/iife.spec.js
new file mode 100644
index 000000000..4eb860146
--- /dev/null
+++ b/cypress/integration/other/iife.spec.js
@@ -0,0 +1,11 @@
+describe('IIFE', () => {
+ beforeEach(() => {
+ cy.visit('http://localhost:9000/iife.html');
+ });
+
+ it('should render when using mermaid.min.js', () => {
+ cy.window().should('have.property', 'rendered', true);
+ cy.get('svg').should('be.visible');
+ cy.get('#d2').should('contain', 'Hello');
+ });
+});
diff --git a/cypress/integration/other/webpackUsage.spec.js b/cypress/integration/other/webpackUsage.spec.js
deleted file mode 100644
index 727fb5ac7..000000000
--- a/cypress/integration/other/webpackUsage.spec.js
+++ /dev/null
@@ -1,16 +0,0 @@
-describe('Sequencediagram', () => {
- it('should render a simple sequence diagrams', () => {
- const url = 'http://localhost:9000/webpackUsage.html';
-
- cy.visit(url);
- cy.get('body').find('svg').should('have.length', 1);
- });
- it('should handle html escapings properly', () => {
- const url = 'http://localhost:9000/webpackUsage.html?test-html-escaping=true';
-
- cy.visit(url);
- cy.get('body').find('svg').should('have.length', 1);
-
- cy.get('g.label > foreignobject > div').should('not.contain.text', '');
- });
-});
diff --git a/cypress/integration/rendering/block.spec.js b/cypress/integration/rendering/block.spec.js
new file mode 100644
index 000000000..9d62c642d
--- /dev/null
+++ b/cypress/integration/rendering/block.spec.js
@@ -0,0 +1,386 @@
+import { imgSnapshotTest } from '../../helpers/util';
+/* eslint-disable no-useless-escape */
+describe('Block diagram', () => {
+ it('BL1: should calculate the block widths', () => {
+ imgSnapshotTest(
+ `block-beta
+ columns 2
+ block
+ id2["I am a wide one"]
+ id1
+ end
+ id["Next row"]
+ `
+ );
+ });
+
+ it('BL2: should handle colums statement in sub-blocks', () => {
+ imgSnapshotTest(
+ `block-beta
+ id1["Hello"]
+ block
+ columns 3
+ id2["to"]
+ id3["the"]
+ id4["World"]
+ id5["World"]
+ end
+ `,
+ {}
+ );
+ });
+
+ it('BL3: should align block widths and handle colums statement in sub-blocks', () => {
+ imgSnapshotTest(
+ `block-beta
+ block
+ columns 1
+ id1
+ id2
+ id2.1
+ end
+ id3
+ id4
+ `,
+ {}
+ );
+ });
+
+ it('BL4: should align block widths and handle colums statements in deeper sub-blocks then 1 level', () => {
+ imgSnapshotTest(
+ `block-beta
+ columns 1
+ block
+ columns 1
+ block
+ columns 3
+ id1
+ id2
+ id2.1(("XYZ"))
+ end
+ id48
+ end
+ id3
+ `,
+ {}
+ );
+ });
+
+ it('BL5: should align block widths and handle colums statements in deeper sub-blocks then 1 level (alt)', () => {
+ imgSnapshotTest(
+ `block-beta
+ columns 1
+ block
+ id1
+ id2
+ block
+ columns 1
+ id3("Wider then")
+ id5(("id5"))
+ end
+ end
+ id4
+ `,
+ {}
+ );
+ });
+
+ it('BL6: should handle block arrows and spece statements', () => {
+ imgSnapshotTest(
+ `block-beta
+ columns 3
+ space:3
+ ida idb idc
+ id1 id2
+ blockArrowId<["Label"]>(right)
+ blockArrowId2<["Label"]>(left)
+ blockArrowId3<["Label"]>(up)
+ blockArrowId4<["Label"]>(down)
+ blockArrowId5<["Label"]>(x)
+ blockArrowId6<["Label"]>(y)
+ blockArrowId6<["Label"]>(x, down)
+ `,
+ {}
+ );
+ });
+
+ it('BL7: should handle different types of edges', () => {
+ imgSnapshotTest(
+ `block-beta
+ columns 3
+ A space:5
+ A --o B
+ A --> C
+ A --x D
+ `,
+ {}
+ );
+ });
+
+ it('BL8: should handle sub-blocks without columns statements', () => {
+ imgSnapshotTest(
+ `block-beta
+ columns 2
+ C A B
+ block
+ D
+ E
+ end
+ `,
+ {}
+ );
+ });
+
+ it('BL9: should handle edges from blocks in sub blocks to other blocks', () => {
+ imgSnapshotTest(
+ `block-beta
+ columns 3
+ B space
+ block
+ D
+ end
+ D --> B
+ `,
+ {}
+ );
+ });
+
+ it('BL10: should handle edges from composite blocks', () => {
+ imgSnapshotTest(
+ `block-beta
+ columns 3
+ B space
+ block BL
+ D
+ end
+ BL --> B
+ `,
+ {}
+ );
+ });
+
+ it('BL11: should handle edges to composite blocks', () => {
+ imgSnapshotTest(
+ `block-beta
+ columns 3
+ B space
+ block BL
+ D
+ end
+ B --> BL
+ `,
+ {}
+ );
+ });
+
+ it('BL12: edges should handle labels', () => {
+ imgSnapshotTest(
+ `block-beta
+ A
+ space
+ A -- "apa" --> E
+ `,
+ {}
+ );
+ });
+
+ it('BL13: should handle block arrows in different directions', () => {
+ imgSnapshotTest(
+ `block-beta
+ columns 3
+ space blockArrowId1<["down"]>(down) space
+ blockArrowId2<["right"]>(right) blockArrowId3<["Sync"]>(x, y) blockArrowId4<["left"]>(left)
+ space blockArrowId5<["up"]>(up) space
+ blockArrowId6<["x"]>(x) space blockArrowId7<["y"]>(y)
+ `,
+ {}
+ );
+ });
+
+ it('BL14: should style statements and class statements', () => {
+ imgSnapshotTest(
+ `block-beta
+ A
+ B
+ classDef blue fill:#66f,stroke:#333,stroke-width:2px;
+ class A blue
+ style B fill:#f9F,stroke:#333,stroke-width:4px
+ `,
+ {}
+ );
+ });
+
+ it('BL15: width alignment - D and E should share available space', () => {
+ imgSnapshotTest(
+ `block-beta
+ block
+ D
+ E
+ end
+ db("This is the text in the box")
+ `,
+ {}
+ );
+ });
+
+ it('BL16: width alignment - C should be as wide as the composite block', () => {
+ imgSnapshotTest(
+ `block-beta
+ block
+ A("This is the text")
+ B
+ end
+ C
+ `,
+ {}
+ );
+ });
+
+ it('BL16: width alignment - blocks shold be equal in width', () => {
+ imgSnapshotTest(
+ `block-beta
+ A("This is the text")
+ B
+ C
+ `,
+ {}
+ );
+ });
+
+ it('BL17: block types 1 - square, rounded and circle', () => {
+ imgSnapshotTest(
+ `block-beta
+ A["square"]
+ B("rounded")
+ C(("circle"))
+ `,
+ {}
+ );
+ });
+
+ it('BL18: block types 2 - odd, diamond and hexagon', () => {
+ imgSnapshotTest(
+ `block-beta
+ A>"rect_left_inv_arrow"]
+ B{"diamond"}
+ C{{"hexagon"}}
+ `,
+ {}
+ );
+ });
+
+ it('BL19: block types 3 - stadium', () => {
+ imgSnapshotTest(
+ `block-beta
+ A(["stadium"])
+ `,
+ {}
+ );
+ });
+
+ it('BL20: block types 4 - lean right, lean left, trapezoid and inv trapezoid', () => {
+ imgSnapshotTest(
+ `block-beta
+ A[/"lean right"/]
+ B[\"lean left"\]
+ C[/"trapezoid"\]
+ D[\"trapezoid alt"/]
+ `,
+ {}
+ );
+ });
+
+ it('BL21: block types 1 - square, rounded and circle', () => {
+ imgSnapshotTest(
+ `block-beta
+ A["square"]
+ B("rounded")
+ C(("circle"))
+ `,
+ {}
+ );
+ });
+
+ it('BL22: sizing - it should be possible to make a block wider', () => {
+ imgSnapshotTest(
+ `block-beta
+ A("rounded"):2
+ B:2
+ C
+ `,
+ {}
+ );
+ });
+
+ it('BL23: sizing - it should be possible to make a composite block wider', () => {
+ imgSnapshotTest(
+ `block-beta
+ block:2
+ A
+ end
+ B
+ `,
+ {}
+ );
+ });
+
+ it('BL24: block in the middle with space on each side', () => {
+ imgSnapshotTest(
+ `block-beta
+ columns 3
+ space
+ middle["In the middle"]
+ space
+ `,
+ {}
+ );
+ });
+ it('BL25: space and an edge', () => {
+ imgSnapshotTest(
+ `block-beta
+ columns 5
+ A space B
+ A --x B
+ `,
+ {}
+ );
+ });
+ it('BL26: block sizes for regular blocks', () => {
+ imgSnapshotTest(
+ `block-beta
+ columns 3
+ a["A wide one"] b:2 c:2 d
+ `,
+ {}
+ );
+ });
+ it('BL27: composite block with a set width - f should use the available space', () => {
+ imgSnapshotTest(
+ `block-beta
+ columns 3
+ a:3
+ block:e:3
+ f
+ end
+ g
+ `,
+ {}
+ );
+ });
+ it('BL23: composite block with a set width - f and g should split the available space', () => {
+ imgSnapshotTest(
+ `block-beta
+ columns 3
+ a:3
+ block:e:3
+ f
+ g
+ end
+ h
+ i
+ j
+ `,
+ {}
+ );
+ });
+});
diff --git a/cypress/integration/rendering/gantt.spec.js b/cypress/integration/rendering/gantt.spec.js
index 4abde9d44..a0c2dbcb9 100644
--- a/cypress/integration/rendering/gantt.spec.js
+++ b/cypress/integration/rendering/gantt.spec.js
@@ -92,6 +92,31 @@ describe('Gantt diagram', () => {
{}
);
});
+ it('should handle multiple dependencies syntax with after and until', () => {
+ imgSnapshotTest(
+ `
+ gantt
+ dateFormat YYYY-MM-DD
+ axisFormat %d/%m
+ title Adding GANTT diagram to mermaid
+ excludes weekdays 2014-01-10
+ todayMarker off
+
+ section team's critical event
+ deadline A :milestone, crit, deadlineA, 2024-02-01, 0
+ deadline B :milestone, crit, deadlineB, 2024-02-15, 0
+ boss on leave :bossaway, 2024-01-28, 2024-02-11
+
+ section new intern
+ onboarding :onboarding, 2024-01-02, 1w
+ literature review :litreview, 2024-01-02, 10d
+ project A :projectA, after onboarding litreview, until deadlineA bossaway
+ chilling :chilling, after projectA, until deadlineA
+ project B :projectB, after deadlineA, until deadlineB
+ `,
+ {}
+ );
+ });
it('should FAIL redering a gantt chart for issue #1060 with invalid date', () => {
imgSnapshotTest(
`
@@ -548,7 +573,28 @@ describe('Gantt diagram', () => {
`
);
});
-
+ it('should render a gantt diagram exculding friday and saturday', () => {
+ imgSnapshotTest(
+ `gantt
+ title A Gantt Diagram
+ dateFormat YYYY-MM-DD
+ excludes weekends
+ weekend friday
+ section Section1
+ A task :a1, 2024-02-28, 10d`
+ );
+ });
+ it('should render a gantt diagram exculding saturday and sunday', () => {
+ imgSnapshotTest(
+ `gantt
+ title A Gantt Diagram
+ dateFormat YYYY-MM-DD
+ excludes weekends
+ weekend saturday
+ section Section1
+ A task :a1, 2024-02-28, 10d`
+ );
+ });
it('should render when compact is true', () => {
imgSnapshotTest(
`
diff --git a/cypress/integration/rendering/gitGraph.spec.js b/cypress/integration/rendering/gitGraph.spec.js
index 19ddde31d..2184fecf8 100644
--- a/cypress/integration/rendering/gitGraph.spec.js
+++ b/cypress/integration/rendering/gitGraph.spec.js
@@ -943,4 +943,74 @@ gitGraph TB:
{ gitGraph: { parallelCommits: true } }
);
});
+ it('46: should render GitGraph with merge back and merge forward', () => {
+ imgSnapshotTest(
+ `gitGraph LR:
+ commit id:"1-abcdefg"
+
+ branch branch-A
+ branch branch-B
+ commit id:"2-abcdefg"
+
+ checkout branch-A
+ merge branch-B
+
+ checkout branch-B
+ merge branch-A
+ `,
+ { gitGraph: { parallelCommits: true } }
+ );
+ });
+ it('47: should render GitGraph with merge back and merge forward | Vertical Branch', () => {
+ imgSnapshotTest(
+ `gitGraph TB:
+ commit id:"1-abcdefg"
+
+ branch branch-A
+ branch branch-B
+ commit id:"2-abcdefg"
+
+ checkout branch-A
+ merge branch-B
+
+ checkout branch-B
+ merge branch-A
+ `,
+ { gitGraph: { parallelCommits: true } }
+ );
+ });
+ it('48: should render GitGraph with merge on a new branch | Vertical Branch', () => {
+ imgSnapshotTest(
+ `gitGraph LR:
+ commit id:"1-abcdefg"
+
+ branch branch-B order: 2
+ commit id:"2-abcdefg"
+
+ branch branch-A
+ merge main
+
+ checkout branch-B
+ merge branch-A
+ `,
+ { gitGraph: { parallelCommits: true } }
+ );
+ });
+ it('49: should render GitGraph with merge on a new branch | Vertical Branch', () => {
+ imgSnapshotTest(
+ `gitGraph TB:
+ commit id:"1-abcdefg"
+
+ branch branch-B order: 2
+ commit id:"2-abcdefg"
+
+ branch branch-A
+ merge main
+
+ checkout branch-B
+ merge branch-A
+ `,
+ { gitGraph: { parallelCommits: true } }
+ );
+ });
});
diff --git a/cypress/integration/rendering/katex.spec.js b/cypress/integration/rendering/katex.spec.js
new file mode 100644
index 000000000..fb1d13392
--- /dev/null
+++ b/cypress/integration/rendering/katex.spec.js
@@ -0,0 +1,36 @@
+import { imgSnapshotTest } from '../../helpers/util';
+
+describe('Katex', () => {
+ it('1: should render a complex Katex flowchart no htmlLabels', () => {
+ imgSnapshotTest(
+ `graph LR
+ A["$$f(\\relax{x}) = \\int_{-\\infty}^\\infty \\hat{f}(\\xi)\\,e^{2 \\pi i \\xi x}\\,d\\xi$$"] -->|"$$\\Bigg(\\bigg(\\Big(\\big((\\frac{-b\\pm\\sqrt{b^2-4ac}}{2a})\\big)\\Big)\\bigg)\\Bigg)$$"| B("$$1+\\frac{e^{-2\\pi}} {1+\\frac{e^{-4\\pi}} {1+\\frac{e^{-6\\pi}} {1+\\frac{e^{-8\\pi}} {1+\\cdots}}}}$$")
+ A -->|"$$\\overbrace{a+b+c}^{\\text{note}}$$"| C("$$\\phase{-78^\\circ}$$")
+ B --> D("$$x = \\begin{cases} a &\\text{if } b \\\\ c &\\text{if } d \\end{cases}$$")
+ C --> E("$$x(t)=c_1\\begin{bmatrix}-\\cos{t}+\\sin{t}\\\\ 2\\cos{t} \\end{bmatrix}e^{2t}$$")`,
+ { fontFamily: 'courier' }
+ );
+ });
+ it('2: should render a Katex flowchart containing the Greek alphabet', () => {
+ imgSnapshotTest(
+ `graph LR
+ A["$$\\alpha\\beta\\gamma\\delta\\epsilon\\zeta\\eta\\theta\\iota\\kappa\\lambda\\mu\\nu\\xi\\omicron\\pi\\rho\\sigma\\tau\\upsilon\\phi\\chi\\psi\\omega$$"] --> B["$$\\Alpha\\Beta\\Gamma\\Delta\\Epsilon\\Zeta\\Eta\\Theta\\Iota\\Kappa\\Lambda\\Mu\\Nu\\Xi\\Omicron\\Pi\\Rho\\Sigma\\Tau\\Upsilon\\Phi\\Chi\\Psi\\Omega$$"]`,
+ { fontFamily: 'courier' }
+ );
+ });
+ it('3: should render a Katex flowchart containing set theory symbols', () => {
+ imgSnapshotTest(
+ `graph LR
+ A["$$\\forall\\complement\\therefore\\emptyset\\exists\\subset\\because\\empty\\exist\\supset\\mapsto\\varnothing\\nexists\\mid\\to\\implies\\in\\land\\gets\\impliedby\\isin\\lor\\leftrightarrow\\iff\\notin\\ni\\notni\\lnot$$"] --> B["$$\\nabla\\Im\\Reals\\jmath\\partial\\image\\wp\\aleph\\Game\\weierp\\alef\\Finv\\N\\Z\\alefsym\\cnums\\natnums\\beth\\Complex\\R\\gimel\\ell\\Re\\daleth\\hbar\\real\\eth\\hslash\\reals$$"]`,
+ { fontFamily: 'courier' }
+ );
+ });
+ // TODO: changes made to develop between Feb 13 - Feb 23 cause this test to no longer function
+ // it.skip('4: should render an error box originating from Katex', () => {
+ // imgSnapshotTest(
+ // `graph LR
+ // A["$$\\shouldBeError$$"]`,
+ // { fontFamily: 'courier' }
+ // );
+ // });
+});
diff --git a/cypress/integration/rendering/packet.spec.ts b/cypress/integration/rendering/packet.spec.ts
new file mode 100644
index 000000000..61555ea53
--- /dev/null
+++ b/cypress/integration/rendering/packet.spec.ts
@@ -0,0 +1,67 @@
+import { imgSnapshotTest } from '../../helpers/util';
+
+describe('packet structure', () => {
+ it('should render a simple packet diagram', () => {
+ imgSnapshotTest(
+ `packet-beta
+ title Hello world
+ 0-10: "hello"
+`
+ );
+ });
+
+ it('should render a complex packet diagram', () => {
+ imgSnapshotTest(
+ `packet-beta
+ 0-15: "Source Port"
+ 16-31: "Destination Port"
+ 32-63: "Sequence Number"
+ 64-95: "Acknowledgment Number"
+ 96-99: "Data Offset"
+ 100-105: "Reserved"
+ 106: "URG"
+ 107: "ACK"
+ 108: "PSH"
+ 109: "RST"
+ 110: "SYN"
+ 111: "FIN"
+ 112-127: "Window"
+ 128-143: "Checksum"
+ 144-159: "Urgent Pointer"
+ 160-191: "(Options and Padding)"
+ 192-223: "data"
+ `
+ );
+ });
+
+ it('should render a complex packet diagram with showBits false', () => {
+ imgSnapshotTest(
+ `
+ ---
+ title: "Packet Diagram"
+ config:
+ packet:
+ showBits: false
+ ---
+ packet-beta
+ 0-15: "Source Port"
+ 16-31: "Destination Port"
+ 32-63: "Sequence Number"
+ 64-95: "Acknowledgment Number"
+ 96-99: "Data Offset"
+ 100-105: "Reserved"
+ 106: "URG"
+ 107: "ACK"
+ 108: "PSH"
+ 109: "RST"
+ 110: "SYN"
+ 111: "FIN"
+ 112-127: "Window"
+ 128-143: "Checksum"
+ 144-159: "Urgent Pointer"
+ 160-191: "(Options and Padding)"
+ 192-223: "data"
+ `
+ );
+ });
+});
diff --git a/cypress/integration/rendering/sequencediagram.spec.js b/cypress/integration/rendering/sequencediagram.spec.js
index 10432f057..a81f18a2d 100644
--- a/cypress/integration/rendering/sequencediagram.spec.js
+++ b/cypress/integration/rendering/sequencediagram.spec.js
@@ -375,6 +375,29 @@ context('Sequence diagram', () => {
{}
);
});
+ it('should have actor-top and actor-bottom classes on top and bottom actor box and symbol and actor-box and actor-man classes for text tags', () => {
+ imgSnapshotTest(
+ `
+ sequenceDiagram
+ actor Bob
+ Alice->>Bob: Hi Bob
+ Bob->>Alice: Hi Alice
+ `,
+ {}
+ );
+ cy.get('.actor').should('have.class', 'actor-top');
+ cy.get('.actor-man').should('have.class', 'actor-top');
+ cy.get('.actor.actor-top').should('not.have.class', 'actor-bottom');
+ cy.get('.actor-man.actor-top').should('not.have.class', 'actor-bottom');
+
+ cy.get('.actor').should('have.class', 'actor-bottom');
+ cy.get('.actor-man').should('have.class', 'actor-bottom');
+ cy.get('.actor.actor-bottom').should('not.have.class', 'actor-top');
+ cy.get('.actor-man.actor-bottom').should('not.have.class', 'actor-top');
+
+ cy.get('text.actor-box').should('include.text', 'Alice');
+ cy.get('text.actor-man').should('include.text', 'Bob');
+ });
it('should render long notes left of actor', () => {
imgSnapshotTest(
`
diff --git a/cypress/platform/e2e.html b/cypress/platform/e2e.html
index 949fa5798..d80caf7a4 100644
--- a/cypress/platform/e2e.html
+++ b/cypress/platform/e2e.html
@@ -1,7 +1,7 @@
-
+
-->
+
+
diff --git a/cypress/platform/iife.html b/cypress/platform/iife.html
new file mode 100644
index 000000000..7122785fc
--- /dev/null
+++ b/cypress/platform/iife.html
@@ -0,0 +1,29 @@
+
+
+
+graph TB
+ a --> b
+ a --> c
+ b --> d
+ c --> d
+
+
+
+
+
+
+
+
diff --git a/cypress/platform/interaction.html b/cypress/platform/interaction.html
index 59aadcbbb..a9fe7266b 100644
--- a/cypress/platform/interaction.html
+++ b/cypress/platform/interaction.html
@@ -17,20 +17,20 @@
graph TB
Function-->URL
click Function clickByFlow "Add a div"
- click URL "http://localhost:9000/webpackUsage.html" "Visit mermaid docs "
+ click URL "http://localhost:9000/info.html" "Visit mermaid docs "
graph TB
1Function-->2URL
click 1Function clickByFlow "Add a div"
- click 2URL "http://localhost:9000/webpackUsage.html" "Visit mermaid docs "
+ click 2URL "http://localhost:9000/info.html" "Visit mermaid docs "
classDiagram
class Test
class ShapeLink
- link ShapeLink "http://localhost:9000/webpackUsage.html" "This is a tooltip for a link"
+ link ShapeLink "http://localhost:9000/info.html" "This is a tooltip for a link"
class ShapeCallback
callback ShapeCallback "clickByClass" "This is a tooltip for a callback"
@@ -42,7 +42,7 @@
classDiagram-v2
class ShapeLink
- link ShapeLink "http://localhost:9000/webpackUsage.html" "This is a tooltip for a link"
+ link ShapeLink "http://localhost:9000/info.html" "This is a tooltip for a link"
@@ -77,7 +77,7 @@
Calling a Callback (look at the console log) :cl2, after cl1, 3d
Calling a Callback with args :cl3, after cl1, 3d
- click cl1 href "http://localhost:9000/webpackUsage.html"
+ click cl1 href "http://localhost:9000/info.html"
click cl2 call clickByGantt()
click cl3 call clickByGantt("test1", test2, test3)
@@ -102,9 +102,15 @@
div.className = 'created-by-gant-click';
div.style = 'padding: 20px; background: green; color: white;';
div.innerText = 'Clicked By Gant';
- if (arg1) div.innerText += ' ' + arg1;
- if (arg2) div.innerText += ' ' + arg2;
- if (arg3) div.innerText += ' ' + arg3;
+ if (arg1) {
+ div.innerText += ' ' + arg1;
+ }
+ if (arg2) {
+ div.innerText += ' ' + arg2;
+ }
+ if (arg3) {
+ div.innerText += ' ' + arg3;
+ }
document.getElementsByTagName('body')[0].appendChild(div);
}
diff --git a/cypress/platform/knsv2.html b/cypress/platform/knsv2.html
index 020ea8b48..f77f6b0e7 100644
--- a/cypress/platform/knsv2.html
+++ b/cypress/platform/knsv2.html
@@ -17,24 +17,30 @@
-
-
-
-
-
-