mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-18 14:59:53 +02:00
Compare commits
46 Commits
sidv/runTi
...
release/10
Author | SHA1 | Date | |
---|---|---|---|
![]() |
8d815f878c | ||
![]() |
dab26df9c4 | ||
![]() |
c7fe9a6465 | ||
![]() |
4f26f3ae2e | ||
![]() |
a536484408 | ||
![]() |
76801ff564 | ||
![]() |
f2d3ac1e7b | ||
![]() |
edad740e15 | ||
![]() |
a2e3b4ca06 | ||
![]() |
909ad02a18 | ||
![]() |
4a930d2b5b | ||
![]() |
4a19103891 | ||
![]() |
2d91aa0b06 | ||
![]() |
aca0bebaf4 | ||
![]() |
46d20c9968 | ||
![]() |
de1b2c31a1 | ||
![]() |
1f9cbe218f | ||
![]() |
6502036be9 | ||
![]() |
f86da19362 | ||
![]() |
b04e150dc1 | ||
![]() |
1c0c374c29 | ||
![]() |
33287a63ad | ||
![]() |
3134a87e72 | ||
![]() |
447263ecc2 | ||
![]() |
08a7f662ea | ||
![]() |
6422175ef2 | ||
![]() |
32ca0b97fc | ||
![]() |
244b161032 | ||
![]() |
cd3d560e8d | ||
![]() |
c0497d3413 | ||
![]() |
e6d80c60fb | ||
![]() |
8f457815e9 | ||
![]() |
3926594c6a | ||
![]() |
dbeb0a4720 | ||
![]() |
da33867ad7 | ||
![]() |
539010c65c | ||
![]() |
cbe44a6cff | ||
![]() |
b077fedd4c | ||
![]() |
38fcc2847b | ||
![]() |
2caeb9db47 | ||
![]() |
f9c359e70c | ||
![]() |
24528c1426 | ||
![]() |
df026c795d | ||
![]() |
077b1a5d8a | ||
![]() |
31686802b3 | ||
![]() |
b96eaed6f4 |
@@ -1,30 +0,0 @@
|
||||
/**
|
||||
* 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;
|
@@ -1,5 +0,0 @@
|
||||
import { generate } from 'langium-cli';
|
||||
|
||||
export async function generateLangium() {
|
||||
await generate({ file: `./packages/parser/langium-config.json` });
|
||||
}
|
@@ -1,124 +0,0 @@
|
||||
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<MermaidConfig>) {
|
||||
const ajv = new Ajv2019({
|
||||
useDefaults: true,
|
||||
allowUnionTypes: true,
|
||||
strict: true,
|
||||
});
|
||||
|
||||
ajv.addKeyword({
|
||||
keyword: 'meta:enum', // used by jsonschema2md
|
||||
errors: false,
|
||||
});
|
||||
ajv.addKeyword({
|
||||
keyword: 'tsType', // used by json-schema-to-typescript
|
||||
errors: false,
|
||||
});
|
||||
|
||||
// ajv currently doesn't support nested default values, see https://github.com/ajv-validator/ajv/issues/1718
|
||||
// (may be fixed in v9) so we need to manually use sub-schemas
|
||||
const mermaidDefaultConfig = {};
|
||||
|
||||
assert.ok(mermaidConfigSchema.$defs);
|
||||
const baseDiagramConfig = mermaidConfigSchema.$defs.BaseDiagramConfig;
|
||||
|
||||
for (const key of MERMAID_CONFIG_DIAGRAM_KEYS) {
|
||||
const subSchemaRef = mermaidConfigSchema.properties[key].$ref;
|
||||
const [root, defs, defName] = subSchemaRef.split('/');
|
||||
assert.strictEqual(root, '#');
|
||||
assert.strictEqual(defs, '$defs');
|
||||
const subSchema = {
|
||||
$schema: mermaidConfigSchema.$schema,
|
||||
$defs: mermaidConfigSchema.$defs,
|
||||
...mermaidConfigSchema.$defs[defName],
|
||||
} as JSONSchemaType<BaseDiagramConfig>;
|
||||
|
||||
const validate = ajv.compile(subSchema);
|
||||
|
||||
mermaidDefaultConfig[key] = {};
|
||||
|
||||
for (const required of subSchema.required ?? []) {
|
||||
if (subSchema.properties[required] === undefined && baseDiagramConfig.properties[required]) {
|
||||
mermaidDefaultConfig[key][required] = baseDiagramConfig.properties[required].default;
|
||||
}
|
||||
}
|
||||
if (!validate(mermaidDefaultConfig[key])) {
|
||||
throw new Error(
|
||||
`schema for subconfig ${key} does not have valid defaults! Errors were ${JSON.stringify(
|
||||
validate.errors,
|
||||
undefined,
|
||||
2
|
||||
)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const validate = ajv.compile(mermaidConfigSchema);
|
||||
|
||||
if (!validate(mermaidDefaultConfig)) {
|
||||
throw new Error(
|
||||
`Mermaid config JSON Schema does not have valid defaults! Errors were ${JSON.stringify(
|
||||
validate.errors,
|
||||
undefined,
|
||||
2
|
||||
)}`
|
||||
);
|
||||
}
|
||||
|
||||
return mermaidDefaultConfig;
|
||||
}
|
||||
|
||||
export const loadSchema = (src: string, filename: string): JSONSchemaType<MermaidConfig> => {
|
||||
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<MermaidConfig>;
|
||||
return jsonSchema;
|
||||
};
|
||||
|
||||
export const getDefaults = (schema: JSONSchemaType<MermaidConfig>) => {
|
||||
return `export default ${JSON.stringify(generateDefaults(schema), undefined, 2)};`;
|
||||
};
|
||||
|
||||
export const getSchema = (schema: JSONSchemaType<MermaidConfig>) => {
|
||||
return `export default ${JSON.stringify(schema, undefined, 2)};`;
|
||||
};
|
@@ -1,18 +0,0 @@
|
||||
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);
|
||||
}
|
@@ -53,7 +53,6 @@ GENERICTYPE
|
||||
getBoundarys
|
||||
grammr
|
||||
graphtype
|
||||
iife
|
||||
interp
|
||||
introdcued
|
||||
INVTRAPEND
|
||||
@@ -75,20 +74,17 @@ loglevel
|
||||
LOGMSG
|
||||
lookaheads
|
||||
mdast
|
||||
metafile
|
||||
minlen
|
||||
Mstartx
|
||||
MULT
|
||||
NODIR
|
||||
NSTR
|
||||
outdir
|
||||
Qcontrolx
|
||||
reinit
|
||||
rels
|
||||
reqs
|
||||
rewritelinks
|
||||
rgba
|
||||
runtimes
|
||||
RIGHTOF
|
||||
sankey
|
||||
sequencenumber
|
||||
|
@@ -1,65 +0,0 @@
|
||||
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();
|
@@ -1,15 +0,0 @@
|
||||
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: [] };
|
||||
});
|
||||
},
|
||||
};
|
@@ -1,35 +0,0 @@
|
||||
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<MermaidConfig> | 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<MermaidConfig> =
|
||||
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;
|
@@ -1,102 +0,0 @@
|
||||
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();
|
101
.esbuild/util.ts
101
.esbuild/util.ts
@@ -1,101 +0,0 @@
|
||||
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<MermaidBuildOptions, 'entryName'> = {
|
||||
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;
|
||||
};
|
@@ -6,6 +6,3 @@ cypress/plugins/index.js
|
||||
coverage
|
||||
*.json
|
||||
node_modules
|
||||
|
||||
# autogenereated by langium-cli
|
||||
generated/
|
||||
|
1
.github/codecov.yaml
vendored
1
.github/codecov.yaml
vendored
@@ -15,4 +15,3 @@ coverage:
|
||||
# Turing off for now as code coverage isn't stable and causes unnecessary build failures.
|
||||
# default:
|
||||
# threshold: 2%
|
||||
patch: off
|
||||
|
2
.github/lychee.toml
vendored
2
.github/lychee.toml
vendored
@@ -40,7 +40,7 @@ exclude = [
|
||||
# BundlePhobia has frequent downtime
|
||||
"https://bundlephobia.com",
|
||||
|
||||
# Chrome webstore redirect issue
|
||||
# Chrome webstore migration issue. Temporary
|
||||
"https://chromewebstore.google.com"
|
||||
]
|
||||
|
||||
|
83
.github/workflows/e2e.yml
vendored
83
.github/workflows/e2e.yml
vendored
@@ -15,7 +15,6 @@ on:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
env:
|
||||
# For PRs and MergeQueues, the target commit is used, and for push events, github.event.previous is used.
|
||||
@@ -49,35 +48,15 @@ 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: Build
|
||||
if: ${{ steps.cache-snapshot.outputs.cache-hit != 'true' && github.event_name == 'pull_request' }}
|
||||
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@v6
|
||||
uses: cypress-io/github-action@v4
|
||||
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
|
||||
|
||||
- name: Move runtime data
|
||||
if: ${{ steps.cache-snapshot.outputs.cache-hit != 'true' }}
|
||||
run: |
|
||||
mv cypress/snapshots/runtimes/current cypress/snapshots/runtimes/base
|
||||
|
||||
e2e:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
@@ -107,42 +86,15 @@ jobs:
|
||||
path: ./cypress/snapshots
|
||||
key: ${{ runner.os }}-snapshots-${{ env.targetHash }}
|
||||
|
||||
- name: Install dependencies
|
||||
uses: cypress-io/github-action@v6
|
||||
with:
|
||||
runTests: false
|
||||
|
||||
- name: Build
|
||||
id: size
|
||||
if: ${{ github.event_name == 'pull_request' && matrix.containers == 1 }}
|
||||
run: |
|
||||
pnpm run build:viz
|
||||
mv stats cypress/snapshots/stats/head
|
||||
{
|
||||
echo 'size_diff<<EOF'
|
||||
npx tsx scripts/size.ts
|
||||
echo EOF
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
# Size diff only needs to be posted from one job, on PRs.
|
||||
- name: Comment PR size difference
|
||||
if: ${{ github.event_name == 'pull_request' && matrix.containers == 1 }}
|
||||
uses: thollander/actions-comment-pull-request@v2
|
||||
with:
|
||||
message: |
|
||||
${{ steps.size.outputs.size_diff }}
|
||||
comment_tag: size-diff
|
||||
|
||||
# Install NPM dependencies, cache them correctly
|
||||
# and run all Cypress tests
|
||||
- name: Cypress run
|
||||
uses: cypress-io/github-action@v6
|
||||
uses: cypress-io/github-action@v4
|
||||
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
|
||||
@@ -181,16 +133,6 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ always() }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: pnpm/action-setup@v2
|
||||
# uses version from "packageManager" field in package.json
|
||||
|
||||
- name: Setup Node.js 18.x
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.x
|
||||
|
||||
# Download all snapshot artifacts and merge them into a single folder
|
||||
- name: Download All Artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
@@ -199,27 +141,6 @@ jobs:
|
||||
pattern: snapshots-*
|
||||
merge-multiple: true
|
||||
|
||||
- name: Build
|
||||
id: runtime
|
||||
if: ${{ needs.e2e.result != 'failure' && github.event_name == 'pull_request' }}
|
||||
run: |
|
||||
mv ./snapshots/runtimes/current ./snapshots/runtimes/head
|
||||
npm config set ignore-scripts true
|
||||
pnpm install --frozen-lockfile
|
||||
{
|
||||
echo 'runtime_diff<<EOF'
|
||||
npx tsx scripts/runTime.ts ./snapshots
|
||||
echo EOF
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Comment PR runtime difference
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
uses: thollander/actions-comment-pull-request@v2
|
||||
with:
|
||||
message: |
|
||||
${{ steps.runtime.outputs.runtime_diff }}
|
||||
comment_tag: size-diff
|
||||
|
||||
# For successful push events, we save the snapshots cache
|
||||
- name: Save snapshots cache
|
||||
id: cache-upload
|
||||
|
2
.github/workflows/release-draft.yml
vendored
2
.github/workflows/release-draft.yml
vendored
@@ -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
|
||||
|
5
.gitignore
vendored
5
.gitignore
vendored
@@ -29,7 +29,6 @@ Gemfile.lock
|
||||
|
||||
cypress/screenshots/
|
||||
cypress/snapshots/
|
||||
cypress/runtimes/
|
||||
|
||||
# eslint --cache file
|
||||
.eslintcache
|
||||
@@ -47,8 +46,4 @@ stats/
|
||||
|
||||
demos/dev/**
|
||||
!/demos/dev/example.html
|
||||
!/demos/dev/reload.js
|
||||
tsx-0/**
|
||||
|
||||
# autogenereated by langium-cli
|
||||
generated/
|
||||
|
@@ -11,8 +11,6 @@ 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
|
||||
|
@@ -3,12 +3,11 @@ 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');
|
||||
@@ -37,6 +36,24 @@ 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;
|
||||
@@ -55,8 +72,34 @@ 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: {
|
||||
@@ -86,7 +129,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__', 'generated'],
|
||||
exclude: ['node_modules', 'test/', '__mocks__'],
|
||||
extension: ['.js', '.ts'],
|
||||
requireEnv: true,
|
||||
forceBuildInstrument: coverage,
|
||||
@@ -106,28 +149,24 @@ 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' || pkg === 'parser'
|
||||
)) {
|
||||
for (const pkg of packageNames.filter((pkg) => !mermaidOnly || pkg === 'mermaid')) {
|
||||
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 {
|
||||
|
@@ -1,10 +1,10 @@
|
||||
import { transformJison } from '../.build/jisonTransformer.js';
|
||||
|
||||
import { transformJison } from './jisonTransformer.js';
|
||||
const fileRegex = /\.(jison)$/;
|
||||
|
||||
export default function jison() {
|
||||
return {
|
||||
name: 'jison',
|
||||
|
||||
transform(src: string, id: string) {
|
||||
if (fileRegex.test(id)) {
|
||||
return {
|
||||
|
@@ -1,5 +1,110 @@
|
||||
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 { getDefaults, getSchema, loadSchema } from '../.build/jsonSchema.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',
|
||||
] as const;
|
||||
|
||||
/**
|
||||
* Generate default values from the JSON Schema.
|
||||
*
|
||||
* AJV does not support nested default values yet (or default values with $ref),
|
||||
* so we need to manually find them (this may be fixed in ajv v9).
|
||||
*
|
||||
* @param mermaidConfigSchema - The Mermaid JSON Schema to use.
|
||||
* @returns The default mermaid config object.
|
||||
*/
|
||||
function generateDefaults(mermaidConfigSchema: JSONSchemaType<MermaidConfig>) {
|
||||
const ajv = new Ajv2019({
|
||||
useDefaults: true,
|
||||
allowUnionTypes: true,
|
||||
strict: true,
|
||||
});
|
||||
|
||||
ajv.addKeyword({
|
||||
keyword: 'meta:enum', // used by jsonschema2md
|
||||
errors: false,
|
||||
});
|
||||
ajv.addKeyword({
|
||||
keyword: 'tsType', // used by json-schema-to-typescript
|
||||
errors: false,
|
||||
});
|
||||
|
||||
// ajv currently doesn't support nested default values, see https://github.com/ajv-validator/ajv/issues/1718
|
||||
// (may be fixed in v9) so we need to manually use sub-schemas
|
||||
const mermaidDefaultConfig = {};
|
||||
|
||||
assert.ok(mermaidConfigSchema.$defs);
|
||||
const baseDiagramConfig = mermaidConfigSchema.$defs.BaseDiagramConfig;
|
||||
|
||||
for (const key of MERMAID_CONFIG_DIAGRAM_KEYS) {
|
||||
const subSchemaRef = mermaidConfigSchema.properties[key].$ref;
|
||||
const [root, defs, defName] = subSchemaRef.split('/');
|
||||
assert.strictEqual(root, '#');
|
||||
assert.strictEqual(defs, '$defs');
|
||||
const subSchema = {
|
||||
$schema: mermaidConfigSchema.$schema,
|
||||
$defs: mermaidConfigSchema.$defs,
|
||||
...mermaidConfigSchema.$defs[defName],
|
||||
} as JSONSchemaType<BaseDiagramConfig>;
|
||||
|
||||
const validate = ajv.compile(subSchema);
|
||||
|
||||
mermaidDefaultConfig[key] = {};
|
||||
|
||||
for (const required of subSchema.required ?? []) {
|
||||
if (subSchema.properties[required] === undefined && baseDiagramConfig.properties[required]) {
|
||||
mermaidDefaultConfig[key][required] = baseDiagramConfig.properties[required].default;
|
||||
}
|
||||
}
|
||||
if (!validate(mermaidDefaultConfig[key])) {
|
||||
throw new Error(
|
||||
`schema for subconfig ${key} does not have valid defaults! Errors were ${JSON.stringify(
|
||||
validate.errors,
|
||||
undefined,
|
||||
2
|
||||
)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const validate = ajv.compile(mermaidConfigSchema);
|
||||
|
||||
if (!validate(mermaidDefaultConfig)) {
|
||||
throw new Error(
|
||||
`Mermaid config JSON Schema does not have valid defaults! Errors were ${JSON.stringify(
|
||||
validate.errors,
|
||||
undefined,
|
||||
2
|
||||
)}`
|
||||
);
|
||||
}
|
||||
|
||||
return mermaidDefaultConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vite plugin that handles JSON Schemas saved as a `.schema.yaml` file.
|
||||
@@ -16,13 +121,32 @@ export default function jsonSchemaPlugin(): PluginOption {
|
||||
return;
|
||||
}
|
||||
|
||||
const jsonSchema = loadSchema(src, idAsUrl.pathname);
|
||||
return {
|
||||
code: idAsUrl.searchParams.get('only-defaults')
|
||||
? getDefaults(jsonSchema)
|
||||
: getSchema(jsonSchema),
|
||||
map: null, // no source map
|
||||
};
|
||||
if (idAsUrl.searchParams.get('only-defaults')) {
|
||||
const jsonSchema = load(src, {
|
||||
filename: idAsUrl.pathname,
|
||||
// only allow JSON types in our YAML doc (will probably be default in YAML 1.3)
|
||||
// e.g. `true` will be parsed a boolean `true`, `True` will be parsed as string `"True"`.
|
||||
schema: JSON_SCHEMA,
|
||||
}) as JSONSchemaType<MermaidConfig>;
|
||||
return {
|
||||
code: `export default ${JSON.stringify(generateDefaults(jsonSchema), undefined, 2)};`,
|
||||
map: null, // no source map
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: `export default ${JSON.stringify(
|
||||
load(src, {
|
||||
filename: idAsUrl.pathname,
|
||||
// only allow JSON types in our YAML doc (will probably be default in YAML 1.3)
|
||||
// e.g. `true` will be parsed a boolean `true`, `True` will be parsed as string `"True"`.
|
||||
schema: JSON_SCHEMA,
|
||||
}),
|
||||
undefined,
|
||||
2
|
||||
)};`,
|
||||
map: null, // provide source map if available
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@@ -1,7 +1,6 @@
|
||||
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();
|
||||
@@ -15,9 +14,9 @@ async function createServer() {
|
||||
});
|
||||
|
||||
app.use(cors());
|
||||
for (const { packageName } of Object.values(packageOptions)) {
|
||||
app.use(express.static(`./packages/${packageName}/dist`));
|
||||
}
|
||||
app.use(express.static('./packages/mermaid/dist'));
|
||||
app.use(express.static('./packages/mermaid-zenuml/dist'));
|
||||
app.use(express.static('./packages/mermaid-example-diagram/dist'));
|
||||
app.use(vite.middlewares);
|
||||
app.use(express.static('demos'));
|
||||
app.use(express.static('cypress/platform'));
|
||||
|
21
__mocks__/c4Renderer.js
Normal file
21
__mocks__/c4Renderer.js
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* 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,
|
||||
};
|
16
__mocks__/classRenderer-v2.js
Normal file
16
__mocks__/classRenderer-v2.js
Normal file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* 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,
|
||||
};
|
13
__mocks__/classRenderer.js
Normal file
13
__mocks__/classRenderer.js
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Mocked class diagram renderer
|
||||
*/
|
||||
|
||||
import { vi } from 'vitest';
|
||||
|
||||
export const draw = vi.fn().mockImplementation(() => {
|
||||
return '';
|
||||
});
|
||||
|
||||
export default {
|
||||
draw,
|
||||
};
|
1
__mocks__/dagre-d3.ts
Normal file
1
__mocks__/dagre-d3.ts
Normal file
@@ -0,0 +1 @@
|
||||
// DO NOT delete this file. It is used by vitest to mock the dagre-d3 module.
|
3
__mocks__/entity-decode/browser.ts
Normal file
3
__mocks__/entity-decode/browser.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = function (txt: string) {
|
||||
return txt;
|
||||
};
|
16
__mocks__/erRenderer.js
Normal file
16
__mocks__/erRenderer.js
Normal file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Mocked er diagram renderer
|
||||
*/
|
||||
|
||||
import { vi } from 'vitest';
|
||||
|
||||
export const setConf = vi.fn();
|
||||
|
||||
export const draw = vi.fn().mockImplementation(() => {
|
||||
return '';
|
||||
});
|
||||
|
||||
export default {
|
||||
setConf,
|
||||
draw,
|
||||
};
|
24
__mocks__/flowRenderer-v2.js
Normal file
24
__mocks__/flowRenderer-v2.js
Normal file
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* 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,
|
||||
};
|
16
__mocks__/ganttRenderer.js
Normal file
16
__mocks__/ganttRenderer.js
Normal file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Mocked gantt diagram renderer
|
||||
*/
|
||||
|
||||
import { vi } from 'vitest';
|
||||
|
||||
export const setConf = vi.fn();
|
||||
|
||||
export const draw = vi.fn().mockImplementation(() => {
|
||||
return '';
|
||||
});
|
||||
|
||||
export default {
|
||||
setConf,
|
||||
draw,
|
||||
};
|
13
__mocks__/gitGraphRenderer.js
Normal file
13
__mocks__/gitGraphRenderer.js
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Mocked git (graph) diagram renderer
|
||||
*/
|
||||
|
||||
import { vi } from 'vitest';
|
||||
|
||||
export const draw = vi.fn().mockImplementation(() => {
|
||||
return '';
|
||||
});
|
||||
|
||||
export default {
|
||||
draw,
|
||||
};
|
15
__mocks__/journeyRenderer.js
Normal file
15
__mocks__/journeyRenderer.js
Normal file
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* 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,
|
||||
};
|
8
__mocks__/pieRenderer.ts
Normal file
8
__mocks__/pieRenderer.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Mocked pie (picChart) diagram renderer
|
||||
*/
|
||||
import { vi } from 'vitest';
|
||||
|
||||
const draw = vi.fn().mockImplementation(() => '');
|
||||
|
||||
export const renderer = { draw };
|
13
__mocks__/requirementRenderer.js
Normal file
13
__mocks__/requirementRenderer.js
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Mocked requirement diagram renderer
|
||||
*/
|
||||
|
||||
import { vi } from 'vitest';
|
||||
|
||||
export const draw = vi.fn().mockImplementation(() => {
|
||||
return '';
|
||||
});
|
||||
|
||||
export default {
|
||||
draw,
|
||||
};
|
13
__mocks__/sankeyRenderer.js
Normal file
13
__mocks__/sankeyRenderer.js
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Mocked Sankey diagram renderer
|
||||
*/
|
||||
|
||||
import { vi } from 'vitest';
|
||||
|
||||
export const draw = vi.fn().mockImplementation(() => {
|
||||
return '';
|
||||
});
|
||||
|
||||
export default {
|
||||
draw,
|
||||
};
|
23
__mocks__/sequenceRenderer.js
Normal file
23
__mocks__/sequenceRenderer.js
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* 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,
|
||||
};
|
22
__mocks__/stateRenderer-v2.js
Normal file
22
__mocks__/stateRenderer-v2.js
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 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,
|
||||
};
|
@@ -1,6 +1,4 @@
|
||||
import { defineConfig } from 'cypress';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { addMatchImageSnapshotPlugin } from 'cypress-image-snapshot/plugin';
|
||||
import coverage from '@cypress/code-coverage/task';
|
||||
import eyesPlugin from '@applitools/eyes-cypress';
|
||||
@@ -19,19 +17,6 @@ export default eyesPlugin(
|
||||
}
|
||||
return launchOptions;
|
||||
});
|
||||
on('task', {
|
||||
recordRenderTime({ fileName, testName, timeTaken }) {
|
||||
const resultsPath = path.join('cypress', 'snapshots', 'runtimes', 'current');
|
||||
if (!fs.existsSync(resultsPath)) {
|
||||
fs.mkdirSync(resultsPath, { recursive: true });
|
||||
}
|
||||
fs.appendFileSync(
|
||||
path.join(resultsPath, `${fileName}.csv`),
|
||||
`${testName},${timeTaken}\n`
|
||||
);
|
||||
return true;
|
||||
},
|
||||
});
|
||||
addMatchImageSnapshotPlugin(on, config);
|
||||
// copy any needed variables from process.env to config.env
|
||||
config.env.useAppli = process.env.USE_APPLI ? true : false;
|
||||
|
@@ -110,14 +110,6 @@ export const openURLAndVerifyRendering = (
|
||||
|
||||
cy.visit(url);
|
||||
cy.window().should('have.property', 'rendered', true);
|
||||
cy.window().then((win) => {
|
||||
cy.task('recordRenderTime', {
|
||||
fileName: Cypress.spec.name,
|
||||
testName: name,
|
||||
// @ts-ignore Dynamically added property.
|
||||
timeTaken: win.renderTime,
|
||||
});
|
||||
});
|
||||
cy.get('svg').should('be.visible');
|
||||
|
||||
if (validation) {
|
||||
|
@@ -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',
|
||||
});
|
||||
});
|
||||
});
|
@@ -1,11 +0,0 @@
|
||||
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');
|
||||
});
|
||||
});
|
16
cypress/integration/other/webpackUsage.spec.js
Normal file
16
cypress/integration/other/webpackUsage.spec.js
Normal file
@@ -0,0 +1,16 @@
|
||||
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', '<b>');
|
||||
});
|
||||
});
|
@@ -137,4 +137,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');
|
||||
});
|
||||
});
|
||||
|
@@ -1,67 +0,0 @@
|
||||
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"
|
||||
`
|
||||
);
|
||||
});
|
||||
});
|
@@ -1,7 +1,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<script type="module" src="./viewer.js"></script>
|
||||
<script src="./viewer.js" type="module"></script>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
rel="stylesheet"
|
||||
|
@@ -11,7 +11,8 @@ example-diagram
|
||||
<!-- <script src="//cdn.jsdelivr.net/npm/mermaid@9.1.7/dist/mermaid.min.js"></script> -->
|
||||
<!-- <script type="module" src="./external-diagrams-mindmap.mjs" /> -->
|
||||
<script type="module">
|
||||
import exampleDiagram from './mermaid-example-diagram.esm.mjs';
|
||||
import exampleDiagram from '../../packages/mermaid-example-diagram/dist/mermaid-example-diagram.core.mjs';
|
||||
// import example from '../../packages/mermaid-example-diagram/src/detector';
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
|
||||
await mermaid.registerExternalDiagrams([exampleDiagram]);
|
||||
|
@@ -1,28 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
<pre class="mermaid">
|
||||
flowchart-elk
|
||||
a[hello] --> b[world]
|
||||
b --> c{test}
|
||||
c --> one
|
||||
c --> two
|
||||
c --> three
|
||||
</pre>
|
||||
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
import elk from './mermaid-flowchart-elk.esm.min.mjs';
|
||||
if (window.location.search.includes('elk')) {
|
||||
await mermaid.registerExternalDiagrams([elk]);
|
||||
}
|
||||
mermaid.initialize({
|
||||
logLevel: 3,
|
||||
startOnLoad: false,
|
||||
});
|
||||
await mermaid.run();
|
||||
if (window.Cypress) {
|
||||
window.rendered = true;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@@ -1,29 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
<pre id="diagram" class="mermaid">
|
||||
graph TB
|
||||
a --> b
|
||||
a --> c
|
||||
b --> d
|
||||
c --> d
|
||||
</pre>
|
||||
|
||||
<div id="d2"></div>
|
||||
|
||||
<script src="/mermaid.min.js"></script>
|
||||
<script>
|
||||
mermaid.initialize({
|
||||
startOnLoad: true,
|
||||
});
|
||||
const value = `graph TD\nHello --> World`;
|
||||
const el = document.getElementById('d2');
|
||||
mermaid.render('did', value).then(({ svg }) => {
|
||||
console.log(svg);
|
||||
el.innerHTML = svg;
|
||||
if (window.Cypress) {
|
||||
window.rendered = true;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@@ -17,20 +17,20 @@
|
||||
graph TB
|
||||
Function-->URL
|
||||
click Function clickByFlow "Add a div"
|
||||
click URL "http://localhost:9000/info.html" "Visit <strong>mermaid docs</strong>"
|
||||
click URL "http://localhost:9000/webpackUsage.html" "Visit <strong>mermaid docs</strong>"
|
||||
</pre>
|
||||
<pre id="FirstLine" class="mermaid2">
|
||||
graph TB
|
||||
1Function-->2URL
|
||||
click 1Function clickByFlow "Add a div"
|
||||
click 2URL "http://localhost:9000/info.html" "Visit <strong>mermaid docs</strong>"
|
||||
click 2URL "http://localhost:9000/webpackUsage.html" "Visit <strong>mermaid docs</strong>"
|
||||
</pre>
|
||||
|
||||
<pre id="FirstLine" class="mermaid2">
|
||||
classDiagram
|
||||
class Test
|
||||
class ShapeLink
|
||||
link ShapeLink "http://localhost:9000/info.html" "This is a tooltip for a link"
|
||||
link ShapeLink "http://localhost:9000/webpackUsage.html" "This is a tooltip for a link"
|
||||
class ShapeCallback
|
||||
callback ShapeCallback "clickByClass" "This is a tooltip for a callback"
|
||||
</pre>
|
||||
@@ -42,7 +42,7 @@
|
||||
<pre id="FirstLine" class="mermaid">
|
||||
classDiagram-v2
|
||||
class ShapeLink
|
||||
link ShapeLink "http://localhost:9000/info.html" "This is a tooltip for a link"
|
||||
link ShapeLink "http://localhost:9000/webpackUsage.html" "This is a tooltip for a link"
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
@@ -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/info.html"
|
||||
click cl1 href "http://localhost:9000/webpackUsage.html"
|
||||
click cl2 call clickByGantt()
|
||||
click cl3 call clickByGantt("test1", test2, test3)
|
||||
|
||||
@@ -102,15 +102,9 @@
|
||||
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);
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
import externalExample from './mermaid-example-diagram.esm.mjs';
|
||||
import zenUml from './mermaid-zenuml.esm.mjs';
|
||||
import mermaid2 from './mermaid.esm.mjs';
|
||||
import externalExample from '../../packages/mermaid-example-diagram/dist/mermaid-example-diagram.core.mjs';
|
||||
import zenUml from '../../packages/mermaid-zenuml/dist/mermaid-zenuml.core.mjs';
|
||||
|
||||
function b64ToUtf8(str) {
|
||||
return decodeURIComponent(escape(window.atob(str)));
|
||||
@@ -8,7 +8,6 @@ function b64ToUtf8(str) {
|
||||
|
||||
// Adds a rendered flag to window when rendering is done, so cypress can wait for it.
|
||||
function markRendered() {
|
||||
window.renderTime = Date.now() - window.loadTime;
|
||||
if (window.Cypress) {
|
||||
window.rendered = true;
|
||||
}
|
||||
@@ -46,9 +45,9 @@ const contentLoaded = async function () {
|
||||
document.getElementsByTagName('body')[0].appendChild(div);
|
||||
}
|
||||
|
||||
await mermaid.registerExternalDiagrams([externalExample, zenUml]);
|
||||
mermaid.initialize(graphObj.mermaid);
|
||||
await mermaid.run();
|
||||
await mermaid2.registerExternalDiagrams([externalExample, zenUml]);
|
||||
mermaid2.initialize(graphObj.mermaid);
|
||||
await mermaid2.run();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -96,14 +95,18 @@ const contentLoadedApi = async function () {
|
||||
divs[i] = div;
|
||||
}
|
||||
|
||||
const defaultE2eCnf = { theme: 'forest', startOnLoad: false };
|
||||
const defaultE2eCnf = { theme: 'forest' };
|
||||
|
||||
const cnf = merge(defaultE2eCnf, graphObj.mermaid);
|
||||
|
||||
mermaid.initialize(cnf);
|
||||
mermaid2.initialize(cnf);
|
||||
|
||||
for (let i = 0; i < numCodes; i++) {
|
||||
const { svg, bindFunctions } = await mermaid.render('newid' + i, graphObj.code[i], divs[i]);
|
||||
const { svg, bindFunctions } = await mermaid2.render(
|
||||
'newid' + i,
|
||||
graphObj.code[i],
|
||||
divs[i]
|
||||
);
|
||||
div.innerHTML = svg;
|
||||
bindFunctions(div);
|
||||
}
|
||||
@@ -111,28 +114,24 @@ const contentLoadedApi = async function () {
|
||||
const div = document.createElement('div');
|
||||
div.id = 'block';
|
||||
div.className = 'mermaid';
|
||||
console.warn('graphObj', graphObj);
|
||||
console.warn('graphObj.mermaid', graphObj.mermaid);
|
||||
document.getElementsByTagName('body')[0].appendChild(div);
|
||||
mermaid.initialize(graphObj.mermaid);
|
||||
const { svg, bindFunctions } = await mermaid.render('newid', graphObj.code, div);
|
||||
mermaid2.initialize(graphObj.mermaid);
|
||||
|
||||
const { svg, bindFunctions } = await mermaid2.render('newid', graphObj.code, div);
|
||||
div.innerHTML = svg;
|
||||
console.log(div.innerHTML);
|
||||
bindFunctions(div);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof document !== 'undefined') {
|
||||
mermaid.initialize({
|
||||
startOnLoad: false,
|
||||
});
|
||||
/*!
|
||||
* Wait for document loaded before starting the execution
|
||||
*/
|
||||
window.addEventListener(
|
||||
'load',
|
||||
function () {
|
||||
this.window.loadTime = Date.now();
|
||||
if (this.location.href.match('xss.html')) {
|
||||
this.console.log('Using api');
|
||||
void contentLoadedApi().finally(markRendered);
|
||||
|
19
cypress/platform/webpackUsage.html
Normal file
19
cypress/platform/webpackUsage.html
Normal file
@@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
/* .mermaid {
|
||||
font-family: "trebuchet ms", verdana, arial;;
|
||||
} */
|
||||
/* .mermaid {
|
||||
font-family: 'arial';
|
||||
} */
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="graph-to-be"></div>
|
||||
<script type="module" charset="utf-8">
|
||||
import './bundle-test.js';
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@@ -1,5 +1,6 @@
|
||||
<html>
|
||||
<head>
|
||||
<script src="./viewer.js" type="module"></script>
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
|
||||
<style>
|
||||
.malware {
|
||||
@@ -32,6 +33,12 @@
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<script type="module" src="./viewer.js"></script>
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
mermaid.initialize({
|
||||
startOnLoad: false,
|
||||
useMaxWidth: true,
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
108
cypress/platform/xss25.html
Normal file
108
cypress/platform/xss25.html
Normal file
@@ -0,0 +1,108 @@
|
||||
<html>
|
||||
<head>
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<style>
|
||||
body {
|
||||
/* background: rgb(221, 208, 208); */
|
||||
/* background:#333; */
|
||||
font-family: 'Arial';
|
||||
/* font-size: 18px !important; */
|
||||
}
|
||||
h1 {
|
||||
color: grey;
|
||||
}
|
||||
.mermaid2 {
|
||||
display: none;
|
||||
}
|
||||
.mermaid svg {
|
||||
/* font-size: 18px !important; */
|
||||
}
|
||||
.malware {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 150px;
|
||||
background: red;
|
||||
color: black;
|
||||
display: flex;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family: monospace;
|
||||
font-size: 72px;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
function xssAttack() {
|
||||
const div = document.createElement('div');
|
||||
div.id = 'the-malware';
|
||||
div.className = 'malware';
|
||||
div.innerHTML = 'XSS Succeeded';
|
||||
document.getElementsByTagName('body')[0].appendChild(div);
|
||||
throw new Error('XSS Succeeded');
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div>Security check</div>
|
||||
<div class="flex">
|
||||
<div id="diagram" class="mermaid"></div>
|
||||
<div id="res" class=""></div>
|
||||
</div>
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
mermaid.parseError = function (err, hash) {
|
||||
// console.error('Mermaid error: ', err);
|
||||
};
|
||||
mermaid.initialize({
|
||||
theme: 'forest',
|
||||
arrowMarkerAbsolute: true,
|
||||
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
|
||||
logLevel: 0,
|
||||
state: {
|
||||
defaultRenderer: 'dagre-wrapper',
|
||||
},
|
||||
flowchart: {
|
||||
// defaultRenderer: 'dagre-wrapper',
|
||||
nodeSpacing: 10,
|
||||
curve: 'cardinal',
|
||||
htmlLabels: true,
|
||||
},
|
||||
htmlLabels: false,
|
||||
// gantt: { axisFormat: '%m/%d/%Y' },
|
||||
sequence: { actorFontFamily: 'courier', actorMargin: 50, showSequenceNumbers: false },
|
||||
// sequenceDiagram: { actorMargin: 300 } // deprecated
|
||||
// fontFamily: '"times", sans-serif',
|
||||
// fontFamily: 'courier',
|
||||
fontSize: 18,
|
||||
curve: 'basis',
|
||||
securityLevel: 'strict',
|
||||
startOnLoad: false,
|
||||
secure: ['secure', 'securityLevel', 'startOnLoad', 'maxTextSize'],
|
||||
// themeVariables: {relationLabelColor: 'red'}
|
||||
});
|
||||
function callback() {
|
||||
alert('It worked');
|
||||
}
|
||||
|
||||
let diagram = 'block-beta\n';
|
||||
diagram += '`A-- "X<img src=x on';
|
||||
diagram += 'error=xssAttack()>" -->B';
|
||||
|
||||
console.log(diagram);
|
||||
// document.querySelector('#diagram').innerHTML = diagram;
|
||||
const { svg } = await mermaid.render('diagram', diagram);
|
||||
document.querySelector('#res').innerHTML = svg;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@@ -3,22 +3,6 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Mermaid development page</title>
|
||||
<style>
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
#code {
|
||||
max-width: 30vw;
|
||||
width: 30vw;
|
||||
}
|
||||
|
||||
#dynamicDiagram {
|
||||
padding-left: 2em;
|
||||
flex: 1;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="diagram" class="mermaid">
|
||||
@@ -29,37 +13,22 @@ graph TB
|
||||
c --> d
|
||||
</pre>
|
||||
|
||||
<hr />
|
||||
Type code to view diagram:
|
||||
<div class="container">
|
||||
<textarea name="code" id="code" cols="30" rows="10"></textarea>
|
||||
<div id="dynamicDiagram"></div>
|
||||
</div>
|
||||
<pre class="mermaid">info</pre>
|
||||
<div id="dynamicDiagram"></div>
|
||||
|
||||
<script type="module">
|
||||
import mermaid from '/mermaid.esm.mjs';
|
||||
async function render(str) {
|
||||
const { svg } = await mermaid.render('dynamic', str);
|
||||
document.getElementById('dynamicDiagram').innerHTML = svg;
|
||||
}
|
||||
const storeKey = window.location.pathname;
|
||||
const code = localStorage.getItem(storeKey);
|
||||
if (code) {
|
||||
document.getElementById('code').value = code;
|
||||
await render(code);
|
||||
}
|
||||
mermaid.parseError = function (err, hash) {
|
||||
console.error('Mermaid error: ', err);
|
||||
};
|
||||
mermaid.initialize({
|
||||
startOnLoad: true,
|
||||
logLevel: 0,
|
||||
});
|
||||
document.getElementById('code').addEventListener('input', async (e) => {
|
||||
const value = e.target.value;
|
||||
localStorage.setItem(storeKey, value);
|
||||
await render(value);
|
||||
});
|
||||
const value = `graph TD\nHello --> World`;
|
||||
const el = document.getElementById('dynamicDiagram');
|
||||
const { svg } = await mermaid.render('dd', value);
|
||||
console.log(svg);
|
||||
el.innerHTML = svg;
|
||||
</script>
|
||||
|
||||
<script src="/dev/reload.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
@@ -1,22 +0,0 @@
|
||||
// Connect to the server and reload the page if the server sends a reload message
|
||||
const connectToEvents = () => {
|
||||
const events = new EventSource('/events');
|
||||
const loadTime = Date.now();
|
||||
events.onmessage = (event) => {
|
||||
const time = JSON.parse(event.data);
|
||||
if (time && time > loadTime) {
|
||||
location.reload();
|
||||
}
|
||||
};
|
||||
events.onerror = (error) => {
|
||||
console.error(error);
|
||||
events.close();
|
||||
// Try to reconnect after 1 second in case of errors
|
||||
setTimeout(connectToEvents, 1000);
|
||||
};
|
||||
events.onopen = () => {
|
||||
console.log('Connected to live reload server');
|
||||
};
|
||||
};
|
||||
|
||||
setTimeout(connectToEvents, 500);
|
@@ -1,35 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>Mermaid Flowchart ELK Test Page</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Flowchart ELK</h1>
|
||||
<pre class="mermaid">
|
||||
flowchart-elk TD
|
||||
A([Start]) ==> B[Step 1]
|
||||
B ==> C{Flow 1}
|
||||
C -- Choice 1.1 --> D[Step 2.1]
|
||||
C -- Choice 1.3 --> I[Step 2.3]
|
||||
C == Choice 1.2 ==> E[Step 2.2]
|
||||
D --> F{Flow 2}
|
||||
E ==> F{Flow 2}
|
||||
F{Flow 2} == Choice 2.1 ==> H[Feedback node]
|
||||
H[Feedback node] ==> B[Step 1]
|
||||
F{Flow 2} == Choice 2.2 ==> G((Finish))
|
||||
|
||||
</pre>
|
||||
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
import flowchartELK from './mermaid-flowchart-elk.esm.mjs';
|
||||
await mermaid.registerExternalDiagrams([flowchartELK]);
|
||||
mermaid.initialize({
|
||||
logLevel: 3,
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@@ -81,9 +81,6 @@
|
||||
<li>
|
||||
<h2><a href="./sankey.html">Sankey</a></h2>
|
||||
</li>
|
||||
<li>
|
||||
<h2><a href="./packet.html">Packet</a></h2>
|
||||
</li>
|
||||
<li>
|
||||
<h2><a href="./block.html">Layered Blocks</a></h2>
|
||||
</li>
|
||||
|
@@ -1,141 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>Mermaid Quick Test Page</title>
|
||||
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=" />
|
||||
<style>
|
||||
div.mermaid {
|
||||
font-family: 'Courier New', Courier, monospace !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Packet diagram demo</h1>
|
||||
|
||||
<div class="diagrams">
|
||||
<pre class="mermaid">
|
||||
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"
|
||||
</pre
|
||||
>
|
||||
|
||||
<pre class="mermaid">
|
||||
---
|
||||
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"
|
||||
</pre
|
||||
>
|
||||
|
||||
<pre class="mermaid">
|
||||
---
|
||||
config:
|
||||
theme: forest
|
||||
---
|
||||
packet-beta
|
||||
title Forest theme
|
||||
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"
|
||||
</pre
|
||||
>
|
||||
|
||||
<pre class="mermaid" style="background-color: black">
|
||||
---
|
||||
config:
|
||||
theme: dark
|
||||
---
|
||||
packet-beta
|
||||
title Dark theme
|
||||
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"
|
||||
</pre
|
||||
>
|
||||
</div>
|
||||
<script type="module">
|
||||
import mermaid from '/mermaid.esm.mjs';
|
||||
mermaid.initialize({
|
||||
logLevel: 3,
|
||||
securityLevel: 'loose',
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.diagrams {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
pre {
|
||||
width: 45vw;
|
||||
padding: 2em;
|
||||
}
|
||||
</style>
|
||||
</body>
|
||||
</html>
|
@@ -50,7 +50,7 @@
|
||||
</pre>
|
||||
|
||||
<script type="module">
|
||||
import mermaid from '/mermaid.esm.mjs';
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
mermaid.initialize({
|
||||
theme: 'forest',
|
||||
logLevel: 3,
|
||||
|
222
docs/community/new-diagram-jison.md
Normal file
222
docs/community/new-diagram-jison.md
Normal file
@@ -0,0 +1,222 @@
|
||||
> **Warning**
|
||||
>
|
||||
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
|
||||
>
|
||||
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/community/new-diagram-jison.md](../../packages/mermaid/src/docs/community/new-diagram-jison.md).
|
||||
|
||||
# Adding a New Diagram/Chart (Deprecated) 📊
|
||||
|
||||
> **Warning**
|
||||
> JISON grammars are deprecated in mermaid. Please use Langium instead. See [New Diagram](./new-diagram.md) for more information.
|
||||
>
|
||||
> **New diagrams with JISON grammars will not be accepted.**
|
||||
|
||||
### Step 1: Grammar & Parsing
|
||||
|
||||
#### Grammar
|
||||
|
||||
This would be to define a JISON grammar for the new diagram type. That should start with a way to identify that the text in the mermaid tag is a diagram of that type. Create a new folder under diagrams for your new diagram type and a parser folder in it. This leads us to step 2.
|
||||
|
||||
For instance:
|
||||
|
||||
- the flowchart starts with the keyword _graph_
|
||||
- the sequence diagram starts with the keyword _sequenceDiagram_
|
||||
|
||||
#### Store data found during parsing
|
||||
|
||||
There are some jison specific sub steps here where the parser stores the data encountered when parsing the diagram, this data is later used by the renderer. You can during the parsing call an object provided to the parser by the user of the parser. This object can be called during parsing for storing data.
|
||||
|
||||
```jison
|
||||
statement
|
||||
: 'participant' actor { $$='actor'; }
|
||||
| signal { $$='signal'; }
|
||||
| note_statement { $$='note'; }
|
||||
| 'title' message { yy.setTitle($2); }
|
||||
;
|
||||
```
|
||||
|
||||
In the extract of the grammar above, it is defined that a call to the setTitle method in the data object will be done when parsing and the title keyword is encountered.
|
||||
|
||||
> **Note**
|
||||
> Make sure that the `parseError` function for the parser is defined and calling `mermaid.parseError`. This way a common way of detecting parse errors is provided for the end-user.
|
||||
|
||||
For more info look at the example diagram type:
|
||||
|
||||
The `yy` object has the following function:
|
||||
|
||||
```javascript
|
||||
exports.parseError = function (err, hash) {
|
||||
mermaid.parseError(err, hash);
|
||||
};
|
||||
```
|
||||
|
||||
when parsing the `yy` object is initialized as per below:
|
||||
|
||||
```javascript
|
||||
const parser = exampleParser.parser;
|
||||
parser.yy = db;
|
||||
```
|
||||
|
||||
### Step 2: Rendering
|
||||
|
||||
Write a renderer that given the data found during parsing renders the diagram. To look at an example look at sequenceRenderer.js rather than the flowchart renderer as this is a more generic example.
|
||||
|
||||
Place the renderer in the diagram folder.
|
||||
|
||||
### Step 3: Detection of the new diagram type
|
||||
|
||||
The second thing to do is to add the capability to detect the new diagram to type to the detectType in `diagram-api/detectType.ts`. The detection should return a key for the new diagram type.
|
||||
[This key will be used to as the aria roledescription](#aria-roledescription), so it should be a word that clearly describes the diagram type.
|
||||
For example, if your new diagram uses a UML deployment diagram, a good key would be "UMLDeploymentDiagram" because assistive technologies such as a screen reader
|
||||
would voice that as "U-M-L Deployment diagram." Another good key would be "deploymentDiagram" because that would be voiced as "Deployment Diagram." A bad key would be "deployment" because that would not sufficiently describe the diagram.
|
||||
|
||||
Note that the diagram type key does not have to be the same as the diagram keyword chosen for the [grammar](#grammar), but it is helpful if they are the same.
|
||||
|
||||
### Step 4: The final piece - triggering the rendering
|
||||
|
||||
At this point when mermaid is trying to render the diagram, it will detect it as being of the new type but there will be no match when trying to render the diagram. To fix this add a new case in the switch statement in main.js:init this should match the diagram type returned from step #2. The code in this new case statement should call the renderer for the diagram type with the data found by the parser as an argument.
|
||||
|
||||
## Usage of the parser as a separate module
|
||||
|
||||
### Setup
|
||||
|
||||
```javascript
|
||||
const graph = require('./graphDb');
|
||||
const flow = require('./parser/flow');
|
||||
flow.parser.yy = graph;
|
||||
```
|
||||
|
||||
### Parsing
|
||||
|
||||
```javascript
|
||||
flow.parser.parse(text);
|
||||
```
|
||||
|
||||
### Data extraction
|
||||
|
||||
```javascript
|
||||
graph.getDirection();
|
||||
graph.getVertices();
|
||||
graph.getEdges();
|
||||
```
|
||||
|
||||
The parser is also exposed in the mermaid api by calling:
|
||||
|
||||
```javascript
|
||||
const parser = mermaid.getParser();
|
||||
```
|
||||
|
||||
Note that the parse needs a graph object to store the data as per:
|
||||
|
||||
```javascript
|
||||
flow.parser.yy = graph;
|
||||
```
|
||||
|
||||
Look at `graphDb.js` for more details on that object.
|
||||
|
||||
## Layout
|
||||
|
||||
If you are using a dagre based layout, please use flowchart-v2 as a template and by doing that you will be using dagre-wrapper instead of dagreD3 which we are migrating away from.
|
||||
|
||||
### Common parts of a diagram
|
||||
|
||||
There are a few features that are common between the different types of diagrams. We try to standardize the diagrams that work as similar as possible for the end user. The commonalities are:
|
||||
|
||||
- Directives, a way of modifying the diagram configuration from within the diagram code.
|
||||
- Accessibility, a way for an author to provide additional information like titles and descriptions to people accessing a text with diagrams using a screen reader.
|
||||
- Themes, there is a common way to modify the styling of diagrams in Mermaid.
|
||||
- Comments should follow mermaid standards
|
||||
|
||||
Here are some pointers on how to handle these different areas.
|
||||
|
||||
## Accessibility
|
||||
|
||||
Mermaid automatically adds the following accessibility information for the diagram SVG HTML element:
|
||||
|
||||
- aria-roledescription
|
||||
- accessible title
|
||||
- accessible description
|
||||
|
||||
### aria-roledescription
|
||||
|
||||
The aria-roledescription is automatically set to [the diagram type](#step-3--detection-of-the-new-diagram-type) and inserted into the SVG element.
|
||||
|
||||
See [the definition of aria-roledescription](https://www.w3.org/TR/wai-aria-1.1/#aria-roledescription) in [the Accessible Rich Internet Applications W3 standard.](https://www.w3.org/WAI/standards-guidelines/aria/)
|
||||
|
||||
### accessible title and description
|
||||
|
||||
The syntax for accessible titles and descriptions is described in [the Accessibility documentation section.](../config/accessibility.md)
|
||||
|
||||
As a design goal, the jison syntax should be similar between the diagrams.
|
||||
|
||||
```jison
|
||||
|
||||
* lexical grammar */
|
||||
%lex
|
||||
%x acc_title
|
||||
%x acc_descr
|
||||
%x acc_descr_multiline
|
||||
|
||||
%%
|
||||
accTitle\s*":"\s* { this.begin("acc_title");return 'acc_title'; }
|
||||
<acc_title>(?!\n|;|#)*[^\n]* { this.popState(); return "acc_title_value"; }
|
||||
accDescr\s*":"\s* { this.begin("acc_descr");return 'acc_descr'; }
|
||||
<acc_descr>(?!\n|;|#)*[^\n]* { this.popState(); return "acc_descr_value"; }
|
||||
accDescr\s*"{"\s* { this.begin("acc_descr_multiline");}
|
||||
<acc_descr_multiline>[\}] { this.popState(); }
|
||||
<acc_descr_multiline>[^\}]* return "acc_descr_multiline_value";
|
||||
|
||||
statement
|
||||
: acc_title acc_title_value { $$=$2.trim();yy.setTitle($$); }
|
||||
| acc_descr acc_descr_value { $$=$2.trim();yy.setAccDescription($$); }
|
||||
| acc_descr_multiline_value { $$=$1.trim();yy.setAccDescription($$); }
|
||||
|
||||
```
|
||||
|
||||
The functions for setting title and description are provided by a common module. This is the import from flowDb.js:
|
||||
|
||||
import {
|
||||
setAccTitle,
|
||||
getAccTitle,
|
||||
getAccDescription,
|
||||
setAccDescription,
|
||||
clear as commonClear,
|
||||
} from '../../commonDb';
|
||||
|
||||
The accessibility title and description are inserted into the SVG element in the `render` function in mermaidAPI.
|
||||
|
||||
## Theming
|
||||
|
||||
Mermaid supports themes and has an integrated theming engine. You can read more about how the themes can be used [in the docs](../config/theming.md).
|
||||
|
||||
When adding themes to a diagram it comes down to a few important locations in the code.
|
||||
|
||||
The entry point for the styling engine is in **src/styles.js**. The getStyles function will be called by Mermaid when the styles are being applied to the diagram.
|
||||
|
||||
This function will in turn call a function _your diagram should provide_ returning the css for the new diagram. The diagram specific, also which is commonly also called getStyles and located in the folder for your diagram under src/diagrams and should be named styles.js. The getStyles function will be called with the theme options as an argument like in the following example:
|
||||
|
||||
```js
|
||||
const getStyles = (options) =>
|
||||
`
|
||||
.line {
|
||||
stroke-width: 1;
|
||||
stroke: ${options.lineColor};
|
||||
stroke-dasharray: 2;
|
||||
}
|
||||
// ...
|
||||
`;
|
||||
```
|
||||
|
||||
Note that you need to provide your function to the main getStyles by adding it into the themes object in **src/styles.js** like in the xyzDiagram in the provided example:
|
||||
|
||||
```js
|
||||
const themes = {
|
||||
flowchart,
|
||||
'flowchart-v2': flowchart,
|
||||
sequence,
|
||||
xyzDiagram,
|
||||
//...
|
||||
};
|
||||
```
|
||||
|
||||
The actual options and values for the colors are defined in **src/theme/theme-\[xyz].js**. If you provide the options your diagram needs in the existing theme files then the theming will work smoothly without hiccups.
|
@@ -6,52 +6,18 @@
|
||||
|
||||
# Adding a New Diagram/Chart 📊
|
||||
|
||||
### Examples
|
||||
|
||||
Please refer to the following PRs on how to use Langium to add a new diagram grammar.
|
||||
|
||||
- <https://github.com/mermaid-js/mermaid/pull/4839>
|
||||
- <https://github.com/mermaid-js/mermaid/pull/4751>
|
||||
|
||||
> **Warning**
|
||||
> The below steps are a work in progress and will be updated soon.
|
||||
|
||||
### Step 1: Grammar & Parsing
|
||||
|
||||
#### Grammar
|
||||
|
||||
This would be to define a JISON grammar for the new diagram type. That should start with a way to identify that the text in the mermaid tag is a diagram of that type. Create a new folder under diagrams for your new diagram type and a parser folder in it. This leads us to step 2.
|
||||
|
||||
For instance:
|
||||
|
||||
- the flowchart starts with the keyword _graph_
|
||||
- the sequence diagram starts with the keyword _sequenceDiagram_
|
||||
|
||||
#### Store data found during parsing
|
||||
|
||||
There are some jison specific sub steps here where the parser stores the data encountered when parsing the diagram, this data is later used by the renderer. You can during the parsing call an object provided to the parser by the user of the parser. This object can be called during parsing for storing data.
|
||||
|
||||
```jison
|
||||
statement
|
||||
: 'participant' actor { $$='actor'; }
|
||||
| signal { $$='signal'; }
|
||||
| note_statement { $$='note'; }
|
||||
| 'title' message { yy.setTitle($2); }
|
||||
;
|
||||
```
|
||||
|
||||
In the extract of the grammar above, it is defined that a call to the setTitle method in the data object will be done when parsing and the title keyword is encountered.
|
||||
|
||||
> **Note**
|
||||
> Make sure that the `parseError` function for the parser is defined and calling `mermaid.parseError`. This way a common way of detecting parse errors is provided for the end-user.
|
||||
|
||||
For more info look at the example diagram type:
|
||||
|
||||
The `yy` object has the following function:
|
||||
|
||||
```javascript
|
||||
exports.parseError = function (err, hash) {
|
||||
mermaid.parseError(err, hash);
|
||||
};
|
||||
```
|
||||
|
||||
when parsing the `yy` object is initialized as per below:
|
||||
|
||||
```javascript
|
||||
const parser = exampleParser.parser;
|
||||
parser.yy = db;
|
||||
```
|
||||
|
||||
### Step 2: Rendering
|
||||
|
||||
Write a renderer that given the data found during parsing renders the diagram. To look at an example look at sequenceRenderer.js rather than the flowchart renderer as this is a more generic example.
|
||||
@@ -67,52 +33,6 @@ would voice that as "U-M-L Deployment diagram." Another good key would be "deplo
|
||||
|
||||
Note that the diagram type key does not have to be the same as the diagram keyword chosen for the [grammar](#grammar), but it is helpful if they are the same.
|
||||
|
||||
### Step 4: The final piece - triggering the rendering
|
||||
|
||||
At this point when mermaid is trying to render the diagram, it will detect it as being of the new type but there will be no match when trying to render the diagram. To fix this add a new case in the switch statement in main.js:init this should match the diagram type returned from step #2. The code in this new case statement should call the renderer for the diagram type with the data found by the parser as an argument.
|
||||
|
||||
## Usage of the parser as a separate module
|
||||
|
||||
### Setup
|
||||
|
||||
```javascript
|
||||
const graph = require('./graphDb');
|
||||
const flow = require('./parser/flow');
|
||||
flow.parser.yy = graph;
|
||||
```
|
||||
|
||||
### Parsing
|
||||
|
||||
```javascript
|
||||
flow.parser.parse(text);
|
||||
```
|
||||
|
||||
### Data extraction
|
||||
|
||||
```javascript
|
||||
graph.getDirection();
|
||||
graph.getVertices();
|
||||
graph.getEdges();
|
||||
```
|
||||
|
||||
The parser is also exposed in the mermaid api by calling:
|
||||
|
||||
```javascript
|
||||
const parser = mermaid.getParser();
|
||||
```
|
||||
|
||||
Note that the parse needs a graph object to store the data as per:
|
||||
|
||||
```javascript
|
||||
flow.parser.yy = graph;
|
||||
```
|
||||
|
||||
Look at `graphDb.js` for more details on that object.
|
||||
|
||||
## Layout
|
||||
|
||||
If you are using a dagre based layout, please use flowchart-v2 as a template and by doing that you will be using dagre-wrapper instead of dagreD3 which we are migrating away from.
|
||||
|
||||
### Common parts of a diagram
|
||||
|
||||
There are a few features that are common between the different types of diagrams. We try to standardize the diagrams that work as similar as possible for the end user. The commonalities are:
|
||||
@@ -142,33 +62,7 @@ See [the definition of aria-roledescription](https://www.w3.org/TR/wai-aria-1.1/
|
||||
|
||||
The syntax for accessible titles and descriptions is described in [the Accessibility documentation section.](../config/accessibility.md)
|
||||
|
||||
As a design goal, the jison syntax should be similar between the diagrams.
|
||||
|
||||
```jison
|
||||
|
||||
* lexical grammar */
|
||||
%lex
|
||||
%x acc_title
|
||||
%x acc_descr
|
||||
%x acc_descr_multiline
|
||||
|
||||
%%
|
||||
accTitle\s*":"\s* { this.begin("acc_title");return 'acc_title'; }
|
||||
<acc_title>(?!\n|;|#)*[^\n]* { this.popState(); return "acc_title_value"; }
|
||||
accDescr\s*":"\s* { this.begin("acc_descr");return 'acc_descr'; }
|
||||
<acc_descr>(?!\n|;|#)*[^\n]* { this.popState(); return "acc_descr_value"; }
|
||||
accDescr\s*"{"\s* { this.begin("acc_descr_multiline");}
|
||||
<acc_descr_multiline>[\}] { this.popState(); }
|
||||
<acc_descr_multiline>[^\}]* return "acc_descr_multiline_value";
|
||||
|
||||
statement
|
||||
: acc_title acc_title_value { $$=$2.trim();yy.setTitle($$); }
|
||||
| acc_descr acc_descr_value { $$=$2.trim();yy.setAccDescription($$); }
|
||||
| acc_descr_multiline_value { $$=$1.trim();yy.setAccDescription($$); }
|
||||
|
||||
```
|
||||
|
||||
The functions for setting title and description are provided by a common module. This is the import from flowDb.js:
|
||||
The functions for setting title and description are provided by a common module. This is the import in flowDb.js:
|
||||
|
||||
import {
|
||||
setAccTitle,
|
||||
|
@@ -4,7 +4,7 @@
|
||||
>
|
||||
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/config/math.md](../../packages/mermaid/src/docs/config/math.md).
|
||||
|
||||
# Math Configuration (v\<MERMAID_RELEASE_VERSION>+)
|
||||
# Math Configuration (v10.9.0+)
|
||||
|
||||
Mermaid supports rendering mathematical expressions through the [KaTeX](https://katex.org/) typesetter.
|
||||
|
||||
|
@@ -14,9 +14,6 @@
|
||||
|
||||
• `Optional` **suppressErrors**: `boolean`
|
||||
|
||||
If `true`, parse will return `false` instead of throwing error when the diagram is invalid.
|
||||
The `parseError` function will not be called.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:64](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L64)
|
||||
[mermaidAPI.ts:60](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L60)
|
||||
|
@@ -1,21 +0,0 @@
|
||||
> **Warning**
|
||||
>
|
||||
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
|
||||
>
|
||||
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/config/setup/interfaces/mermaidAPI.ParseResult.md](../../../../packages/mermaid/src/docs/config/setup/interfaces/mermaidAPI.ParseResult.md).
|
||||
|
||||
# Interface: ParseResult
|
||||
|
||||
[mermaidAPI](../modules/mermaidAPI.md).ParseResult
|
||||
|
||||
## Properties
|
||||
|
||||
### diagramType
|
||||
|
||||
• **diagramType**: `string`
|
||||
|
||||
The diagram type, e.g. 'flowchart', 'sequence', etc.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:71](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L71)
|
@@ -39,19 +39,7 @@ bindFunctions?.(div); // To call bindFunctions only if it's present.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:94](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L94)
|
||||
|
||||
---
|
||||
|
||||
### diagramType
|
||||
|
||||
• **diagramType**: `string`
|
||||
|
||||
The diagram type, e.g. 'flowchart', 'sequence', etc.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:84](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L84)
|
||||
[mermaidAPI.ts:80](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L80)
|
||||
|
||||
---
|
||||
|
||||
@@ -63,4 +51,4 @@ The svg code for the rendered graph.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:80](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L80)
|
||||
[mermaidAPI.ts:70](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L70)
|
||||
|
@@ -14,7 +14,7 @@
|
||||
|
||||
#### Defined in
|
||||
|
||||
[defaultConfig.ts:275](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L275)
|
||||
[defaultConfig.ts:272](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L272)
|
||||
|
||||
---
|
||||
|
||||
|
@@ -9,7 +9,6 @@
|
||||
## Interfaces
|
||||
|
||||
- [ParseOptions](../interfaces/mermaidAPI.ParseOptions.md)
|
||||
- [ParseResult](../interfaces/mermaidAPI.ParseResult.md)
|
||||
- [RenderResult](../interfaces/mermaidAPI.RenderResult.md)
|
||||
|
||||
## References
|
||||
@@ -26,13 +25,13 @@ Renames and re-exports [mermaidAPI](mermaidAPI.md#mermaidapi)
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:74](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L74)
|
||||
[mermaidAPI.ts:64](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L64)
|
||||
|
||||
## Variables
|
||||
|
||||
### mermaidAPI
|
||||
|
||||
• `Const` **mermaidAPI**: `Readonly`<{ `defaultConfig`: `MermaidConfig` = configApi.defaultConfig; `getConfig`: () => `MermaidConfig` = configApi.getConfig; `getDiagramFromText`: (`text`: `string`, `metadata`: `Pick`<`DiagramMetadata`, `"title"`>) => `Promise`<`Diagram`> ; `getSiteConfig`: () => `MermaidConfig` = configApi.getSiteConfig; `globalReset`: () => `void` ; `initialize`: (`options`: `MermaidConfig`) => `void` ; `parse`: (`text`: `string`, `parseOptions`: [`ParseOptions`](../interfaces/mermaidAPI.ParseOptions.md) & { `suppressErrors`: `true` }) => `Promise`<[`ParseResult`](../interfaces/mermaidAPI.ParseResult.md) | `false`>(`text`: `string`, `parseOptions?`: [`ParseOptions`](../interfaces/mermaidAPI.ParseOptions.md)) => `Promise`<[`ParseResult`](../interfaces/mermaidAPI.ParseResult.md)> ; `render`: (`id`: `string`, `text`: `string`, `svgContainingElement?`: `Element`) => `Promise`<[`RenderResult`](../interfaces/mermaidAPI.RenderResult.md)> ; `reset`: () => `void` ; `setConfig`: (`conf`: `MermaidConfig`) => `MermaidConfig` = configApi.setConfig; `updateSiteConfig`: (`conf`: `MermaidConfig`) => `MermaidConfig` = configApi.updateSiteConfig }>
|
||||
• `Const` **mermaidAPI**: `Readonly`<{ `defaultConfig`: `MermaidConfig` = configApi.defaultConfig; `getConfig`: () => `MermaidConfig` = configApi.getConfig; `getDiagramFromText`: (`text`: `string`, `metadata`: `Pick`<`DiagramMetadata`, `"title"`>) => `Promise`<`Diagram`> ; `getSiteConfig`: () => `MermaidConfig` = configApi.getSiteConfig; `globalReset`: () => `void` ; `initialize`: (`options`: `MermaidConfig`) => `void` ; `parse`: (`text`: `string`, `parseOptions?`: [`ParseOptions`](../interfaces/mermaidAPI.ParseOptions.md)) => `Promise`<`boolean`> ; `render`: (`id`: `string`, `text`: `string`, `svgContainingElement?`: `Element`) => `Promise`<[`RenderResult`](../interfaces/mermaidAPI.RenderResult.md)> ; `reset`: () => `void` ; `setConfig`: (`conf`: `MermaidConfig`) => `MermaidConfig` = configApi.setConfig; `updateSiteConfig`: (`conf`: `MermaidConfig`) => `MermaidConfig` = configApi.updateSiteConfig }>
|
||||
|
||||
## mermaidAPI configuration defaults
|
||||
|
||||
@@ -97,7 +96,7 @@ mermaid.initialize(config);
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:622](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L622)
|
||||
[mermaidAPI.ts:607](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L607)
|
||||
|
||||
## Functions
|
||||
|
||||
@@ -128,7 +127,7 @@ Return the last node appended
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:277](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L277)
|
||||
[mermaidAPI.ts:263](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L263)
|
||||
|
||||
---
|
||||
|
||||
@@ -154,7 +153,7 @@ the cleaned up svgCode
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:223](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L223)
|
||||
[mermaidAPI.ts:209](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L209)
|
||||
|
||||
---
|
||||
|
||||
@@ -179,7 +178,7 @@ the string with all the user styles
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:153](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L153)
|
||||
[mermaidAPI.ts:139](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L139)
|
||||
|
||||
---
|
||||
|
||||
@@ -202,7 +201,7 @@ the string with all the user styles
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:200](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L200)
|
||||
[mermaidAPI.ts:186](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L186)
|
||||
|
||||
---
|
||||
|
||||
@@ -229,7 +228,7 @@ with an enclosing block that has each of the cssClasses followed by !important;
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:138](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L138)
|
||||
[mermaidAPI.ts:124](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L124)
|
||||
|
||||
---
|
||||
|
||||
@@ -255,7 +254,7 @@ Put the svgCode into an iFrame. Return the iFrame code
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:254](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L254)
|
||||
[mermaidAPI.ts:240](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L240)
|
||||
|
||||
---
|
||||
|
||||
@@ -280,4 +279,4 @@ Remove any existing elements from the given document
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:327](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L327)
|
||||
[mermaidAPI.ts:313](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L313)
|
||||
|
@@ -64,7 +64,7 @@ Example:
|
||||
|
||||
```html
|
||||
<script type="module">
|
||||
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
|
||||
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
|
||||
</script>
|
||||
```
|
||||
|
||||
@@ -83,7 +83,7 @@ Example:
|
||||
B-->D(fa:fa-spinner);
|
||||
</pre>
|
||||
<script type="module">
|
||||
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
|
||||
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -331,17 +331,15 @@ module.exports = (options) ->
|
||||
|
||||
## Advanced usage
|
||||
|
||||
### Syntax validation without rendering
|
||||
**Syntax validation without rendering (Work in Progress)**
|
||||
|
||||
The `mermaid.parse(text, parseOptions)` function validates graph definitions without rendering a graph.
|
||||
The **mermaid.parse(txt)** function validates graph definitions without rendering a graph. **[This function is still a work in progress](https://github.com/mermaid-js/mermaid/issues/1066), find alternatives below.**
|
||||
|
||||
The function `mermaid.parse(text, parseOptions)`, takes a text string as an argument and returns `{ diagramType: string }` if the definition follows mermaid's syntax.
|
||||
The function **mermaid.parse(txt)**, takes a text string as an argument and returns true if the definition follows mermaid's syntax and
|
||||
false if it does not. The parseError function will be called when the parse function returns false.
|
||||
|
||||
If the definition is invalid, the function returns `false` if `parseOptions.suppressErrors` is set to `true`. Otherwise, it throws an error.
|
||||
|
||||
The parseError function will be called when the parse function throws an error. It will not be called if `parseOptions.suppressErrors` is set to `true`.
|
||||
|
||||
It is possible to override this function in order to handle the error in an application-specific way.
|
||||
When the parser encounters invalid syntax the **mermaid.parseError** function is called. It is possible to override this
|
||||
function in order to handle the error in an application-specific way.
|
||||
|
||||
The code-example below in meta code illustrates how this could work:
|
||||
|
||||
@@ -361,10 +359,26 @@ const textFieldUpdated = async function () {
|
||||
bindEventHandler('change', 'code', textFieldUpdated);
|
||||
```
|
||||
|
||||
**Alternative to mermaid.parse():**
|
||||
One effective and more future-proof method of validating your graph definitions, is to paste and render them via the [Mermaid Live Editor](https://mermaid.live/). This will ensure that your code is compliant with the syntax of Mermaid's most recent version.
|
||||
|
||||
## Configuration
|
||||
|
||||
You can pass the required configuration to the `mermaid.initialize` call. This is the preferred way of configuring mermaid.
|
||||
The list of configuration objects are described [in the mermaidAPI documentation](./setup/README.md).
|
||||
Mermaid takes a number of options which lets you tweak the rendering of the diagrams. Currently there are three ways of
|
||||
setting the options in mermaid.
|
||||
|
||||
1. Instantiation of the configuration using the initialize call
|
||||
2. _Using the global mermaid object_ - **Deprecated**
|
||||
3. _using the global mermaid_config object_ - **Deprecated**
|
||||
4. Instantiation of the configuration using the **mermaid.init** call- **Deprecated**
|
||||
|
||||
The list above has two ways too many of doing this. Three are deprecated and will eventually be removed. The list of
|
||||
configuration objects are described [in the mermaidAPI documentation](./setup/README.md).
|
||||
|
||||
## Using the `mermaidAPI.initialize`/`mermaid.initialize` call
|
||||
|
||||
The future proof way of setting the configuration is by using the initialization call to mermaid or mermaidAPI depending
|
||||
on what kind of integration you use.
|
||||
|
||||
```html
|
||||
<script type="module">
|
||||
@@ -394,6 +408,35 @@ mermaid.startOnLoad = true;
|
||||
> **Warning**
|
||||
> This way of setting the configuration is deprecated. Instead the preferred way is to use the initialize method. This functionality is only kept for backwards compatibility.
|
||||
|
||||
## Using the mermaid_config
|
||||
|
||||
It is possible to set some configuration via the mermaid object. The two parameters that are supported using this
|
||||
approach are:
|
||||
|
||||
- mermaid_config.startOnLoad
|
||||
- mermaid_config.htmlLabels
|
||||
|
||||
```javascript
|
||||
mermaid_config.startOnLoad = true;
|
||||
```
|
||||
|
||||
> **Warning**
|
||||
> This way of setting the configuration is deprecated. Instead the preferred way is to use the initialize method. This functionality is only kept for backwards compatibility.
|
||||
|
||||
## Using the mermaid.init call
|
||||
|
||||
To set some configuration via the mermaid object. The two parameters that are supported using this approach are:
|
||||
|
||||
- mermaid_config.startOnLoad
|
||||
- mermaid_config.htmlLabels
|
||||
|
||||
```javascript
|
||||
mermaid_config.startOnLoad = true;
|
||||
```
|
||||
|
||||
> **Warning**
|
||||
> This way of setting the configuration is deprecated. Instead the preferred way is to use the initialize method. This functionality is only kept for backwards compatibility.
|
||||
|
||||
<!---
|
||||
cspell:locale en,en-gb
|
||||
cspell:ignore pumbaa
|
||||
|
@@ -118,7 +118,7 @@ Communication tools and platforms
|
||||
- [phpBB](https://phpbb.com)
|
||||
- [phpbb-ext-mermaid](https://github.com/AlfredoRamos/phpbb-ext-mermaid)
|
||||
- [Slack](https://slack.com)
|
||||
- [Mermaid Preview](https://github.com/JackuB/mermaid-for-slack)
|
||||
- [Mermaid Preview](https://mermaid-preview.com)
|
||||
|
||||
### Wikis
|
||||
|
||||
|
@@ -6,6 +6,10 @@
|
||||
|
||||
# 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).
|
||||
|
||||
<br />
|
||||
|
||||
<a href="https://www.producthunt.com/posts/mermaid-chart?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-mermaid-chart" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=416671&theme=light" alt="Mermaid Chart - A smarter way to create diagrams | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
|
||||
@@ -18,22 +22,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
|
||||
|
||||
@@ -43,11 +51,9 @@
|
||||
|
||||
- **Enterprise** - A paid plan for enterprise use that includes all Pro features, and more.
|
||||
|
||||
## Access
|
||||
To learn more, visit our [Pricing](https://mermaidchart.com/pricing) page.
|
||||
|
||||
Sign up for a free account at [Mermaid Chart](https://www.mermaidchart.com/app/sign-up).
|
||||
|
||||
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
|
||||
|
||||
|
@@ -224,7 +224,7 @@ b. The importing of the Mermaid library through the `mermaid.esm.mjs` or `mermai
|
||||
```html
|
||||
<body>
|
||||
<script type="module">
|
||||
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
|
||||
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
|
||||
mermaid.initialize({ startOnLoad: true });
|
||||
</script>
|
||||
</body>
|
||||
@@ -246,23 +246,23 @@ In this example, the `mermaidAPI` is being called through the `CDN`:
|
||||
<body>
|
||||
Here is one mermaid diagram:
|
||||
<pre class="mermaid">
|
||||
graph TD
|
||||
A[Client] --> B[Load Balancer]
|
||||
B --> C[Server1]
|
||||
graph TD
|
||||
A[Client] --> B[Load Balancer]
|
||||
B --> C[Server1]
|
||||
B --> D[Server2]
|
||||
</pre>
|
||||
|
||||
And here is another:
|
||||
<pre class="mermaid">
|
||||
graph TD
|
||||
graph TD
|
||||
A[Client] -->|tcp_123| B
|
||||
B(Load Balancer)
|
||||
B -->|tcp_456| C[Server1]
|
||||
B(Load Balancer)
|
||||
B -->|tcp_456| C[Server1]
|
||||
B -->|tcp_456| D[Server2]
|
||||
</pre>
|
||||
|
||||
<script type="module">
|
||||
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
|
||||
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
|
||||
mermaid.initialize({ startOnLoad: true });
|
||||
</script>
|
||||
</body>
|
||||
@@ -278,15 +278,15 @@ In this example, `mermaid.js` is referenced in `src` as a separate JavaScript fi
|
||||
</head>
|
||||
<body>
|
||||
<pre class="mermaid">
|
||||
graph LR
|
||||
A --- B
|
||||
B-->C[fa:fa-ban forbidden]
|
||||
graph LR
|
||||
A --- B
|
||||
B-->C[fa:fa-ban forbidden]
|
||||
B-->D(fa:fa-spinner);
|
||||
</pre>
|
||||
<pre class="mermaid">
|
||||
graph TD
|
||||
A[Client] --> B[Load Balancer]
|
||||
B --> C[Server1]
|
||||
graph TD
|
||||
A[Client] --> B[Load Balancer]
|
||||
B --> C[Server1]
|
||||
B --> D[Server2]
|
||||
</pre>
|
||||
<script type="module">
|
||||
|
@@ -317,7 +317,7 @@ To select a version:
|
||||
|
||||
Replace `<version>` with the desired version number.
|
||||
|
||||
Latest Version: <https://cdn.jsdelivr.net/npm/mermaid@11>
|
||||
Latest Version: <https://cdn.jsdelivr.net/npm/mermaid@10>
|
||||
|
||||
## Deploying Mermaid
|
||||
|
||||
@@ -335,7 +335,7 @@ To Deploy Mermaid:
|
||||
|
||||
```html
|
||||
<script type="module">
|
||||
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
|
||||
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
|
||||
mermaid.initialize({ startOnLoad: true });
|
||||
</script>
|
||||
```
|
||||
|
@@ -6,13 +6,45 @@
|
||||
|
||||
# Announcements
|
||||
|
||||
## 🚀 Mermaid Chart's Visual Editor for Flowcharts
|
||||
## 🚀 Exciting News from Mermaid Chart! 🚀
|
||||
|
||||
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.
|
||||
We're thrilled to announce that Mermaid Chart has successfully raised $7.5 million in Seed funding! 🌟 This achievement marks the beginning of a new era for Mermaid and Mermaid Chart.
|
||||
|
||||
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.
|
||||
**Why It Matters for Mermaid Chart:**
|
||||
|
||||
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.
|
||||
- **Empowering Collaboration**: Our tools are designed to enable faster, more efficient team collaboration across any distance, leveraging the best of text, voice, and automation.
|
||||
- **Opening New Doors**: Mermaid AI and our Visual Editor are breaking down barriers, making sophisticated diagramming accessible to everyone, not just software engineers.
|
||||
- **Looking Forward**: We're not stopping here! Expect groundbreaking features like automated documentation tools, advanced AI diagramming, and high-security on-premise solutions.
|
||||
|
||||
**Why It Matters for Mermaid JS:**
|
||||
|
||||
- **Continued support from Mermaid Chart**: At Mermaid Chart, we value our still-growing Mermaid JS roots. As such, we have funneled back development and support to the project. Thanks to the successful seed round, we can continue to ramp up these efforts.
|
||||
|
||||
We are incredibly excited about the future and are grateful to the community, our team, and our investors for being part of this journey. Together, we're not just creating diagrams; we're designing the future of collaboration.
|
||||
|
||||
🌐 Learn more about our groundbreaking tools and what's next for Mermaid Chart by visiting [our website](https://www.mermaidchart.com/blog/posts/mermaid-chart-raises-7.5m-to-reinvent-visual-collaoration-for-enterprises).
|
||||
|
||||
Thank you for being part of our story. Here's to creating, innovating, and collaborating on a global scale!
|
||||
|
||||
Knut Sveidqvist 🧜♂️✨
|
||||
|
||||
## Mermaid Chart's Visual Editor for Flowcharts and Sequence diagrams
|
||||
|
||||
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.
|
||||
|
||||
Learn more:
|
||||
|
||||
- Visual Editor For Flowcharts
|
||||
|
||||
- [Blog post](https://www.mermaidchart.com/blog/posts/mermaid-chart-releases-new-visual-editor-for-flowcharts)
|
||||
|
||||
- [Demo video](https://www.youtube.com/watch?v=5aja0gijoO0)
|
||||
|
||||
- Visual Editor For Sequence diagrams
|
||||
|
||||
- [Blog post](https://www.mermaidchart.com/blog/posts/mermaid-chart-unveils-visual-editor-for-sequence-diagrams)
|
||||
|
||||
- [Demo video](https://youtu.be/imc2u5_N6Dc)
|
||||
|
||||
## 📖 Blog posts
|
||||
|
||||
|
@@ -6,6 +6,48 @@
|
||||
|
||||
# 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
|
||||
|
||||
Mermaid Chart, the company offering text-based diagramming and workflow management tools, today announced it has raised $7.5 million in Seed funding.
|
||||
|
||||
## [Mermaid Chart GPT Is Now Available In the GPT Store!](https://www.mermaidchart.com/blog/posts/mermaid-chart-gpt-is-now-available-in-the-gpt-store/)
|
||||
|
||||
7 March 2024 · 3 mins
|
||||
|
||||
Mermaid Chart GPT is Now Available In the GPT Store!
|
||||
|
||||
## [How to Make a Flowchart with Mermaid Chart](https://www.mermaidchart.com/blog/posts/how-to-make-flowcharts-with-mermaid-chart/)
|
||||
|
||||
30 January 2024 · 6 mins
|
||||
|
||||
Learn how to make a flowchart with Mermaid Chart, the leading text-to-diagram platform for both developers and non-developers.
|
||||
|
||||
## [How one data scientist uses Mermaid Chart to quickly and easily build flowcharts](https://www.mermaidchart.com/blog/posts/customer-spotlight-ari-tal/)
|
||||
|
||||
23 January 2024 · 4 mins
|
||||
|
@@ -143,7 +143,7 @@ After processing the tags, the remaining metadata items are interpreted as follo
|
||||
| `until <otherTaskId>` | End date of preceding task | Start date of previously specified task `otherTaskID` | n/a |
|
||||
|
||||
> **Note**
|
||||
> Support for keyword `until` was added in (v\<MERMAID_RELEASE_VERSION>+). This can be used to define a task which is running until some other specific task or milestone starts.
|
||||
> Support for keyword `until` was added in (v10.9.0+). This can be used to define a task which is running until some other specific task or milestone starts.
|
||||
|
||||
For simplicity, the table does not show the use of multiple tasks listed with the `after` keyword. Here is an example of how to use it and how it's interpreted:
|
||||
|
||||
|
@@ -300,7 +300,7 @@ From version 9.4.0 you can simplify this code to:
|
||||
|
||||
```html
|
||||
<script type="module">
|
||||
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
|
||||
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
|
||||
</script>
|
||||
```
|
||||
|
||||
|
@@ -1,141 +0,0 @@
|
||||
> **Warning**
|
||||
>
|
||||
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
|
||||
>
|
||||
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/syntax/packet.md](../../packages/mermaid/src/docs/syntax/packet.md).
|
||||
|
||||
# Packet Diagram (v\<MERMAID_RELEASE_VERSION>+)
|
||||
|
||||
## Introduction
|
||||
|
||||
A packet diagram is a visual representation used to illustrate the structure and contents of a network packet. Network packets are the fundamental units of data transferred over a network.
|
||||
|
||||
## Usage
|
||||
|
||||
This diagram type is particularly useful for network engineers, educators, and students who require a clear and concise way to represent the structure of network packets.
|
||||
|
||||
## Syntax
|
||||
|
||||
```md
|
||||
packet-beta
|
||||
start: "Block name" %% Single-bit block
|
||||
start-end: "Block name" %% Multi-bit blocks
|
||||
... More Fields ...
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
```mermaid-example
|
||||
---
|
||||
title: "TCP Packet"
|
||||
---
|
||||
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-255: "Data (variable length)"
|
||||
```
|
||||
|
||||
```mermaid
|
||||
---
|
||||
title: "TCP Packet"
|
||||
---
|
||||
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-255: "Data (variable length)"
|
||||
```
|
||||
|
||||
```mermaid-example
|
||||
packet-beta
|
||||
title UDP Packet
|
||||
0-15: "Source Port"
|
||||
16-31: "Destination Port"
|
||||
32-47: "Length"
|
||||
48-63: "Checksum"
|
||||
64-95: "Data (variable length)"
|
||||
```
|
||||
|
||||
```mermaid
|
||||
packet-beta
|
||||
title UDP Packet
|
||||
0-15: "Source Port"
|
||||
16-31: "Destination Port"
|
||||
32-47: "Length"
|
||||
48-63: "Checksum"
|
||||
64-95: "Data (variable length)"
|
||||
```
|
||||
|
||||
## Details of Syntax
|
||||
|
||||
- **Ranges**: Each line after the title represents a different field in the packet. The range (e.g., `0-15`) indicates the bit positions in the packet.
|
||||
- **Field Description**: A brief description of what the field represents, enclosed in quotes.
|
||||
|
||||
## Configuration
|
||||
|
||||
Please refer to the [configuration](/config/schema-docs/config-defs-packet-diagram-config.html) guide for details.
|
||||
|
||||
<!--
|
||||
|
||||
Theme variables are not currently working due to a mermaid bug. The passed values are not being propagated into styles function.
|
||||
|
||||
## Theme Variables
|
||||
|
||||
| Property | Description | Default Value |
|
||||
| ---------------- | -------------------------- | ------------- |
|
||||
| byteFontSize | Font size of the bytes | '10px' |
|
||||
| startByteColor | Color of the starting byte | 'black' |
|
||||
| endByteColor | Color of the ending byte | 'black' |
|
||||
| labelColor | Color of the labels | 'black' |
|
||||
| labelFontSize | Font size of the labels | '12px' |
|
||||
| titleColor | Color of the title | 'black' |
|
||||
| titleFontSize | Font size of the title | '14px' |
|
||||
| blockStrokeColor | Color of the block stroke | 'black' |
|
||||
| blockStrokeWidth | Width of the block stroke | '1' |
|
||||
| blockFillColor | Fill color of the block | '#efefef' |
|
||||
|
||||
## Example on config and theme
|
||||
|
||||
```mermaid-example
|
||||
---
|
||||
config:
|
||||
packet:
|
||||
showBits: true
|
||||
themeVariables:
|
||||
packet:
|
||||
startByteColor: red
|
||||
---
|
||||
packet-beta
|
||||
0-15: "Source Port"
|
||||
16-31: "Destination Port"
|
||||
32-63: "Sequence Number"
|
||||
```
|
||||
|
||||
-->
|
@@ -469,7 +469,7 @@ You can use this method to add mermaid including the timeline diagram to a web p
|
||||
|
||||
```html
|
||||
<script type="module">
|
||||
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
|
||||
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
|
||||
</script>
|
||||
```
|
||||
|
||||
|
@@ -7,9 +7,9 @@
|
||||
base = ""
|
||||
|
||||
# Directory that contains the deploy-ready HTML files and
|
||||
# assets generated by the build. This is an absolute path relative
|
||||
# assets generated by the build. This is an absolute path relative
|
||||
# to the base directory, which is the root by default (/).
|
||||
# This sample publishes the directory located at the absolute
|
||||
# This sample publishes the directory located at the absolute
|
||||
# path "root/project/build-output"
|
||||
|
||||
publish = "mermaid-live-editor/docs"
|
||||
|
23
package.json
23
package.json
@@ -15,15 +15,15 @@
|
||||
"git graph"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "pnpm build:esbuild && pnpm build:types",
|
||||
"build:esbuild": "pnpm run -r clean && tsx .esbuild/build.ts",
|
||||
"build:mermaid": "pnpm build:esbuild --mermaid",
|
||||
"build:viz": "pnpm build:esbuild --visualize",
|
||||
"build:types": "tsx .build/types.ts",
|
||||
"build:vite": "tsx .vite/build.ts",
|
||||
"build:mermaid": "pnpm build:vite --mermaid",
|
||||
"build:viz": "pnpm build:mermaid --visualize",
|
||||
"build:types": "tsc -p ./packages/mermaid/tsconfig.json --emitDeclarationOnly && tsc -p ./packages/mermaid-zenuml/tsconfig.json --emitDeclarationOnly && tsc -p ./packages/mermaid-example-diagram/tsconfig.json --emitDeclarationOnly",
|
||||
"build:types:watch": "tsc -p ./packages/mermaid/tsconfig.json --emitDeclarationOnly --watch",
|
||||
"dev": "tsx .esbuild/server.ts",
|
||||
"dev:vite": "tsx .vite/server.ts",
|
||||
"dev:coverage": "pnpm coverage:cypress:clean && VITE_COVERAGE=true pnpm dev:vite",
|
||||
"build:watch": "pnpm build:vite --watch",
|
||||
"build": "pnpm run -r clean && pnpm build:types && pnpm build:vite",
|
||||
"dev": "concurrently \"pnpm build:vite --watch\" \"tsx .vite/server.ts\"",
|
||||
"dev:coverage": "pnpm coverage:cypress:clean && VITE_COVERAGE=true pnpm dev",
|
||||
"release": "pnpm build",
|
||||
"lint": "eslint --cache --cache-strategy content --ignore-path .gitignore . && pnpm lint:jison && prettier --cache --check .",
|
||||
"lint:fix": "eslint --cache --cache-strategy content --fix --ignore-path .gitignore . && prettier --write . && tsx scripts/fixCSpell.ts",
|
||||
@@ -32,8 +32,8 @@
|
||||
"cypress": "cypress run",
|
||||
"cypress:open": "cypress open",
|
||||
"e2e": "start-server-and-test dev http://localhost:9000/ cypress",
|
||||
"e2e:coverage": "start-server-and-test dev:coverage http://localhost:9000/ cypress",
|
||||
"coverage:cypress:clean": "rimraf .nyc_output coverage/cypress",
|
||||
"e2e:coverage": "pnpm coverage:cypress:clean && VITE_COVERAGE=true pnpm e2e",
|
||||
"coverage:merge": "tsx scripts/coverage.ts",
|
||||
"coverage": "pnpm test:coverage --run && pnpm e2e:coverage && pnpm coverage:merge",
|
||||
"ci": "vitest run",
|
||||
@@ -74,7 +74,7 @@
|
||||
"@types/jsdom": "^21.1.1",
|
||||
"@types/lodash": "^4.14.194",
|
||||
"@types/mdast": "^3.0.11",
|
||||
"@types/node": "^20.11.17",
|
||||
"@types/node": "^20.11.10",
|
||||
"@types/prettier": "^2.7.2",
|
||||
"@types/rollup-plugin-visualizer": "^4.2.1",
|
||||
"@typescript-eslint/eslint-plugin": "^6.7.2",
|
||||
@@ -83,7 +83,6 @@
|
||||
"@vitest/spy": "^0.34.0",
|
||||
"@vitest/ui": "^0.34.0",
|
||||
"ajv": "^8.12.0",
|
||||
"chokidar": "^3.5.3",
|
||||
"concurrently": "^8.0.1",
|
||||
"cors": "^2.8.5",
|
||||
"cspell": "^8.3.2",
|
||||
@@ -109,9 +108,7 @@
|
||||
"jison": "^0.4.18",
|
||||
"js-yaml": "^4.1.0",
|
||||
"jsdom": "^22.0.0",
|
||||
"langium-cli": "3.0.1",
|
||||
"lint-staged": "^13.2.1",
|
||||
"markdown-table": "^3.0.3",
|
||||
"nyc": "^15.1.0",
|
||||
"path-browserify": "^1.0.1",
|
||||
"pnpm": "^8.6.8",
|
||||
|
@@ -1,45 +0,0 @@
|
||||
{
|
||||
"name": "@mermaid-js/flowchart-elk",
|
||||
"version": "1.0.0-rc.1",
|
||||
"description": "Flowchart plugin for mermaid with ELK layout",
|
||||
"module": "dist/mermaid-flowchart-elk.core.mjs",
|
||||
"types": "dist/packages/mermaid-flowchart-elk/src/detector.d.ts",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/mermaid-flowchart-elk.core.mjs",
|
||||
"types": "./dist/packages/mermaid-flowchart-elk/src/detector.d.ts"
|
||||
},
|
||||
"./*": "./*"
|
||||
},
|
||||
"keywords": [
|
||||
"diagram",
|
||||
"markdown",
|
||||
"flowchart",
|
||||
"elk",
|
||||
"mermaid"
|
||||
],
|
||||
"scripts": {
|
||||
"prepublishOnly": "pnpm -w run build"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mermaid-js/mermaid"
|
||||
},
|
||||
"author": "Knut Sveidqvist",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"d3": "^7.4.0",
|
||||
"dagre-d3-es": "7.0.10",
|
||||
"khroma": "^2.0.0",
|
||||
"elkjs": "^0.8.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"concurrently": "^8.0.0",
|
||||
"rimraf": "^5.0.0",
|
||||
"mermaid": "workspace:^"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
]
|
||||
}
|
@@ -1,32 +0,0 @@
|
||||
import type {
|
||||
ExternalDiagramDefinition,
|
||||
DiagramDetector,
|
||||
DiagramLoader,
|
||||
} from '../../mermaid/src/diagram-api/types.js';
|
||||
|
||||
const id = 'flowchart-elk';
|
||||
|
||||
const detector: DiagramDetector = (txt, config): boolean => {
|
||||
if (
|
||||
// If diagram explicitly states flowchart-elk
|
||||
/^\s*flowchart-elk/.test(txt) ||
|
||||
// If a flowchart/graph diagram has their default renderer set to elk
|
||||
(/^\s*flowchart|graph/.test(txt) && config?.flowchart?.defaultRenderer === 'elk')
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const loader: DiagramLoader = async () => {
|
||||
const { diagram } = await import('./diagram-definition.js');
|
||||
return { id, diagram };
|
||||
};
|
||||
|
||||
const plugin: ExternalDiagramDefinition = {
|
||||
id,
|
||||
detector,
|
||||
loader,
|
||||
};
|
||||
|
||||
export default plugin;
|
@@ -1,12 +0,0 @@
|
||||
// @ts-ignore: JISON typing missing
|
||||
import parser from '../../mermaid/src/diagrams/flowchart/parser/flow.jison';
|
||||
import * as db from '../../mermaid/src/diagrams/flowchart/flowDb.js';
|
||||
import styles from '../../mermaid/src/diagrams/flowchart/styles.js';
|
||||
import renderer from './flowRenderer-elk.js';
|
||||
|
||||
export const diagram = {
|
||||
db,
|
||||
renderer,
|
||||
parser,
|
||||
styles,
|
||||
};
|
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "../..",
|
||||
"outDir": "./dist",
|
||||
"types": ["vitest/importMeta", "vitest/globals"]
|
||||
},
|
||||
"include": ["./src/**/*.ts"],
|
||||
"typeRoots": ["./src/types"]
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mermaid-js/mermaid-zenuml",
|
||||
"version": "0.1.2",
|
||||
"version": "0.2.0",
|
||||
"description": "MermaidJS plugin for ZenUML integration",
|
||||
"module": "dist/mermaid-zenuml.core.mjs",
|
||||
"types": "dist/detector.d.ts",
|
||||
@@ -19,7 +19,6 @@
|
||||
"mermaid"
|
||||
],
|
||||
"scripts": {
|
||||
"clean": "rimraf dist",
|
||||
"prepublishOnly": "pnpm -w run build"
|
||||
},
|
||||
"repository": {
|
||||
|
@@ -5,6 +5,7 @@
|
||||
* This is a dummy parser that satisfies the mermaid API logic.
|
||||
*/
|
||||
export default {
|
||||
parser: { yy: {} },
|
||||
parse: () => {
|
||||
// no op
|
||||
},
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mermaid",
|
||||
"version": "11.0.0-alpha.6",
|
||||
"version": "10.9.1",
|
||||
"description": "Markdown-ish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
|
||||
"type": "module",
|
||||
"module": "./dist/mermaid.core.mjs",
|
||||
@@ -60,7 +60,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@braintree/sanitize-url": "^6.0.1",
|
||||
"@mermaid-js/parser": "workspace:^",
|
||||
"@types/d3-scale": "^4.0.3",
|
||||
"@types/d3-scale-chromatic": "^3.0.0",
|
||||
"cytoscape": "^3.28.1",
|
||||
"cytoscape-cose-bilkent": "^4.1.0",
|
||||
"d3": "^7.4.0",
|
||||
@@ -73,9 +74,11 @@
|
||||
"khroma": "^2.0.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"mdast-util-from-markdown": "^1.3.0",
|
||||
"non-layered-tidy-tree-layout": "^2.0.2",
|
||||
"stylis": "^4.1.3",
|
||||
"ts-dedent": "^2.2.0",
|
||||
"uuid": "^9.0.0"
|
||||
"uuid": "^9.0.0",
|
||||
"web-worker": "^1.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@adobe/jsonschema2md": "^7.1.4",
|
||||
@@ -83,7 +86,6 @@
|
||||
"@types/d3": "^7.4.0",
|
||||
"@types/d3-sankey": "^0.12.1",
|
||||
"@types/d3-scale": "^4.0.3",
|
||||
"@types/d3-scale-chromatic": "^3.0.0",
|
||||
"@types/d3-selection": "^3.0.5",
|
||||
"@types/d3-shape": "^3.1.1",
|
||||
"@types/dompurify": "^3.0.2",
|
||||
|
@@ -233,23 +233,6 @@ async function generateTypescript(mermaidConfigSchema: JSONSchemaType<MermaidCon
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Workaround for type duplication when a $ref property has siblings.
|
||||
*
|
||||
* @param json - The input JSON object.
|
||||
*
|
||||
* @see https://github.com/bcherny/json-schema-to-typescript/issues/193
|
||||
*/
|
||||
function removeProp(json: any, name: string) {
|
||||
for (const prop in json) {
|
||||
if (prop === name) {
|
||||
delete json[prop];
|
||||
} else if (typeof json[prop] === 'object') {
|
||||
removeProp(json[prop], name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Main function */
|
||||
async function main() {
|
||||
if (verifyOnly) {
|
||||
@@ -260,8 +243,6 @@ async function main() {
|
||||
|
||||
const configJsonSchema = await loadJsonSchemaFromYaml();
|
||||
|
||||
removeProp(configJsonSchema, 'default');
|
||||
|
||||
validateSchema(configJsonSchema);
|
||||
|
||||
// Generate types from JSON Schema
|
||||
|
@@ -252,11 +252,12 @@ export function transformMarkdownAst({
|
||||
node.lang = MERMAID_KEYWORD;
|
||||
return [node];
|
||||
} else if (MERMAID_EXAMPLE_KEYWORDS.includes(node.lang)) {
|
||||
// Return 2 nodes:
|
||||
// If Vitepress, return only the original node with the language now set to 'mermaid-example' (will be rendered using custom renderer)
|
||||
// Else Return 2 nodes:
|
||||
// 1. the original node with the language now set to 'mermaid-example' (will be rendered as code), and
|
||||
// 2. a copy of the original node with the language set to 'mermaid' (will be rendered as a diagram)
|
||||
node.lang = MERMAID_CODE_ONLY_KEYWORD;
|
||||
return [node, Object.assign({}, node, { lang: MERMAID_KEYWORD })];
|
||||
return vitepress ? [node] : [node, Object.assign({}, node, { lang: MERMAID_KEYWORD })];
|
||||
}
|
||||
|
||||
// Transform these blocks into block quotes.
|
||||
|
@@ -1,8 +1,10 @@
|
||||
import * as configApi from './config.js';
|
||||
import { log } from './logger.js';
|
||||
import { getDiagram, registerDiagram } from './diagram-api/diagramAPI.js';
|
||||
import { detectType, getDiagramLoader } from './diagram-api/detectType.js';
|
||||
import { UnknownDiagramError } from './errors.js';
|
||||
import { encodeEntities } from './utils.js';
|
||||
|
||||
import type { DetailedError } from './utils.js';
|
||||
import type { DiagramDefinition, DiagramMetadata } from './diagram-api/types.js';
|
||||
|
||||
@@ -13,44 +15,47 @@ export type ParseErrorFunction = (err: string | DetailedError | unknown, hash?:
|
||||
* @privateRemarks This is exported as part of the public mermaidAPI.
|
||||
*/
|
||||
export class Diagram {
|
||||
public static async fromText(text: string, metadata: Pick<DiagramMetadata, 'title'> = {}) {
|
||||
const config = configApi.getConfig();
|
||||
const type = detectType(text, config);
|
||||
text = encodeEntities(text) + '\n';
|
||||
type = 'graph';
|
||||
parser: DiagramDefinition['parser'];
|
||||
renderer: DiagramDefinition['renderer'];
|
||||
db: DiagramDefinition['db'];
|
||||
private init?: DiagramDefinition['init'];
|
||||
|
||||
private detectError?: UnknownDiagramError;
|
||||
constructor(public text: string, public metadata: Pick<DiagramMetadata, 'title'> = {}) {
|
||||
this.text = encodeEntities(text);
|
||||
this.text += '\n';
|
||||
const cnf = configApi.getConfig();
|
||||
try {
|
||||
getDiagram(type);
|
||||
this.type = detectType(text, cnf);
|
||||
} catch (e) {
|
||||
const loader = getDiagramLoader(type);
|
||||
if (!loader) {
|
||||
throw new UnknownDiagramError(`Diagram ${type} not found.`);
|
||||
}
|
||||
// Diagram not available, loading it.
|
||||
// new diagram will try getDiagram again and if fails then it is a valid throw
|
||||
const { id, diagram } = await loader();
|
||||
registerDiagram(id, diagram);
|
||||
this.type = 'error';
|
||||
this.detectError = e as UnknownDiagramError;
|
||||
}
|
||||
const { db, parser, renderer, init } = getDiagram(type);
|
||||
if (parser.parser) {
|
||||
// The parser.parser.yy is only present in JISON parsers. So, we'll only set if required.
|
||||
parser.parser.yy = db;
|
||||
}
|
||||
db.clear?.();
|
||||
init?.(config);
|
||||
// This block was added for legacy compatibility. Use frontmatter instead of adding more special cases.
|
||||
if (metadata.title) {
|
||||
db.setDiagramTitle?.(metadata.title);
|
||||
}
|
||||
await parser.parse(text);
|
||||
return new Diagram(type, text, db, parser, renderer);
|
||||
const diagram = getDiagram(this.type);
|
||||
log.debug('Type ' + this.type);
|
||||
// Setup diagram
|
||||
this.db = diagram.db;
|
||||
this.renderer = diagram.renderer;
|
||||
this.parser = diagram.parser;
|
||||
this.parser.parser.yy = this.db;
|
||||
this.init = diagram.init;
|
||||
this.parse();
|
||||
}
|
||||
|
||||
private constructor(
|
||||
public type: string,
|
||||
public text: string,
|
||||
public db: DiagramDefinition['db'],
|
||||
public parser: DiagramDefinition['parser'],
|
||||
public renderer: DiagramDefinition['renderer']
|
||||
) {}
|
||||
parse() {
|
||||
if (this.detectError) {
|
||||
throw this.detectError;
|
||||
}
|
||||
this.db.clear?.();
|
||||
const config = configApi.getConfig();
|
||||
this.init?.(config);
|
||||
// This block was added for legacy compatibility. Use frontmatter instead of adding more special cases.
|
||||
if (this.metadata.title) {
|
||||
this.db.setDiagramTitle?.(this.metadata.title);
|
||||
}
|
||||
this.parser.parse(this.text);
|
||||
}
|
||||
|
||||
async render(id: string, version: string) {
|
||||
await this.renderer.draw(this.text, id, version, this);
|
||||
@@ -64,3 +69,34 @@ export class Diagram {
|
||||
return this.type;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the text asynchronously and generate a Diagram object asynchronously.
|
||||
* **Warning:** This function may be changed in the future.
|
||||
* @alpha
|
||||
* @param text - The mermaid diagram definition.
|
||||
* @param metadata - Diagram metadata, defined in YAML.
|
||||
* @returns A the Promise of a Diagram object.
|
||||
* @throws {@link UnknownDiagramError} if the diagram type can not be found.
|
||||
* @privateRemarks This is exported as part of the public mermaidAPI.
|
||||
*/
|
||||
export const getDiagramFromText = async (
|
||||
text: string,
|
||||
metadata: Pick<DiagramMetadata, 'title'> = {}
|
||||
): Promise<Diagram> => {
|
||||
const type = detectType(text, configApi.getConfig());
|
||||
try {
|
||||
// Trying to find the diagram
|
||||
getDiagram(type);
|
||||
} catch (error) {
|
||||
const loader = getDiagramLoader(type);
|
||||
if (!loader) {
|
||||
throw new UnknownDiagramError(`Diagram ${type} not found.`);
|
||||
}
|
||||
// Diagram not available, loading it.
|
||||
// new diagram will try getDiagram again and if fails then it is a valid throw
|
||||
const { id, diagram } = await loader();
|
||||
registerDiagram(id, diagram);
|
||||
}
|
||||
return new Diagram(text, metadata);
|
||||
};
|
||||
|
@@ -61,7 +61,7 @@ export interface MermaidConfig {
|
||||
* You may also use `themeCSS` to override this value.
|
||||
*
|
||||
*/
|
||||
theme?: 'default' | 'forest' | 'dark' | 'neutral' | 'null';
|
||||
theme?: string | 'default' | 'forest' | 'dark' | 'neutral' | 'null';
|
||||
themeVariables?: any;
|
||||
themeCSS?: string;
|
||||
/**
|
||||
@@ -87,11 +87,26 @@ export interface MermaidConfig {
|
||||
* This option decides the amount of logging to be used by mermaid.
|
||||
*
|
||||
*/
|
||||
logLevel?: 'trace' | 0 | 'debug' | 1 | 'info' | 2 | 'warn' | 3 | 'error' | 4 | 'fatal' | 5;
|
||||
logLevel?:
|
||||
| number
|
||||
| string
|
||||
| 0
|
||||
| 2
|
||||
| 1
|
||||
| 'trace'
|
||||
| 'debug'
|
||||
| 'info'
|
||||
| 'warn'
|
||||
| 'error'
|
||||
| 'fatal'
|
||||
| 3
|
||||
| 4
|
||||
| 5
|
||||
| undefined;
|
||||
/**
|
||||
* Level of trust for parsed diagram
|
||||
*/
|
||||
securityLevel?: 'strict' | 'loose' | 'antiscript' | 'sandbox';
|
||||
securityLevel?: string | 'strict' | 'loose' | 'antiscript' | 'sandbox' | undefined;
|
||||
/**
|
||||
* Dictates whether mermaid starts on Page load
|
||||
*/
|
||||
@@ -154,43 +169,19 @@ export interface MermaidConfig {
|
||||
gitGraph?: GitGraphDiagramConfig;
|
||||
c4?: C4DiagramConfig;
|
||||
sankey?: SankeyDiagramConfig;
|
||||
packet?: PacketDiagramConfig;
|
||||
block?: BlockDiagramConfig;
|
||||
dompurifyConfig?: DOMPurifyConfiguration;
|
||||
wrap?: boolean;
|
||||
fontSize?: number;
|
||||
}
|
||||
/**
|
||||
* The object containing configurations specific for packet diagrams.
|
||||
* The object containing configurations specific for block diagrams.
|
||||
*
|
||||
* This interface was referenced by `MermaidConfig`'s JSON-Schema
|
||||
* via the `definition` "PacketDiagramConfig".
|
||||
* via the `definition` "BlockDiagramConfig".
|
||||
*/
|
||||
export interface PacketDiagramConfig extends BaseDiagramConfig {
|
||||
/**
|
||||
* The height of each row in the packet diagram.
|
||||
*/
|
||||
rowHeight?: number;
|
||||
/**
|
||||
* The width of each bit in the packet diagram.
|
||||
*/
|
||||
bitWidth?: number;
|
||||
/**
|
||||
* The number of bits to display per row.
|
||||
*/
|
||||
bitsPerRow?: number;
|
||||
/**
|
||||
* Toggle to display or hide bit numbers.
|
||||
*/
|
||||
showBits?: boolean;
|
||||
/**
|
||||
* The horizontal padding between the blocks in a row.
|
||||
*/
|
||||
paddingX?: number;
|
||||
/**
|
||||
* The vertical padding between the rows.
|
||||
*/
|
||||
paddingY?: number;
|
||||
export interface BlockDiagramConfig extends BaseDiagramConfig {
|
||||
padding?: number;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `MermaidConfig`'s JSON-Schema
|
||||
@@ -206,15 +197,6 @@ export interface BaseDiagramConfig {
|
||||
*/
|
||||
useMaxWidth?: boolean;
|
||||
}
|
||||
/**
|
||||
* The object containing configurations specific for block diagrams.
|
||||
*
|
||||
* This interface was referenced by `MermaidConfig`'s JSON-Schema
|
||||
* via the `definition` "BlockDiagramConfig".
|
||||
*/
|
||||
export interface BlockDiagramConfig extends BaseDiagramConfig {
|
||||
padding?: number;
|
||||
}
|
||||
/**
|
||||
* The object containing configurations specific for c4 diagrams
|
||||
*
|
||||
@@ -825,8 +807,8 @@ export interface XYChartConfig extends BaseDiagramConfig {
|
||||
* Should show the chart title
|
||||
*/
|
||||
showTitle?: boolean;
|
||||
xAxis?: XYChartAxisConfig;
|
||||
yAxis?: XYChartAxisConfig;
|
||||
xAxis?: XYChartAxisConfig1;
|
||||
yAxis?: XYChartAxisConfig2;
|
||||
/**
|
||||
* How to plot will be drawn horizontal or vertical
|
||||
*/
|
||||
@@ -836,6 +818,104 @@ export interface XYChartConfig extends BaseDiagramConfig {
|
||||
*/
|
||||
plotReservedSpacePercent?: number;
|
||||
}
|
||||
/**
|
||||
* This object contains configuration for XYChart axis config
|
||||
*/
|
||||
export interface XYChartAxisConfig1 {
|
||||
/**
|
||||
* Should show the axis labels (tick text)
|
||||
*/
|
||||
showLabel?: boolean;
|
||||
/**
|
||||
* font size of the axis labels (tick text)
|
||||
*/
|
||||
labelFontSize?: number;
|
||||
/**
|
||||
* top and bottom space from axis label (tick text)
|
||||
*/
|
||||
labelPadding?: number;
|
||||
/**
|
||||
* Should show the axis title
|
||||
*/
|
||||
showTitle?: boolean;
|
||||
/**
|
||||
* font size of the axis title
|
||||
*/
|
||||
titleFontSize?: number;
|
||||
/**
|
||||
* top and bottom space from axis title
|
||||
*/
|
||||
titlePadding?: number;
|
||||
/**
|
||||
* Should show the axis tick lines
|
||||
*/
|
||||
showTick?: boolean;
|
||||
/**
|
||||
* length of the axis tick lines
|
||||
*/
|
||||
tickLength?: number;
|
||||
/**
|
||||
* width of the axis tick lines
|
||||
*/
|
||||
tickWidth?: number;
|
||||
/**
|
||||
* Show line across the axis
|
||||
*/
|
||||
showAxisLine?: boolean;
|
||||
/**
|
||||
* Width of the axis line
|
||||
*/
|
||||
axisLineWidth?: number;
|
||||
}
|
||||
/**
|
||||
* This object contains configuration for XYChart axis config
|
||||
*/
|
||||
export interface XYChartAxisConfig2 {
|
||||
/**
|
||||
* Should show the axis labels (tick text)
|
||||
*/
|
||||
showLabel?: boolean;
|
||||
/**
|
||||
* font size of the axis labels (tick text)
|
||||
*/
|
||||
labelFontSize?: number;
|
||||
/**
|
||||
* top and bottom space from axis label (tick text)
|
||||
*/
|
||||
labelPadding?: number;
|
||||
/**
|
||||
* Should show the axis title
|
||||
*/
|
||||
showTitle?: boolean;
|
||||
/**
|
||||
* font size of the axis title
|
||||
*/
|
||||
titleFontSize?: number;
|
||||
/**
|
||||
* top and bottom space from axis title
|
||||
*/
|
||||
titlePadding?: number;
|
||||
/**
|
||||
* Should show the axis tick lines
|
||||
*/
|
||||
showTick?: boolean;
|
||||
/**
|
||||
* length of the axis tick lines
|
||||
*/
|
||||
tickLength?: number;
|
||||
/**
|
||||
* width of the axis tick lines
|
||||
*/
|
||||
tickWidth?: number;
|
||||
/**
|
||||
* Show line across the axis
|
||||
*/
|
||||
showAxisLine?: boolean;
|
||||
/**
|
||||
* Width of the axis line
|
||||
*/
|
||||
axisLineWidth?: number;
|
||||
}
|
||||
/**
|
||||
* The object containing configurations specific for entity relationship diagrams
|
||||
*
|
||||
@@ -856,7 +936,7 @@ export interface ErDiagramConfig extends BaseDiagramConfig {
|
||||
/**
|
||||
* Directional bias for layout of entities
|
||||
*/
|
||||
layoutDirection?: 'TB' | 'BT' | 'LR' | 'RL';
|
||||
layoutDirection?: string | 'TB' | 'BT' | 'LR' | 'RL';
|
||||
/**
|
||||
* The minimum width of an entity box. Expressed in pixels.
|
||||
*/
|
||||
@@ -921,7 +1001,7 @@ export interface StateDiagramConfig extends BaseDiagramConfig {
|
||||
* Decides which rendering engine that is to be used for the rendering.
|
||||
*
|
||||
*/
|
||||
defaultRenderer?: 'dagre-d3' | 'dagre-wrapper' | 'elk';
|
||||
defaultRenderer?: string | 'dagre-d3' | 'dagre-wrapper' | 'elk';
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `MermaidConfig`'s JSON-Schema
|
||||
@@ -945,7 +1025,7 @@ export interface ClassDiagramConfig extends BaseDiagramConfig {
|
||||
* Decides which rendering engine that is to be used for the rendering.
|
||||
*
|
||||
*/
|
||||
defaultRenderer?: 'dagre-d3' | 'dagre-wrapper' | 'elk';
|
||||
defaultRenderer?: string | 'dagre-d3' | 'dagre-wrapper' | 'elk';
|
||||
nodeSpacing?: number;
|
||||
rankSpacing?: number;
|
||||
/**
|
||||
@@ -1005,7 +1085,7 @@ export interface JourneyDiagramConfig extends BaseDiagramConfig {
|
||||
/**
|
||||
* Multiline message alignment
|
||||
*/
|
||||
messageAlign?: 'left' | 'center' | 'right';
|
||||
messageAlign?: string | 'left' | 'center' | 'right';
|
||||
/**
|
||||
* Prolongs the edge of the diagram downwards.
|
||||
*
|
||||
@@ -1084,7 +1164,7 @@ export interface TimelineDiagramConfig extends BaseDiagramConfig {
|
||||
/**
|
||||
* Multiline message alignment
|
||||
*/
|
||||
messageAlign?: 'left' | 'center' | 'right';
|
||||
messageAlign?: string | 'left' | 'center' | 'right';
|
||||
/**
|
||||
* Prolongs the edge of the diagram downwards.
|
||||
*
|
||||
@@ -1195,7 +1275,7 @@ export interface GanttDiagramConfig extends BaseDiagramConfig {
|
||||
* Controls the display mode.
|
||||
*
|
||||
*/
|
||||
displayMode?: '' | 'compact';
|
||||
displayMode?: string | 'compact';
|
||||
/**
|
||||
* On which day a week-based interval should start
|
||||
*
|
||||
@@ -1254,7 +1334,7 @@ export interface SequenceDiagramConfig extends BaseDiagramConfig {
|
||||
/**
|
||||
* Multiline message alignment
|
||||
*/
|
||||
messageAlign?: 'left' | 'center' | 'right';
|
||||
messageAlign?: string | 'left' | 'center' | 'right';
|
||||
/**
|
||||
* Mirror actors under diagram
|
||||
*
|
||||
@@ -1311,7 +1391,7 @@ export interface SequenceDiagramConfig extends BaseDiagramConfig {
|
||||
/**
|
||||
* This sets the text alignment of actor-attached notes
|
||||
*/
|
||||
noteAlign?: 'left' | 'center' | 'right';
|
||||
noteAlign?: string | 'left' | 'center' | 'right';
|
||||
/**
|
||||
* This sets the font size of actor messages
|
||||
*/
|
||||
@@ -1395,7 +1475,7 @@ export interface FlowchartDiagramConfig extends BaseDiagramConfig {
|
||||
* Defines how mermaid renders curves for flowcharts.
|
||||
*
|
||||
*/
|
||||
curve?: 'basis' | 'linear' | 'cardinal';
|
||||
curve?: string | 'basis' | 'linear' | 'cardinal';
|
||||
/**
|
||||
* Represents the padding between the labels and the shape
|
||||
*
|
||||
@@ -1407,7 +1487,7 @@ export interface FlowchartDiagramConfig extends BaseDiagramConfig {
|
||||
* Decides which rendering engine that is to be used for the rendering.
|
||||
*
|
||||
*/
|
||||
defaultRenderer?: 'dagre-d3' | 'dagre-wrapper' | 'elk';
|
||||
defaultRenderer?: string | 'dagre-d3' | 'dagre-wrapper' | 'elk';
|
||||
/**
|
||||
* Width of nodes where text is wrapped.
|
||||
*
|
||||
@@ -1431,7 +1511,13 @@ export interface SankeyDiagramConfig extends BaseDiagramConfig {
|
||||
*
|
||||
*/
|
||||
linkColor?: SankeyLinkColor | string;
|
||||
nodeAlignment?: SankeyNodeAlignment;
|
||||
/**
|
||||
* Controls the alignment of the Sankey diagrams.
|
||||
*
|
||||
* See <https://github.com/d3/d3-sankey#alignments>.
|
||||
*
|
||||
*/
|
||||
nodeAlignment?: 'left' | 'right' | 'center' | 'justify';
|
||||
useMaxWidth?: boolean;
|
||||
/**
|
||||
* Toggle to display or hide values along with title.
|
||||
|
@@ -257,9 +257,6 @@ const config: RequiredDeep<MermaidConfig> = {
|
||||
// TODO: can we make this default to `true` instead?
|
||||
useMaxWidth: false,
|
||||
},
|
||||
packet: {
|
||||
...defaultConfigJson.packet,
|
||||
},
|
||||
};
|
||||
|
||||
const keyify = (obj: any, prefix = ''): string[] =>
|
||||
|
@@ -71,9 +71,10 @@ export const registerLazyLoadedDiagrams = (...diagrams: ExternalDiagramDefinitio
|
||||
|
||||
export const addDetector = (key: string, detector: DiagramDetector, loader?: DiagramLoader) => {
|
||||
if (detectors[key]) {
|
||||
log.warn(`Detector with key ${key} already exists. Overwriting.`);
|
||||
log.error(`Detector with key ${key} already exists`);
|
||||
} else {
|
||||
detectors[key] = { detector, loader };
|
||||
}
|
||||
detectors[key] = { detector, loader };
|
||||
log.debug(`Detector with key ${key} added${loader ? ' with loader' : ''}`);
|
||||
};
|
||||
|
||||
|
@@ -20,7 +20,6 @@ import flowchartElk from '../diagrams/flowchart/elk/detector.js';
|
||||
import timeline from '../diagrams/timeline/detector.js';
|
||||
import mindmap from '../diagrams/mindmap/detector.js';
|
||||
import sankey from '../diagrams/sankey/sankeyDetector.js';
|
||||
import { packet } from '../diagrams/packet/detector.js';
|
||||
import block from '../diagrams/block/blockDetector.js';
|
||||
import { registerLazyLoadedDiagrams } from './detectType.js';
|
||||
import { registerDiagram } from './diagramAPI.js';
|
||||
@@ -52,6 +51,7 @@ export const addDiagrams = () => {
|
||||
},
|
||||
},
|
||||
parser: {
|
||||
parser: { yy: {} },
|
||||
parse: () => {
|
||||
throw new Error(
|
||||
'Diagrams beginning with --- are not valid. ' +
|
||||
@@ -88,7 +88,6 @@ export const addDiagrams = () => {
|
||||
journey,
|
||||
quadrantChart,
|
||||
sankey,
|
||||
packet,
|
||||
xychart,
|
||||
block
|
||||
);
|
||||
|
@@ -2,12 +2,12 @@ import { detectType } from './detectType.js';
|
||||
import { getDiagram, registerDiagram } from './diagramAPI.js';
|
||||
import { addDiagrams } from './diagram-orchestration.js';
|
||||
import type { DiagramDetector } from './types.js';
|
||||
import { Diagram } from '../Diagram.js';
|
||||
import { getDiagramFromText } from '../Diagram.js';
|
||||
import { it, describe, expect, beforeAll } from 'vitest';
|
||||
|
||||
addDiagrams();
|
||||
beforeAll(async () => {
|
||||
await Diagram.fromText('sequenceDiagram');
|
||||
await getDiagramFromText('sequenceDiagram');
|
||||
});
|
||||
|
||||
describe('DiagramAPI', () => {
|
||||
@@ -39,6 +39,7 @@ describe('DiagramAPI', () => {
|
||||
parse: (_text) => {
|
||||
return;
|
||||
},
|
||||
parser: { yy: {} },
|
||||
},
|
||||
renderer: {
|
||||
draw: () => {
|
||||
|
@@ -49,7 +49,7 @@ export const registerDiagram = (
|
||||
detector?: DiagramDetector
|
||||
) => {
|
||||
if (diagrams[id]) {
|
||||
log.warn(`Diagram with id ${id} already registered. Overwriting.`);
|
||||
throw new Error(`Diagram ${id} already registered.`);
|
||||
}
|
||||
diagrams[id] = diagram;
|
||||
if (detector) {
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import type { GanttDiagramConfig, MermaidConfig } from '../config.type.js';
|
||||
import type { MermaidConfig } from '../config.type.js';
|
||||
import { frontMatterRegex } from './regexes.js';
|
||||
// The "* as yaml" part is necessary for tree-shaking
|
||||
import * as yaml from 'js-yaml';
|
||||
@@ -6,7 +6,7 @@ import * as yaml from 'js-yaml';
|
||||
interface FrontMatterMetadata {
|
||||
title?: string;
|
||||
// Allows custom display modes. Currently used for compact mode in gantt charts.
|
||||
displayMode?: GanttDiagramConfig['displayMode'];
|
||||
displayMode?: string;
|
||||
config?: MermaidConfig;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ export function extractFrontMatter(text: string): FrontMatterResult {
|
||||
|
||||
// Only add properties that are explicitly supported, if they exist
|
||||
if (parsed.displayMode) {
|
||||
metadata.displayMode = parsed.displayMode.toString() as GanttDiagramConfig['displayMode'];
|
||||
metadata.displayMode = parsed.displayMode.toString();
|
||||
}
|
||||
if (parsed.title) {
|
||||
metadata.title = parsed.title.toString();
|
||||
|
@@ -1,8 +1,7 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import type * as d3 from 'd3';
|
||||
import type { SetRequired } from 'type-fest';
|
||||
import type { Diagram } from '../Diagram.js';
|
||||
import type { BaseDiagramConfig, MermaidConfig } from '../config.type.js';
|
||||
import type * as d3 from 'd3';
|
||||
|
||||
export interface DiagramMetadata {
|
||||
title?: string;
|
||||
@@ -40,22 +39,6 @@ export interface DiagramDB {
|
||||
bindFunctions?: (element: Element) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* DiagramDB with fields that is required for all new diagrams.
|
||||
*/
|
||||
export type DiagramDBBase<T extends BaseDiagramConfig> = {
|
||||
getConfig: () => Required<T>;
|
||||
} & SetRequired<
|
||||
DiagramDB,
|
||||
| 'clear'
|
||||
| 'getAccTitle'
|
||||
| 'getDiagramTitle'
|
||||
| 'getAccDescription'
|
||||
| 'setAccDescription'
|
||||
| 'setAccTitle'
|
||||
| 'setDiagramTitle'
|
||||
>;
|
||||
|
||||
// This is what is returned from getClasses(...) methods.
|
||||
// It is slightly renamed to ..StyleClassDef instead of just ClassDef because "class" is a greatly ambiguous and overloaded word.
|
||||
// It makes it clear we're working with a style class definition, even though defining the type is currently difficult.
|
||||
@@ -121,8 +104,8 @@ export type DrawDefinition = (
|
||||
) => void | Promise<void>;
|
||||
|
||||
export interface ParserDefinition {
|
||||
parse: (text: string) => void | Promise<void>;
|
||||
parser?: { yy: DiagramDB };
|
||||
parse: (text: string) => void;
|
||||
parser: { yy: DiagramDB };
|
||||
}
|
||||
|
||||
export type HTML = d3.Selection<HTMLIFrameElement, unknown, Element | null, unknown>;
|
||||
|
@@ -1,39 +1,16 @@
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import { Diagram } from './Diagram.js';
|
||||
import { Diagram, getDiagramFromText } from './Diagram.js';
|
||||
import { addDetector } from './diagram-api/detectType.js';
|
||||
import { addDiagrams } from './diagram-api/diagram-orchestration.js';
|
||||
import type { DiagramLoader } from './diagram-api/types.js';
|
||||
|
||||
addDiagrams();
|
||||
|
||||
const getDummyDiagram = (id: string, title?: string): Awaited<ReturnType<DiagramLoader>> => {
|
||||
return {
|
||||
id,
|
||||
diagram: {
|
||||
db: {
|
||||
getDiagramTitle: () => title ?? id,
|
||||
},
|
||||
parser: {
|
||||
parse: () => {
|
||||
// no-op
|
||||
},
|
||||
},
|
||||
renderer: {
|
||||
draw: () => {
|
||||
// no-op
|
||||
},
|
||||
},
|
||||
styles: {},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
describe('diagram detection', () => {
|
||||
test('should detect inbuilt diagrams', async () => {
|
||||
const graph = (await Diagram.fromText('graph TD; A-->B')) as Diagram;
|
||||
const graph = (await getDiagramFromText('graph TD; A-->B')) as Diagram;
|
||||
expect(graph).toBeInstanceOf(Diagram);
|
||||
expect(graph.type).toBe('flowchart-v2');
|
||||
const sequence = (await Diagram.fromText(
|
||||
const sequence = (await getDiagramFromText(
|
||||
'sequenceDiagram; Alice->>+John: Hello John, how are you?'
|
||||
)) as Diagram;
|
||||
expect(sequence).toBeInstanceOf(Diagram);
|
||||
@@ -44,33 +21,41 @@ describe('diagram detection', () => {
|
||||
addDetector(
|
||||
'loki',
|
||||
(str) => str.startsWith('loki'),
|
||||
() => Promise.resolve(getDummyDiagram('loki'))
|
||||
() =>
|
||||
Promise.resolve({
|
||||
id: 'loki',
|
||||
diagram: {
|
||||
db: {},
|
||||
parser: {
|
||||
parse: () => {
|
||||
// no-op
|
||||
},
|
||||
parser: {
|
||||
yy: {},
|
||||
},
|
||||
},
|
||||
renderer: {
|
||||
draw: () => {
|
||||
// no-op
|
||||
},
|
||||
},
|
||||
styles: {},
|
||||
},
|
||||
})
|
||||
);
|
||||
const diagram = await Diagram.fromText('loki TD; A-->B');
|
||||
const diagram = (await getDiagramFromText('loki TD; A-->B')) as Diagram;
|
||||
expect(diagram).toBeInstanceOf(Diagram);
|
||||
expect(diagram.type).toBe('loki');
|
||||
});
|
||||
|
||||
test('should allow external diagrams to override internal ones with same ID', async () => {
|
||||
const title = 'overridden';
|
||||
addDetector(
|
||||
'flowchart-elk',
|
||||
(str) => str.startsWith('flowchart-elk'),
|
||||
() => Promise.resolve(getDummyDiagram('flowchart-elk', title))
|
||||
);
|
||||
const diagram = await Diagram.fromText('flowchart-elk TD; A-->B');
|
||||
expect(diagram).toBeInstanceOf(Diagram);
|
||||
expect(diagram.db.getDiagramTitle?.()).toBe(title);
|
||||
});
|
||||
|
||||
test('should throw the right error for incorrect diagram', async () => {
|
||||
await expect(Diagram.fromText('graph TD; A-->')).rejects.toThrowErrorMatchingInlineSnapshot(`
|
||||
await expect(getDiagramFromText('graph TD; A-->')).rejects.toThrowErrorMatchingInlineSnapshot(`
|
||||
"Parse error on line 2:
|
||||
graph TD; A-->
|
||||
--------------^
|
||||
Expecting 'AMP', 'COLON', 'PIPE', 'TESTSTR', 'DOWN', 'DEFAULT', 'NUM', 'COMMA', 'NODE_STRING', 'BRKT', 'MINUS', 'MULT', 'UNICODE_TEXT', got 'EOF'"
|
||||
`);
|
||||
await expect(Diagram.fromText('sequenceDiagram; A-->B')).rejects
|
||||
await expect(getDiagramFromText('sequenceDiagram; A-->B')).rejects
|
||||
.toThrowErrorMatchingInlineSnapshot(`
|
||||
"Parse error on line 1:
|
||||
...quenceDiagram; A-->B
|
||||
@@ -80,13 +65,13 @@ Expecting 'TXT', got 'NEWLINE'"
|
||||
});
|
||||
|
||||
test('should throw the right error for unregistered diagrams', async () => {
|
||||
await expect(Diagram.fromText('thor TD; A-->B')).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
await expect(getDiagramFromText('thor TD; A-->B')).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||
'"No diagram type detected matching given configuration for text: thor TD; A-->B"'
|
||||
);
|
||||
});
|
||||
|
||||
test('should consider entity codes when present in diagram defination', async () => {
|
||||
const diagram = await Diagram.fromText(`sequenceDiagram
|
||||
const diagram = await getDiagramFromText(`sequenceDiagram
|
||||
A->>B: I #9829; you!
|
||||
B->>A: I #9829; you #infin; times more!`);
|
||||
// @ts-ignore: we need to add types for sequenceDb which will be done in separate PR
|
||||
|
@@ -1,9 +1,11 @@
|
||||
import clone from 'lodash-es/clone.js';
|
||||
import * as configApi from '../../config.js';
|
||||
import type { DiagramDB } from '../../diagram-api/types.js';
|
||||
import { log } from '../../logger.js';
|
||||
import type { BlockConfig, BlockType, Block, ClassDef } from './blockTypes.js';
|
||||
import * as configApi from '../../config.js';
|
||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
||||
import { clear as commonClear } from '../common/commonDb.js';
|
||||
import type { Block, ClassDef } from './blockTypes.js';
|
||||
import { log } from '../../logger.js';
|
||||
import clone from 'lodash-es/clone.js';
|
||||
import common from '../common/common.js';
|
||||
|
||||
// Initialize the node database for simple lookups
|
||||
let blockDatabase: Record<string, Block> = {};
|
||||
@@ -14,9 +16,12 @@ const COLOR_KEYWORD = 'color';
|
||||
const FILL_KEYWORD = 'fill';
|
||||
const BG_FILL = 'bgFill';
|
||||
const STYLECLASS_SEP = ',';
|
||||
const config = getConfig();
|
||||
|
||||
let classes = {} as Record<string, ClassDef>;
|
||||
|
||||
const sanitizeText = (txt:string) => common.sanitizeText(txt, config);
|
||||
|
||||
/**
|
||||
* Called when the parser comes across a (style) class definition
|
||||
* @example classDef my-style fill:#f96;
|
||||
@@ -87,6 +92,9 @@ const populateBlockDatabase = (_blockList: Block[] | Block[][], parent: Block):
|
||||
const blockList = _blockList.flat();
|
||||
const children = [];
|
||||
for (const block of blockList) {
|
||||
if (block.label) {
|
||||
block.label = sanitizeText(block.label);
|
||||
}
|
||||
if (block.type === 'classDef') {
|
||||
addStyleClass(block.id, block.css);
|
||||
continue;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user