mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-10-05 07:09:40 +02:00
Compare commits
12 Commits
copilot/fi
...
v10.9.4
Author | SHA1 | Date | |
---|---|---|---|
![]() |
80dcf2eaad | ||
![]() |
cdff69fe13 | ||
![]() |
2ce5801568 | ||
![]() |
2efe338cb5 | ||
![]() |
7509b066f1 | ||
![]() |
85ec96a72d | ||
![]() |
9301a5788a | ||
![]() |
2bedd0ef87 | ||
![]() |
92a07ffe40 | ||
![]() |
4dd4997c4d | ||
![]() |
fc61512a0a | ||
![]() |
402abdf883 |
@@ -1,46 +0,0 @@
|
||||
export interface PackageOptions {
|
||||
name: string;
|
||||
packageName: string;
|
||||
file: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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-layout-elk': {
|
||||
name: 'mermaid-layout-elk',
|
||||
packageName: 'mermaid-layout-elk',
|
||||
file: 'layouts.ts',
|
||||
},
|
||||
'mermaid-layout-tidy-tree': {
|
||||
name: 'mermaid-layout-tidy-tree',
|
||||
packageName: 'mermaid-layout-tidy-tree',
|
||||
file: 'index.ts',
|
||||
},
|
||||
examples: {
|
||||
name: 'mermaid-examples',
|
||||
packageName: 'examples',
|
||||
file: 'index.ts',
|
||||
},
|
||||
} as const satisfies Record<string, PackageOptions>;
|
@@ -1,5 +0,0 @@
|
||||
import { generate } from 'langium-cli';
|
||||
|
||||
export async function generateLangium() {
|
||||
await generate({ file: `./packages/parser/langium-config.json` });
|
||||
}
|
@@ -1,127 +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',
|
||||
'kanban',
|
||||
'timeline',
|
||||
'gitGraph',
|
||||
'c4',
|
||||
'sankey',
|
||||
'block',
|
||||
'packet',
|
||||
'architecture',
|
||||
'radar',
|
||||
] 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,28 +0,0 @@
|
||||
/* eslint-disable no-console */
|
||||
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`);
|
||||
if (out.length > 0) {
|
||||
console.log(out.toString());
|
||||
}
|
||||
} catch (e) {
|
||||
if (e.stdout.length > 0) {
|
||||
console.error(e.stdout.toString());
|
||||
}
|
||||
if (e.stderr.length > 0) {
|
||||
console.error(e.stderr.toString());
|
||||
}
|
||||
// Exit the build process if we are in CI
|
||||
if (process.env.CI) {
|
||||
throw new Error(`Failed to build types for ${packageName}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (const { packageName } of Object.values(packageOptions)) {
|
||||
buildType(packageName);
|
||||
}
|
@@ -1,8 +0,0 @@
|
||||
# Changesets
|
||||
|
||||
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
|
||||
with multi-package repos, or single-package repos to help you version and publish your code. You can
|
||||
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
|
||||
|
||||
We have a quick list of common questions to get you started engaging with this project in
|
||||
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
|
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'mermaid': patch
|
||||
---
|
||||
|
||||
fix: Render newlines as spaces in class diagrams
|
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
|
||||
"changelog": ["@changesets/changelog-github", { "repo": "mermaid-js/mermaid" }],
|
||||
"commit": false,
|
||||
"fixed": [],
|
||||
"linked": [],
|
||||
"access": "public",
|
||||
"baseBranch": "master",
|
||||
"updateInternalDependencies": "patch",
|
||||
"bumpVersionsWithWorkspaceProtocolOnly": true,
|
||||
"ignore": ["@mermaid-js/docs", "@mermaid-js/webpack-test", "@mermaid-js/mermaid-example-diagram"]
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'mermaid': patch
|
||||
---
|
||||
|
||||
fix: Handle arrows correctly when auto number is enabled
|
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'mermaid': minor
|
||||
---
|
||||
|
||||
feat: Added support for new participant types (`actor`, `boundary`, `control`, `entity`, `database`, `collections`, `queue`) in `sequenceDiagram`.
|
@@ -1,7 +0,0 @@
|
||||
---
|
||||
'mermaid': minor
|
||||
'@mermaid-js/layout-tidy-tree': minor
|
||||
'@mermaid-js/layout-elk': minor
|
||||
---
|
||||
|
||||
feat: Update mindmap rendering to support multiple layouts, improved edge intersections, and new shapes
|
@@ -1,9 +0,0 @@
|
||||
---
|
||||
'mermaid': patch
|
||||
---
|
||||
|
||||
chore: revert marked dependency from ^15.0.7 to ^16.0.0
|
||||
|
||||
- Reverted marked package version to ^16.0.0 for better compatibility
|
||||
- This is a dependency update that maintains API compatibility
|
||||
- All tests pass with the updated version
|
3
.commitlintrc.json
Normal file
3
.commitlintrc.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": ["@commitlint/config-conventional"]
|
||||
}
|
@@ -13,7 +13,6 @@ bqstring
|
||||
BQUOTE
|
||||
bramp
|
||||
BRKT
|
||||
brotli
|
||||
callbackargs
|
||||
callbackname
|
||||
classdef
|
||||
@@ -26,10 +25,8 @@ concat
|
||||
controlx
|
||||
controly
|
||||
CSSCLASS
|
||||
curv
|
||||
CYLINDEREND
|
||||
CYLINDERSTART
|
||||
DAGA
|
||||
datakey
|
||||
DEND
|
||||
descr
|
||||
@@ -47,17 +44,15 @@ edgesep
|
||||
EMPTYSTR
|
||||
enddate
|
||||
ERDIAGRAM
|
||||
eslint
|
||||
flatmap
|
||||
forwardable
|
||||
frontmatter
|
||||
funs
|
||||
gantt
|
||||
GENERICTYPE
|
||||
getBoundarys
|
||||
grammr
|
||||
graphtype
|
||||
halign
|
||||
iife
|
||||
interp
|
||||
introdcued
|
||||
INVTRAPEND
|
||||
@@ -68,7 +63,6 @@ Kaufmann
|
||||
keyify
|
||||
LABELPOS
|
||||
LABELTYPE
|
||||
layoutstop
|
||||
lcov
|
||||
LEFTOF
|
||||
Lexa
|
||||
@@ -80,22 +74,18 @@ loglevel
|
||||
LOGMSG
|
||||
lookaheads
|
||||
mdast
|
||||
metafile
|
||||
minlen
|
||||
Mstartx
|
||||
MULT
|
||||
NODIR
|
||||
NSTR
|
||||
outdir
|
||||
Qcontrolx
|
||||
QSTR
|
||||
reinit
|
||||
rels
|
||||
reqs
|
||||
rewritelinks
|
||||
rgba
|
||||
RIGHTOF
|
||||
roughjs
|
||||
sankey
|
||||
sequencenumber
|
||||
shrc
|
||||
@@ -115,17 +105,13 @@ strikethrough
|
||||
stringifying
|
||||
struct
|
||||
STYLECLASS
|
||||
STYLEDEF
|
||||
STYLEOPTS
|
||||
subcomponent
|
||||
subcomponents
|
||||
subconfig
|
||||
SUBROUTINEEND
|
||||
SUBROUTINESTART
|
||||
Subschemas
|
||||
substr
|
||||
SVGG
|
||||
SVGSVG
|
||||
TAGEND
|
||||
TAGSTART
|
||||
techn
|
||||
@@ -136,13 +122,11 @@ titlevalue
|
||||
topbar
|
||||
TRAPEND
|
||||
TRAPSTART
|
||||
treemap
|
||||
ts-nocheck
|
||||
tsdoc
|
||||
typeof
|
||||
typestr
|
||||
unshift
|
||||
urlsafe
|
||||
verifymethod
|
||||
VERIFYMTHD
|
||||
WARN_DOCSDIR_DOESNT_MATCH
|
||||
|
@@ -2,11 +2,7 @@
|
||||
Ashish Jain
|
||||
cpettitt
|
||||
Dong Cai
|
||||
fourcube
|
||||
knsv
|
||||
Knut Sveidqvist
|
||||
Nikolay Rozhkov
|
||||
Peng Xiao
|
||||
Per Brolin
|
||||
Sidharth Vinod
|
||||
subhash-halder
|
||||
Vinod Sidharth
|
||||
|
@@ -28,9 +28,6 @@ dictionaryDefinitions:
|
||||
- name: suggestions
|
||||
words:
|
||||
- none
|
||||
- disp
|
||||
- subproc
|
||||
- tria
|
||||
suggestWords:
|
||||
- seperator:separator
|
||||
- vertice:vertex
|
||||
|
@@ -20,19 +20,14 @@ dagre-d3
|
||||
Deepdwn
|
||||
Docsify
|
||||
Docsy
|
||||
Doctave
|
||||
DokuWiki
|
||||
dompurify
|
||||
elkjs
|
||||
fcose
|
||||
fontawesome
|
||||
Fonticons
|
||||
Forgejo
|
||||
Foswiki
|
||||
Gitea
|
||||
graphlib
|
||||
Grav
|
||||
icones
|
||||
iconify
|
||||
Inkdrop
|
||||
jiti
|
||||
@@ -59,17 +54,13 @@ presetAttributify
|
||||
pyplot
|
||||
redmine
|
||||
rehype
|
||||
roughjs
|
||||
rscratch
|
||||
shiki
|
||||
Slidev
|
||||
sparkline
|
||||
sphinxcontrib
|
||||
ssim
|
||||
stylis
|
||||
Swimm
|
||||
tsbuildinfo
|
||||
tseslint
|
||||
Tuleap
|
||||
Typora
|
||||
unocss
|
||||
|
@@ -1,32 +1,26 @@
|
||||
Adamiecki
|
||||
arrowend
|
||||
Bendpoints
|
||||
bmatrix
|
||||
braintree
|
||||
catmull
|
||||
compositTitleSize
|
||||
cose
|
||||
curv
|
||||
doublecircle
|
||||
elems
|
||||
gantt
|
||||
gitgraph
|
||||
gzipped
|
||||
handDrawn
|
||||
kanban
|
||||
knsv
|
||||
Knut
|
||||
marginx
|
||||
marginy
|
||||
Markdownish
|
||||
mermaidchart
|
||||
mermaidjs
|
||||
mindmap
|
||||
mindmaps
|
||||
mrtree
|
||||
multigraph
|
||||
nodesep
|
||||
NOTEGROUP
|
||||
Pinterest
|
||||
procs
|
||||
rankdir
|
||||
ranksep
|
||||
rect
|
||||
@@ -35,6 +29,7 @@ sandboxed
|
||||
siebling
|
||||
statediagram
|
||||
substate
|
||||
Sveidqvist
|
||||
unfixable
|
||||
Viewbox
|
||||
viewports
|
||||
|
@@ -1,8 +1 @@
|
||||
BRANDES
|
||||
Buzan
|
||||
circo
|
||||
handDrawn
|
||||
KOEPF
|
||||
neato
|
||||
newbranch
|
||||
validify
|
||||
|
@@ -1,107 +0,0 @@
|
||||
import { build } from 'esbuild';
|
||||
import { cp, mkdir, readFile, rename, writeFile } from 'node:fs/promises';
|
||||
import { packageOptions } from '../.build/common.js';
|
||||
import { generateLangium } from '../.build/generateLangium.js';
|
||||
import type { MermaidBuildOptions } from './util.js';
|
||||
import { defaultOptions, getBuildConfig } from './util.js';
|
||||
|
||||
const shouldVisualize = process.argv.includes('--visualize');
|
||||
|
||||
const buildPackage = async (entryName: keyof typeof packageOptions) => {
|
||||
const commonOptions: MermaidBuildOptions = {
|
||||
...defaultOptions,
|
||||
options: packageOptions[entryName],
|
||||
} as const;
|
||||
const buildConfigs: MermaidBuildOptions[] = [
|
||||
// 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 },
|
||||
// mermaid.tiny.min.js
|
||||
{
|
||||
...iifeOptions,
|
||||
minify: true,
|
||||
includeLargeFeatures: false,
|
||||
metafile: shouldVisualize,
|
||||
sourcemap: false,
|
||||
}
|
||||
);
|
||||
}
|
||||
if (entryName === 'mermaid-zenuml') {
|
||||
const iifeOptions: MermaidBuildOptions = {
|
||||
...commonOptions,
|
||||
format: 'iife',
|
||||
globalName: 'mermaid-zenuml',
|
||||
};
|
||||
buildConfigs.push(
|
||||
// mermaid-zenuml.js
|
||||
{ ...iifeOptions },
|
||||
// mermaid-zenuml.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?.outputs) {
|
||||
continue;
|
||||
}
|
||||
const fileName = Object.keys(metafile.outputs)
|
||||
.find((file) => !file.includes('chunks') && file.endsWith('js'))!
|
||||
.replace('dist/', '');
|
||||
// Upload metafile into https://esbuild.github.io/analyze/
|
||||
await writeFile(`stats/${fileName}.meta.json`, JSON.stringify(metafile));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handler = (e) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
};
|
||||
|
||||
const buildTinyMermaid = async () => {
|
||||
await mkdir('./packages/tiny/dist', { recursive: true });
|
||||
await rename(
|
||||
'./packages/mermaid/dist/mermaid.tiny.min.js',
|
||||
'./packages/tiny/dist/mermaid.tiny.js'
|
||||
);
|
||||
// Copy version from mermaid's package.json to tiny's package.json
|
||||
const mermaidPkg = JSON.parse(await readFile('./packages/mermaid/package.json', 'utf8'));
|
||||
const tinyPkg = JSON.parse(await readFile('./packages/tiny/package.json', 'utf8'));
|
||||
tinyPkg.version = mermaidPkg.version;
|
||||
|
||||
await writeFile('./packages/tiny/package.json', JSON.stringify(tinyPkg, null, 2) + '\n');
|
||||
await cp('./packages/mermaid/CHANGELOG.md', './packages/tiny/CHANGELOG.md');
|
||||
};
|
||||
|
||||
const main = async () => {
|
||||
await generateLangium();
|
||||
await mkdir('stats', { recursive: true });
|
||||
const packageNames = Object.keys(packageOptions) as (keyof typeof packageOptions)[];
|
||||
// it should build `parser` before `mermaid` because it's a dependency
|
||||
for (const pkg of packageNames) {
|
||||
await buildPackage(pkg).catch(handler);
|
||||
}
|
||||
await buildTinyMermaid();
|
||||
};
|
||||
|
||||
void main();
|
@@ -1,15 +0,0 @@
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import { transformJison } from '../.build/jisonTransformer.js';
|
||||
import type { 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,122 +0,0 @@
|
||||
/* eslint-disable no-console */
|
||||
import chokidar from 'chokidar';
|
||||
import cors from 'cors';
|
||||
import { context } from 'esbuild';
|
||||
import type { Request, Response } from 'express';
|
||||
import express from 'express';
|
||||
import { packageOptions } from '../.build/common.js';
|
||||
import { generateLangium } from '../.build/generateLangium.js';
|
||||
import { defaultOptions, getBuildConfig } from './util.js';
|
||||
|
||||
const configs = Object.values(packageOptions).map(({ packageName }) =>
|
||||
getBuildConfig({
|
||||
...defaultOptions,
|
||||
minify: false,
|
||||
core: false,
|
||||
options: packageOptions[packageName],
|
||||
})
|
||||
);
|
||||
const mermaidIIFEConfig = getBuildConfig({
|
||||
...defaultOptions,
|
||||
minify: false,
|
||||
core: false,
|
||||
options: packageOptions.mermaid,
|
||||
format: 'iife',
|
||||
});
|
||||
configs.push(mermaidIIFEConfig);
|
||||
|
||||
const contexts = await Promise.all(
|
||||
configs.map(async (config) => ({ config, context: await context(config) }))
|
||||
);
|
||||
|
||||
let rebuildCounter = 1;
|
||||
const rebuildAll = async () => {
|
||||
const buildNumber = rebuildCounter++;
|
||||
const timeLabel = `Rebuild ${buildNumber} Time (total)`;
|
||||
console.time(timeLabel);
|
||||
await Promise.all(
|
||||
contexts.map(async ({ config, context }) => {
|
||||
const buildVariant = `Rebuild ${buildNumber} Time (${Object.keys(config.entryPoints!)[0]} ${config.format})`;
|
||||
console.time(buildVariant);
|
||||
await context.rebuild();
|
||||
console.timeEnd(buildVariant);
|
||||
})
|
||||
).catch((e) => console.error(e));
|
||||
console.timeEnd(timeLabel);
|
||||
};
|
||||
|
||||
let clients: { id: number; response: Response }[] = [];
|
||||
function eventsHandler(request: Request, response: Response) {
|
||||
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);
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
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/],
|
||||
})
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
.on('all', async (event, path) => {
|
||||
// Ignore other events.
|
||||
if (!['add', 'change'].includes(event)) {
|
||||
return;
|
||||
}
|
||||
console.log(`${path} changed. Rebuilding...`);
|
||||
if (path.endsWith('.langium')) {
|
||||
await generateLangium();
|
||||
}
|
||||
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`);
|
||||
});
|
||||
}
|
||||
|
||||
void createServer();
|
119
.esbuild/util.ts
119
.esbuild/util.ts
@@ -1,119 +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 type { PackageOptions } from '../.build/common.js';
|
||||
import { jisonPlugin } from './jisonPlugin.js';
|
||||
|
||||
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
||||
|
||||
export interface MermaidBuildOptions extends BuildOptions {
|
||||
minify: boolean;
|
||||
core: boolean;
|
||||
metafile: boolean;
|
||||
format: 'esm' | 'iife';
|
||||
options: PackageOptions;
|
||||
includeLargeFeatures: boolean;
|
||||
}
|
||||
|
||||
export const defaultOptions: Omit<MermaidBuildOptions, 'entryName' | 'options'> = {
|
||||
minify: false,
|
||||
metafile: false,
|
||||
core: false,
|
||||
format: 'esm',
|
||||
includeLargeFeatures: true,
|
||||
} 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, includeLargeFeatures }: MermaidBuildOptions
|
||||
) => {
|
||||
if (core) {
|
||||
fileName += '.core';
|
||||
} else if (format === 'esm') {
|
||||
fileName += '.esm';
|
||||
}
|
||||
if (!includeLargeFeatures) {
|
||||
fileName += '.tiny';
|
||||
}
|
||||
if (minify) {
|
||||
fileName += '.min';
|
||||
}
|
||||
return fileName;
|
||||
};
|
||||
|
||||
export const getBuildConfig = (options: MermaidBuildOptions): BuildOptions => {
|
||||
const {
|
||||
core,
|
||||
format,
|
||||
options: { name, file, packageName },
|
||||
globalName = 'mermaid',
|
||||
includeLargeFeatures,
|
||||
...rest
|
||||
} = options;
|
||||
|
||||
const external: string[] = ['require', 'fs', 'path'];
|
||||
const outFileName = getFileName(name, options);
|
||||
const output: BuildOptions = buildOptions({
|
||||
...rest,
|
||||
absWorkingDir: resolve(__dirname, `../packages/${packageName}`),
|
||||
entryPoints: {
|
||||
[outFileName]: `src/${file}`,
|
||||
},
|
||||
globalName,
|
||||
logLevel: 'info',
|
||||
chunkNames: `chunks/${outFileName}/[name]-[hash]`,
|
||||
define: {
|
||||
// This needs to be stringified for esbuild
|
||||
includeLargeFeatures: `${includeLargeFeatures}`,
|
||||
'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;
|
||||
const originalGlobalName = output.globalName ?? 'mermaid';
|
||||
output.globalName = `__esbuild_esm_mermaid_nm[${JSON.stringify(originalGlobalName)}]`;
|
||||
// Workaround for removing the .default access in esbuild IIFE.
|
||||
// https://github.com/mermaid-js/mermaid/pull/4109#discussion_r1292317396
|
||||
output.footer = {
|
||||
js: `globalThis[${JSON.stringify(originalGlobalName)}] = globalThis.${output.globalName}.default;`,
|
||||
};
|
||||
output.outExtension = { '.js': '.js' };
|
||||
} else {
|
||||
output.format = 'esm';
|
||||
output.splitting = true;
|
||||
output.outExtension = { '.js': '.mjs' };
|
||||
}
|
||||
|
||||
return output;
|
||||
};
|
8
.eslintignore
Normal file
8
.eslintignore
Normal file
@@ -0,0 +1,8 @@
|
||||
dist/**
|
||||
.github/**
|
||||
docs/Setup.md
|
||||
cypress.config.js
|
||||
cypress/plugins/index.js
|
||||
coverage
|
||||
*.json
|
||||
node_modules
|
189
.eslintrc.cjs
Normal file
189
.eslintrc.cjs
Normal file
@@ -0,0 +1,189 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
es6: true,
|
||||
'jest/globals': true,
|
||||
node: true,
|
||||
},
|
||||
root: true,
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
ecmaFeatures: {
|
||||
experimentalObjectRestSpread: true,
|
||||
jsx: true,
|
||||
},
|
||||
tsconfigRootDir: __dirname,
|
||||
sourceType: 'module',
|
||||
ecmaVersion: 2020,
|
||||
allowAutomaticSingleRunInference: true,
|
||||
project: ['./tsconfig.eslint.json', './packages/*/tsconfig.json'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
},
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:json/recommended',
|
||||
'plugin:markdown/recommended',
|
||||
'plugin:@cspell/recommended',
|
||||
'prettier',
|
||||
],
|
||||
plugins: [
|
||||
'@typescript-eslint',
|
||||
'no-only-tests',
|
||||
'html',
|
||||
'jest',
|
||||
'jsdoc',
|
||||
'json',
|
||||
'@cspell',
|
||||
'lodash',
|
||||
'unicorn',
|
||||
],
|
||||
ignorePatterns: [
|
||||
// this file is automatically generated by `pnpm run --filter mermaid types:build-config`
|
||||
'packages/mermaid/src/config.type.ts',
|
||||
],
|
||||
rules: {
|
||||
curly: 'error',
|
||||
'no-console': 'error',
|
||||
'no-prototype-builtins': 'off',
|
||||
'no-unused-vars': 'off',
|
||||
'cypress/no-async-tests': 'off',
|
||||
'@typescript-eslint/consistent-type-imports': 'error',
|
||||
'@typescript-eslint/no-explicit-any': 'warn',
|
||||
'@typescript-eslint/no-floating-promises': 'error',
|
||||
'@typescript-eslint/no-misused-promises': 'error',
|
||||
'@typescript-eslint/no-unused-vars': 'warn',
|
||||
'@typescript-eslint/ban-ts-comment': [
|
||||
'error',
|
||||
{
|
||||
'ts-expect-error': 'allow-with-description',
|
||||
'ts-ignore': 'allow-with-description',
|
||||
'ts-nocheck': 'allow-with-description',
|
||||
'ts-check': 'allow-with-description',
|
||||
minimumDescriptionLength: 10,
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/naming-convention': [
|
||||
'error',
|
||||
{
|
||||
selector: 'typeLike',
|
||||
format: ['PascalCase'],
|
||||
custom: {
|
||||
regex: '^I[A-Z]',
|
||||
match: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
'json/*': ['error', 'allowComments'],
|
||||
'@cspell/spellchecker': [
|
||||
'error',
|
||||
{
|
||||
checkIdentifiers: true,
|
||||
checkStrings: true,
|
||||
checkStringTemplates: true,
|
||||
},
|
||||
],
|
||||
'no-empty': [
|
||||
'error',
|
||||
{
|
||||
allowEmptyCatch: true,
|
||||
},
|
||||
],
|
||||
'no-only-tests/no-only-tests': 'error',
|
||||
'lodash/import-scope': ['error', 'method'],
|
||||
'unicorn/better-regex': 'error',
|
||||
'unicorn/no-abusive-eslint-disable': 'error',
|
||||
'unicorn/no-array-push-push': 'error',
|
||||
'unicorn/no-for-loop': 'error',
|
||||
'unicorn/no-instanceof-array': 'error',
|
||||
'unicorn/no-typeof-undefined': 'error',
|
||||
'unicorn/no-unnecessary-await': 'error',
|
||||
'unicorn/no-unsafe-regex': 'warn',
|
||||
'unicorn/no-useless-promise-resolve-reject': 'error',
|
||||
'unicorn/prefer-array-find': 'error',
|
||||
'unicorn/prefer-array-flat-map': 'error',
|
||||
'unicorn/prefer-array-index-of': 'error',
|
||||
'unicorn/prefer-array-some': 'error',
|
||||
'unicorn/prefer-default-parameters': 'error',
|
||||
'unicorn/prefer-includes': 'error',
|
||||
'unicorn/prefer-negative-index': 'error',
|
||||
'unicorn/prefer-object-from-entries': 'error',
|
||||
'unicorn/prefer-string-starts-ends-with': 'error',
|
||||
'unicorn/prefer-string-trim-start-end': 'error',
|
||||
'unicorn/string-content': 'error',
|
||||
'unicorn/prefer-spread': 'error',
|
||||
'unicorn/no-lonely-if': 'error',
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ['cypress/**', 'demos/**'],
|
||||
rules: {
|
||||
'no-console': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['*.{js,jsx,mjs,cjs}'],
|
||||
extends: ['plugin:jsdoc/recommended'],
|
||||
rules: {
|
||||
'jsdoc/check-indentation': 'off',
|
||||
'jsdoc/check-alignment': 'off',
|
||||
'jsdoc/check-line-alignment': 'off',
|
||||
'jsdoc/multiline-blocks': 'off',
|
||||
'jsdoc/newline-after-description': 'off',
|
||||
'jsdoc/tag-lines': 'off',
|
||||
'jsdoc/require-param-description': 'off',
|
||||
'jsdoc/require-param-type': 'off',
|
||||
'jsdoc/require-returns': 'off',
|
||||
'jsdoc/require-returns-description': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['*.{ts,tsx}'],
|
||||
plugins: ['tsdoc'],
|
||||
rules: {
|
||||
'no-restricted-syntax': [
|
||||
'error',
|
||||
{
|
||||
selector: 'TSEnumDeclaration',
|
||||
message:
|
||||
'Prefer using TypeScript union types over TypeScript enum, since TypeScript enums have a bunch of issues, see https://dev.to/dvddpl/whats-the-problem-with-typescript-enums-2okj',
|
||||
},
|
||||
],
|
||||
'tsdoc/syntax': 'error',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['*.spec.{ts,js}', 'cypress/**', 'demos/**', '**/docs/**'],
|
||||
rules: {
|
||||
'jsdoc/require-jsdoc': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['*.spec.{ts,js}', 'tests/**', 'cypress/**/*.js'],
|
||||
rules: {
|
||||
'@cspell/spellchecker': [
|
||||
'error',
|
||||
{
|
||||
checkIdentifiers: false,
|
||||
checkStrings: false,
|
||||
checkStringTemplates: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['*.html', '*.md', '**/*.md/*'],
|
||||
rules: {
|
||||
'no-var': 'error',
|
||||
'no-undef': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
'@typescript-eslint/no-floating-promises': 'off',
|
||||
'@typescript-eslint/no-misused-promises': 'off',
|
||||
},
|
||||
parserOptions: {
|
||||
project: null,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
2
.github/ISSUE_TEMPLATE/config.yml
vendored
2
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -4,7 +4,7 @@ contact_links:
|
||||
url: https://github.com/mermaid-js/mermaid/discussions
|
||||
about: Ask the Community questions or share your own graphs in our discussions.
|
||||
- name: Discord
|
||||
url: https://discord.gg/sKeNQX4Wtj
|
||||
url: https://discord.gg/AgrbSrBer3
|
||||
about: Join our Community on Discord for Help and a casual chat.
|
||||
- name: Documentation
|
||||
url: https://mermaid.js.org
|
||||
|
2
.github/ISSUE_TEMPLATE/theme_proposal.yml
vendored
2
.github/ISSUE_TEMPLATE/theme_proposal.yml
vendored
@@ -29,7 +29,7 @@ body:
|
||||
label: Colors
|
||||
description: |-
|
||||
A detailed list of the different colour values to use.
|
||||
See the [list of currently used variable names](https://mermaid-js.github.io/mermaid/#/theming?id=theme-variables-reference-table)
|
||||
A list of currently used variable names can be found [here](https://mermaid-js.github.io/mermaid/#/theming?id=theme-variables-reference-table)
|
||||
placeholder: |-
|
||||
- background: #f4f4f4
|
||||
- primaryColor: #fff4dd
|
||||
|
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
|
||||
|
21
.github/lychee.toml
vendored
21
.github/lychee.toml
vendored
@@ -41,26 +41,7 @@ exclude = [
|
||||
"https://bundlephobia.com",
|
||||
|
||||
# Chrome webstore migration issue. Temporary
|
||||
"https://chromewebstore.google.com",
|
||||
|
||||
# Drupal 403
|
||||
"https://(www.)?drupal.org",
|
||||
|
||||
# Phbpp 403
|
||||
"https://(www.)?phpbb.com",
|
||||
|
||||
# Swimm returns 404, even though the link is valid
|
||||
"https://docs.swimm.io",
|
||||
|
||||
# Certificate Error
|
||||
"https://noteshub.app",
|
||||
|
||||
# Timeout
|
||||
"https://huehive.co",
|
||||
"https://foswiki.org",
|
||||
"https://www.gnu.org",
|
||||
"https://redmine.org",
|
||||
"https://mermaid-preview.com"
|
||||
"https://chromewebstore.google.com"
|
||||
]
|
||||
|
||||
# Exclude all private IPs from checking.
|
||||
|
2
.github/pull_request_template.md
vendored
2
.github/pull_request_template.md
vendored
@@ -15,4 +15,4 @@ Make sure you
|
||||
- [ ] :book: have read the [contribution guidelines](https://mermaid.js.org/community/contributing.html)
|
||||
- [ ] :computer: have added necessary unit/e2e tests.
|
||||
- [ ] :notebook: have added documentation. Make sure [`MERMAID_RELEASE_VERSION`](https://mermaid.js.org/community/contributing.html#update-documentation) is used for all new features.
|
||||
- [ ] :butterfly: If your PR makes a change that should be noted in one or more packages' changelogs, generate a changeset by running `pnpm changeset` and following the prompts. Changesets that add features should be `minor` and those that fix bugs should be `patch`. Please prefix changeset messages with `feat:`, `fix:`, or `chore:`.
|
||||
- [ ] :bookmark: targeted `develop` branch
|
||||
|
36
.github/release-drafter.yml
vendored
Normal file
36
.github/release-drafter.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
name-template: '$NEXT_PATCH_VERSION'
|
||||
tag-template: '$NEXT_PATCH_VERSION'
|
||||
categories:
|
||||
- title: '🚨 **Breaking Changes**'
|
||||
labels:
|
||||
- 'Breaking Change'
|
||||
- title: '🚀 Features'
|
||||
labels:
|
||||
- 'Type: Enhancement'
|
||||
- 'feature' # deprecated, new PRs shouldn't have this
|
||||
- title: '🐛 Bug Fixes'
|
||||
labels:
|
||||
- 'Type: Bug / Error'
|
||||
- 'fix' # deprecated, new PRs shouldn't have this
|
||||
- title: '🧰 Maintenance'
|
||||
labels:
|
||||
- 'Type: Other'
|
||||
- 'chore' # deprecated, new PRs shouldn't have this
|
||||
- title: '⚡️ Performance'
|
||||
labels:
|
||||
- 'Type: Performance'
|
||||
- title: '📚 Documentation'
|
||||
labels:
|
||||
- 'Area: Documentation'
|
||||
change-template: '- $TITLE (#$NUMBER) @$AUTHOR'
|
||||
sort-by: title
|
||||
sort-direction: ascending
|
||||
exclude-labels:
|
||||
- 'Skip changelog'
|
||||
no-changes-template: 'This release contains minor changes and bugfixes.'
|
||||
template: |
|
||||
# Release Notes
|
||||
|
||||
$CHANGES
|
||||
|
||||
🎉 **Thanks to all contributors helping with this release!** 🎉
|
2
.github/stale.yml
vendored
2
.github/stale.yml
vendored
@@ -15,5 +15,5 @@ markComment: >
|
||||
If you are still interested in this issue and it is still relevant you can comment to revive it.
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: >
|
||||
This issue has been automatically closed due to a lack of activity.
|
||||
This issue has been been automatically closed due to a lack of activity.
|
||||
This is done to maintain a clean list of issues that the community is interested in developing.
|
||||
|
45
.github/workflows/autofix.yml
vendored
45
.github/workflows/autofix.yml
vendored
@@ -1,45 +0,0 @@
|
||||
name: autofix.ci # needed to securely identify the workflow
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches-ignore:
|
||||
- 'renovate/**'
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
jobs:
|
||||
autofix:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||
# uses version from "packageManager" field in package.json
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||
with:
|
||||
cache: pnpm
|
||||
node-version-file: '.node-version'
|
||||
|
||||
- name: Install Packages
|
||||
run: |
|
||||
pnpm install --frozen-lockfile
|
||||
env:
|
||||
CYPRESS_CACHE_FOLDER: .cache/Cypress
|
||||
|
||||
- name: Fix Linting
|
||||
shell: bash
|
||||
run: pnpm -w run lint:fix
|
||||
|
||||
- name: Sync `./src/config.type.ts` with `./src/schemas/config.schema.yaml`
|
||||
shell: bash
|
||||
run: pnpm run --filter mermaid types:build-config
|
||||
|
||||
- name: Build Docs
|
||||
working-directory: ./packages/mermaid
|
||||
run: pnpm run docs:build
|
||||
|
||||
- uses: autofix-ci/action@635ffb0c9798bd160680f18fd73371e355b85f27 # main
|
8
.github/workflows/build-docs.yml
vendored
8
.github/workflows/build-docs.yml
vendored
@@ -8,8 +8,6 @@ on:
|
||||
pull_request:
|
||||
merge_group:
|
||||
|
||||
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
@@ -18,12 +16,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||
- uses: pnpm/action-setup@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
cache: pnpm
|
||||
node-version-file: '.node-version'
|
||||
|
49
.github/workflows/build.yml
vendored
Normal file
49
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
name: Build
|
||||
|
||||
on:
|
||||
push: {}
|
||||
merge_group:
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
- ready_for_review
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build-mermaid:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
# uses version from "packageManager" field in package.json
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
cache: pnpm
|
||||
node-version-file: '.node-version'
|
||||
|
||||
- name: Install Packages
|
||||
run: |
|
||||
pnpm install --frozen-lockfile
|
||||
env:
|
||||
CYPRESS_CACHE_FOLDER: .cache/Cypress
|
||||
|
||||
- name: Run Build
|
||||
run: pnpm run build
|
||||
|
||||
- name: Upload Mermaid Build as Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: mermaid-build
|
||||
path: packages/mermaid/dist
|
||||
|
||||
- name: Upload Mermaid Mindmap Build as Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: mermaid-mindmap-build
|
||||
path: packages/mermaid-mindmap/dist
|
2
.github/workflows/check-readme-in-sync.yml
vendored
2
.github/workflows/check-readme-in-sync.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Check for difference in README.md and docs/README.md
|
||||
run: |
|
||||
|
26
.github/workflows/checks.yml
vendored
Normal file
26
.github/workflows/checks.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
on:
|
||||
push:
|
||||
merge_group:
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
- ready_for_review
|
||||
|
||||
name: Static analysis on Test files
|
||||
|
||||
jobs:
|
||||
check-tests:
|
||||
runs-on: ubuntu-latest
|
||||
name: check tests
|
||||
if: github.repository_owner == 'mermaid-js'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: testomatio/check-tests@stable
|
||||
with:
|
||||
framework: cypress
|
||||
tests: './cypress/e2e/**/**.spec.js'
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
has-tests-label: true
|
11
.github/workflows/codeql.yml
vendored
11
.github/workflows/codeql.yml
vendored
@@ -11,9 +11,6 @@ on:
|
||||
- synchronize
|
||||
- ready_for_review
|
||||
|
||||
permissions: # added using https://github.com/step-security/secure-repo
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
@@ -32,11 +29,11 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
config-file: ./.github/codeql/codeql-config.yml
|
||||
languages: ${{ matrix.language }}
|
||||
@@ -48,7 +45,7 @@ jobs:
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
@@ -62,4 +59,4 @@ jobs:
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10
|
||||
uses: github/codeql-action/analyze@v2
|
||||
|
4
.github/workflows/dependency-review.yml
vendored
4
.github/workflows/dependency-review.yml
vendored
@@ -15,6 +15,6 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 'Checkout Repository'
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@v4
|
||||
- name: 'Dependency Review'
|
||||
uses: actions/dependency-review-action@3b139cfc5fae8b618d3eae3675e383bb1769c019 # v4.5.0
|
||||
uses: actions/dependency-review-action@v3
|
||||
|
17
.github/workflows/e2e-applitools.yml
vendored
17
.github/workflows/e2e-applitools.yml
vendored
@@ -11,8 +11,6 @@ on:
|
||||
default: master
|
||||
description: 'Parent branch to use for PRs'
|
||||
|
||||
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
@@ -23,37 +21,38 @@ env:
|
||||
jobs:
|
||||
e2e-applitools:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: cypress/browsers:node-20.11.0-chrome-121.0.6167.85-1-ff-120.0-edge-121.0.2277.83-1
|
||||
options: --user 1001
|
||||
steps:
|
||||
- if: ${{ ! env.USE_APPLI }}
|
||||
name: Warn if not using Applitools
|
||||
run: |
|
||||
echo "::error,title=Not using Applitools::APPLITOOLS_API_KEY is empty, disabling Applitools for this run."
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||
- uses: pnpm/action-setup@v4
|
||||
# uses version from "packageManager" field in package.json
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.node-version'
|
||||
|
||||
- if: ${{ env.USE_APPLI }}
|
||||
name: Notify applitools of new batch
|
||||
# Copied from docs https://applitools.com/docs/topics/integrations/github-integration-ci-setup.html
|
||||
run: curl -L -d '' -X POST "$APPLITOOLS_SERVER_URL/api/externals/github/push?apiKey=$APPLITOOLS_API_KEY&CommitSha=$GITHUB_SHA&BranchName=${APPLITOOLS_BRANCH}$&ParentBranchName=$APPLITOOLS_PARENT_BRANCH"
|
||||
env:
|
||||
# e.g. mermaid-js/mermaid/my-branch
|
||||
APPLITOOLS_BRANCH: ${{ github.repository }}/${{ github.ref_name }}
|
||||
APPLITOOLS_PARENT_BRANCH: ${{ github.event.inputs.parent_branch }}
|
||||
APPLITOOLS_API_KEY: ${{ secrets.APPLITOOLS_API_KEY }}
|
||||
APPLITOOLS_SERVER_URL: 'https://eyesapi.applitools.com'
|
||||
uses: wei/curl@012398a392d02480afa2720780031f8621d5f94c
|
||||
with:
|
||||
args: -X POST "$APPLITOOLS_SERVER_URL/api/externals/github/push?apiKey=$APPLITOOLS_API_KEY&CommitSha=$GITHUB_SHA&BranchName=${APPLITOOLS_BRANCH}$&ParentBranchName=$APPLITOOLS_PARENT_BRANCH"
|
||||
|
||||
- name: Cypress run
|
||||
uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
|
||||
uses: cypress-io/github-action@v4
|
||||
id: cypress
|
||||
with:
|
||||
start: pnpm run dev
|
||||
|
70
.github/workflows/e2e-timings.yml
vendored
70
.github/workflows/e2e-timings.yml
vendored
@@ -1,70 +0,0 @@
|
||||
name: E2E - Generate Timings
|
||||
|
||||
on:
|
||||
# run this workflow every night at 3am
|
||||
schedule:
|
||||
- cron: '28 3 * * *'
|
||||
# or when the user triggers it from GitHub Actions page
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
timings:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: cypress/browsers:node-20.11.0-chrome-121.0.6167.85-1-ff-120.0-edge-121.0.2277.83-1
|
||||
options: --user 1001
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||
with:
|
||||
node-version-file: '.node-version'
|
||||
- name: Install dependencies
|
||||
uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
|
||||
with:
|
||||
runTests: false
|
||||
|
||||
- name: Cypress run
|
||||
uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
|
||||
id: cypress
|
||||
with:
|
||||
install: false
|
||||
start: pnpm run dev:coverage
|
||||
wait-on: 'http://localhost:9000'
|
||||
browser: chrome
|
||||
publish-summary: false
|
||||
env:
|
||||
VITEST_COVERAGE: true
|
||||
CYPRESS_COMMIT: ${{ github.sha }}
|
||||
SPLIT: 1
|
||||
SPLIT_INDEX: 0
|
||||
SPLIT_FILE: 'cypress/timings.json'
|
||||
|
||||
- name: Compare timings
|
||||
id: compare
|
||||
run: |
|
||||
OUTPUT=$(pnpm tsx scripts/compare-timings.ts)
|
||||
echo "$OUTPUT" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
echo "output<<EOF" >> $GITHUB_OUTPUT
|
||||
echo "$OUTPUT" >> $GITHUB_OUTPUT
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Commit and create pull request
|
||||
uses: peter-evans/create-pull-request@18e469570b1cf0dfc11d60ec121099f8ff3e617a
|
||||
with:
|
||||
add-paths: |
|
||||
cypress/timings.json
|
||||
commit-message: 'chore: update E2E timings'
|
||||
branch: update-timings
|
||||
title: Update E2E Timings
|
||||
body: ${{ steps.compare.outputs.output }}
|
||||
delete-branch: true
|
||||
sign-commits: true
|
157
.github/workflows/e2e.yml
vendored
157
.github/workflows/e2e.yml
vendored
@@ -1,35 +1,25 @@
|
||||
# We use github cache to save snapshots between runs.
|
||||
# For PRs and MergeQueues, the target commit is used, and for push events, github.event.previous is used.
|
||||
# If a snapshot for a given Hash is not found, we checkout that commit, run the tests and cache the snapshots.
|
||||
# These are then downloaded before running the E2E, providing the reference snapshots.
|
||||
# If there are any errors, the diff image is uploaded to artifacts, and the user is notified.
|
||||
|
||||
name: E2E
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- develop
|
||||
- master
|
||||
- release/**
|
||||
branches-ignore:
|
||||
- 'gh-readonly-queue/**'
|
||||
pull_request:
|
||||
merge_group:
|
||||
|
||||
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
# For PRs and MergeQueues, the target commit is used, and for push events to non-develop branches, github.event.previous is used if available. Otherwise, 'develop' is used.
|
||||
targetHash: >-
|
||||
${{
|
||||
github.event.pull_request.base.sha ||
|
||||
github.event.merge_group.base_sha ||
|
||||
(
|
||||
(
|
||||
(github.event_name == 'push' && github.ref == 'refs/heads/develop') ||
|
||||
github.event.before == '0000000000000000000000000000000000000000'
|
||||
) && 'develop'
|
||||
) ||
|
||||
github.event.before
|
||||
}}
|
||||
RUN_VISUAL_TEST: >-
|
||||
${{ github.repository == 'mermaid-js/mermaid' && (github.event_name != 'pull_request' || !startsWith(github.head_ref, 'renovate/')) }}
|
||||
# For PRs and MergeQueues, the target commit is used, and for push events, github.event.previous is used.
|
||||
targetHash: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha || (github.event.before == '0000000000000000000000000000000000000000' && 'develop' || github.event.before) }}
|
||||
|
||||
jobs:
|
||||
cache:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -37,39 +27,35 @@ jobs:
|
||||
image: cypress/browsers:node-20.11.0-chrome-121.0.6167.85-1-ff-120.0-edge-121.0.2277.83-1
|
||||
options: --user 1001
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.node-version'
|
||||
- name: Cache snapshots
|
||||
id: cache-snapshot
|
||||
uses: actions/cache@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
save-always: true
|
||||
path: ./cypress/snapshots
|
||||
key: ${{ runner.os }}-snapshots-${{ env.targetHash }}
|
||||
|
||||
# If a snapshot for a given Hash is not found, we checkout that commit, run the tests and cache the snapshots.
|
||||
- name: Switch to base branch
|
||||
if: ${{ steps.cache-snapshot.outputs.cache-hit != 'true' }}
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ env.targetHash }}
|
||||
|
||||
- name: Install dependencies
|
||||
- name: Cypress run
|
||||
uses: cypress-io/github-action@v4
|
||||
id: cypress-snapshot-gen
|
||||
if: ${{ steps.cache-snapshot.outputs.cache-hit != 'true' }}
|
||||
uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
|
||||
with:
|
||||
# just perform install
|
||||
runTests: false
|
||||
|
||||
- name: Calculate bundle size
|
||||
if: ${{ steps.cache-snapshot.outputs.cache-hit != 'true'}}
|
||||
run: |
|
||||
pnpm run build:viz
|
||||
mkdir -p cypress/snapshots/stats/base
|
||||
mv stats cypress/snapshots/stats/base
|
||||
start: pnpm run dev
|
||||
wait-on: 'http://localhost:9000'
|
||||
browser: chrome
|
||||
|
||||
e2e:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -80,66 +66,49 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
containers: [1, 2, 3, 4, 5]
|
||||
containers: [1, 2, 3, 4]
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||
- uses: pnpm/action-setup@v4
|
||||
# uses version from "packageManager" field in package.json
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.node-version'
|
||||
|
||||
# These cached snapshots are downloaded, providing the reference snapshots.
|
||||
- name: Cache snapshots
|
||||
id: cache-snapshot
|
||||
uses: actions/cache/restore@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1
|
||||
uses: actions/cache/restore@v3
|
||||
with:
|
||||
path: ./cypress/snapshots
|
||||
key: ${{ runner.os }}-snapshots-${{ env.targetHash }}
|
||||
|
||||
- name: Install dependencies
|
||||
uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
|
||||
with:
|
||||
runTests: false
|
||||
|
||||
- name: Output size diff
|
||||
if: ${{ matrix.containers == 1 }}
|
||||
run: |
|
||||
pnpm run build:viz
|
||||
mv stats cypress/snapshots/stats/head
|
||||
echo '## Bundle size difference' >> "$GITHUB_STEP_SUMMARY"
|
||||
echo '' >> "$GITHUB_STEP_SUMMARY"
|
||||
npx tsx scripts/size.ts >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
# Install NPM dependencies, cache them correctly
|
||||
# and run all Cypress tests
|
||||
- name: Cypress run
|
||||
uses: cypress-io/github-action@18a6541367f4580a515371905f499a27a44e8dbe # v6.7.12
|
||||
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
|
||||
# Disable recording if we don't have an API key
|
||||
# e.g. if this action was run from a fork
|
||||
record: ${{ env.RUN_VISUAL_TEST == 'true' && secrets.CYPRESS_RECORD_KEY != '' }}
|
||||
record: ${{ secrets.CYPRESS_RECORD_KEY != '' }}
|
||||
parallel: ${{ secrets.CYPRESS_RECORD_KEY != '' }}
|
||||
env:
|
||||
ARGOS_PARALLEL: ${{ env.RUN_VISUAL_TEST == 'true' }}
|
||||
ARGOS_PARALLEL_TOTAL: ${{ env.RUN_VISUAL_TEST == 'true' && strategy.job-total || 1 }}
|
||||
ARGOS_PARALLEL_INDEX: ${{ env.RUN_VISUAL_TEST == 'true' && matrix.containers || 1 }}
|
||||
CYPRESS_COMMIT: ${{ github.sha }}
|
||||
CYPRESS_RECORD_KEY: ${{ env.RUN_VISUAL_TEST == 'true' && secrets.CYPRESS_RECORD_KEY || ''}}
|
||||
SPLIT: ${{ strategy.job-total }}
|
||||
SPLIT_INDEX: ${{ strategy.job-index }}
|
||||
SPLIT_FILE: 'cypress/timings.json'
|
||||
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
|
||||
VITEST_COVERAGE: true
|
||||
CYPRESS_COMMIT: ${{ github.sha }}
|
||||
|
||||
- name: Upload Coverage to Codecov
|
||||
uses: codecov/codecov-action@13ce06bfc6bbe3ecf90edbbf1bc32fe5978ca1d3 # v5.3.1
|
||||
uses: codecov/codecov-action@v3
|
||||
# Run step only pushes to develop and pull_requests
|
||||
if: ${{ steps.cypress.conclusion == 'success' && (github.event_name == 'pull_request' || github.ref == 'refs/heads/develop')}}
|
||||
with:
|
||||
@@ -149,3 +118,55 @@ jobs:
|
||||
fail_ci_if_error: false
|
||||
verbose: true
|
||||
token: 6845cc80-77ee-4e17-85a1-026cd95e0766
|
||||
|
||||
# We upload the artifacts into numbered archives to prevent overwriting
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
if: ${{ always() }}
|
||||
with:
|
||||
name: snapshots-${{ matrix.containers }}
|
||||
retention-days: 1
|
||||
path: ./cypress/snapshots
|
||||
|
||||
combineArtifacts:
|
||||
needs: e2e
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ always() }}
|
||||
steps:
|
||||
# Download all snapshot artifacts and merge them into a single folder
|
||||
- name: Download All Artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: snapshots
|
||||
pattern: snapshots-*
|
||||
merge-multiple: true
|
||||
|
||||
# For successful push events, we save the snapshots cache
|
||||
- name: Save snapshots cache
|
||||
id: cache-upload
|
||||
if: ${{ github.event_name == 'push' && needs.e2e.result != 'failure' }}
|
||||
uses: actions/cache/save@v3
|
||||
with:
|
||||
path: ./snapshots
|
||||
key: ${{ runner.os }}-snapshots-${{ github.event.after }}
|
||||
|
||||
- name: Flatten images to a folder
|
||||
if: ${{ needs.e2e.result == 'failure' }}
|
||||
run: |
|
||||
mkdir errors
|
||||
cd snapshots
|
||||
find . -mindepth 2 -type d -name "*__diff_output__*" -exec sh -c 'mv "$0"/*.png ../errors/' {} \;
|
||||
|
||||
- name: Upload Error snapshots
|
||||
if: ${{ needs.e2e.result == 'failure' }}
|
||||
uses: actions/upload-artifact@v4
|
||||
id: upload-artifacts
|
||||
with:
|
||||
name: error-snapshots
|
||||
retention-days: 10
|
||||
path: errors/
|
||||
|
||||
- name: Notify Users
|
||||
if: ${{ needs.e2e.result == 'failure' }}
|
||||
run: |
|
||||
echo "::error title=Visual tests failed::You can view images that failed by downloading the error-snapshots artifact: ${{ steps.upload-artifacts.outputs.artifact-url }}"
|
||||
|
8
.github/workflows/issue-triage.yml
vendored
8
.github/workflows/issue-triage.yml
vendored
@@ -4,17 +4,11 @@ on:
|
||||
issues:
|
||||
types: [opened]
|
||||
|
||||
permissions: # added using https://github.com/step-security/secure-repo
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
triage:
|
||||
permissions:
|
||||
issues: write # for andymckay/labeler to label issues
|
||||
pull-requests: write # for andymckay/labeler to label PRs
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: andymckay/labeler@e6c4322d0397f3240f0e7e30a33b5c5df2d39e90 # 1.0.4
|
||||
- uses: andymckay/labeler@1.0.4
|
||||
with:
|
||||
repo-token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
add-labels: 'Status: Triage'
|
||||
|
9
.github/workflows/link-checker.yml
vendored
9
.github/workflows/link-checker.yml
vendored
@@ -19,9 +19,6 @@ on:
|
||||
# * is a special character in YAML so you have to quote this string
|
||||
- cron: '30 8 * * *'
|
||||
|
||||
permissions: # added using https://github.com/step-security/secure-repo
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
link-checker:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -29,17 +26,17 @@ jobs:
|
||||
# lychee only uses the GITHUB_TOKEN to avoid rate-limiting
|
||||
contents: read
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Restore lychee cache
|
||||
uses: actions/cache@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: .lycheecache
|
||||
key: cache-lychee-${{ github.sha }}
|
||||
restore-keys: cache-lychee-
|
||||
|
||||
- name: Link Checker
|
||||
uses: lycheeverse/lychee-action@f613c4a64e50d792e0b31ec34bbcbba12263c6a6 # v2.3.0
|
||||
uses: lycheeverse/lychee-action@v1.9.3
|
||||
with:
|
||||
args: >-
|
||||
--config .github/lychee.toml
|
||||
|
35
.github/workflows/lint.yml
vendored
35
.github/workflows/lint.yml
vendored
@@ -4,32 +4,26 @@ on:
|
||||
push:
|
||||
merge_group:
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
- ready_for_review
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
docker-lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- uses: hadolint/hadolint-action@54c9adbab1582c2ef04b2016b760714a4bfde3cf # v3.1.0
|
||||
with:
|
||||
verbose: true
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||
- uses: pnpm/action-setup@v4
|
||||
# uses version from "packageManager" field in package.json
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
cache: pnpm
|
||||
node-version-file: '.node-version'
|
||||
@@ -89,9 +83,14 @@ jobs:
|
||||
continue-on-error: ${{ github.event_name == 'push' }}
|
||||
run: pnpm run docs:verify
|
||||
|
||||
- uses: testomatio/check-tests@0ea638fcec1820cf2e7b9854fdbdd04128a55bd4 # stable
|
||||
- name: Rebuild Docs
|
||||
if: ${{ steps.verifyDocs.outcome == 'failure' && github.event_name == 'push' }}
|
||||
working-directory: ./packages/mermaid
|
||||
run: pnpm run docs:build
|
||||
|
||||
- name: Commit changes
|
||||
uses: EndBug/add-and-commit@v9
|
||||
if: ${{ steps.verifyDocs.outcome == 'failure' && github.event_name == 'push' }}
|
||||
with:
|
||||
framework: cypress
|
||||
tests: './cypress/e2e/**/**.spec.js'
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
has-tests-label: true
|
||||
message: 'Update docs'
|
||||
add: 'docs/*'
|
||||
|
28
.github/workflows/pr-labeler.yml
vendored
28
.github/workflows/pr-labeler.yml
vendored
@@ -22,36 +22,10 @@ jobs:
|
||||
pull-requests: write # write permission is required to label PRs
|
||||
steps:
|
||||
- name: Label PR
|
||||
uses: release-drafter/release-drafter@b1476f6e6eb133afa41ed8589daba6dc69b4d3f5 # v6.1.0
|
||||
uses: release-drafter/release-drafter@v5
|
||||
with:
|
||||
config-name: pr-labeler.yml
|
||||
disable-autolabeler: false
|
||||
disable-releaser: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Add "Sponsored by MermaidChart" label
|
||||
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
const prNumber = context.payload.pull_request.number;
|
||||
const { data: commits } = await github.rest.pulls.listCommits({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: prNumber,
|
||||
});
|
||||
|
||||
const isSponsored = commits.every(
|
||||
(c) => c.commit.author.email?.endsWith('@mermaidchart.com')
|
||||
);
|
||||
|
||||
if (isSponsored) {
|
||||
console.log('PR is sponsored. Adding label.');
|
||||
await github.rest.issues.addLabels({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: prNumber,
|
||||
labels: ['Sponsored by MermaidChart'],
|
||||
});
|
||||
}
|
||||
|
12
.github/workflows/publish-docs.yml
vendored
12
.github/workflows/publish-docs.yml
vendored
@@ -23,12 +23,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||
- uses: pnpm/action-setup@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
cache: pnpm
|
||||
node-version-file: '.node-version'
|
||||
@@ -37,13 +37,13 @@ jobs:
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Setup Pages
|
||||
uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0
|
||||
uses: actions/configure-pages@v3
|
||||
|
||||
- name: Run Build
|
||||
run: pnpm --filter mermaid run docs:build:vitepress
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3.0.1
|
||||
uses: actions/upload-pages-artifact@v1
|
||||
with:
|
||||
path: packages/mermaid/src/vitepress/.vitepress/dist
|
||||
|
||||
@@ -56,4 +56,4 @@ jobs:
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5
|
||||
uses: actions/deploy-pages@v2
|
||||
|
23
.github/workflows/release-draft.yml
vendored
Normal file
23
.github/workflows/release-draft.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
name: Draft Release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
draft-release:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write # write permission is required to create a GitHub release
|
||||
pull-requests: read # required to read PR titles/labels
|
||||
steps:
|
||||
- name: Draft Release
|
||||
uses: release-drafter/release-drafter@v5
|
||||
with:
|
||||
disable-autolabeler: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
@@ -9,14 +9,14 @@ jobs:
|
||||
publish-preview:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||
- uses: pnpm/action-setup@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
cache: pnpm
|
||||
node-version-file: '.node-version'
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
CYPRESS_CACHE_FOLDER: .cache/Cypress
|
||||
|
||||
- name: Install Json
|
||||
run: npm i json@11.0.0 --global
|
||||
run: npm i json --global
|
||||
|
||||
- name: Publish
|
||||
working-directory: ./packages/mermaid
|
||||
|
43
.github/workflows/release-preview.yml
vendored
43
.github/workflows/release-preview.yml
vendored
@@ -1,43 +0,0 @@
|
||||
name: Preview release
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [develop]
|
||||
types: [opened, synchronize, labeled, ready_for_review]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.number }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
actions: write
|
||||
|
||||
jobs:
|
||||
preview:
|
||||
if: ${{ github.repository_owner == 'mermaid-js' }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
issues: write
|
||||
pull-requests: write
|
||||
name: Publish preview release
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||
with:
|
||||
cache: pnpm
|
||||
node-version-file: '.node-version'
|
||||
|
||||
- name: Install Packages
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Publish packages
|
||||
run: pnpx pkg-pr-new publish --pnpm './packages/*'
|
47
.github/workflows/release-publish.yml
vendored
Normal file
47
.github/workflows/release-publish.yml
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
name: Publish release
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: fregante/setup-git-user@v2
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
# uses version from "packageManager" field in package.json
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
cache: pnpm
|
||||
node-version-file: '.node-version'
|
||||
|
||||
- name: Install Packages
|
||||
run: |
|
||||
pnpm install --frozen-lockfile
|
||||
npm i json --global
|
||||
env:
|
||||
CYPRESS_CACHE_FOLDER: .cache/Cypress
|
||||
|
||||
- name: Prepare release
|
||||
run: |
|
||||
VERSION=${GITHUB_REF:10}
|
||||
echo "Preparing release $VERSION"
|
||||
git checkout -t origin/release/$VERSION
|
||||
npm version --no-git-tag-version --allow-same-version $VERSION
|
||||
git add package.json
|
||||
git commit -nm "Bump version $VERSION"
|
||||
git checkout -t origin/master
|
||||
git merge -m "Release $VERSION" --no-ff release/$VERSION
|
||||
git push --no-verify
|
||||
|
||||
- name: Publish
|
||||
run: |
|
||||
npm set //registry.npmjs.org/:_authToken $NPM_TOKEN
|
||||
npm publish
|
||||
env:
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
46
.github/workflows/release.yml
vendored
46
.github/workflows/release.yml
vendored
@@ -1,46 +0,0 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
permissions: # added using https://github.com/step-security/secure-repo
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
release:
|
||||
if: github.repository == 'mermaid-js/mermaid'
|
||||
permissions:
|
||||
contents: write # to create release (changesets/action)
|
||||
id-token: write # OpenID Connect token needed for provenance
|
||||
pull-requests: write # to create pull request (changesets/action)
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||
with:
|
||||
cache: pnpm
|
||||
node-version-file: '.node-version'
|
||||
|
||||
- name: Install Packages
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Create Release Pull Request or Publish to npm
|
||||
id: changesets
|
||||
uses: changesets/action@c8bada60c408975afd1a20b3db81d6eee6789308 # v1.4.9
|
||||
with:
|
||||
version: pnpm changeset:version
|
||||
publish: pnpm changeset:publish
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
NPM_CONFIG_PROVENANCE: true
|
37
.github/workflows/scorecard.yml
vendored
37
.github/workflows/scorecard.yml
vendored
@@ -1,37 +0,0 @@
|
||||
name: Scorecard supply-chain security
|
||||
on:
|
||||
branch_protection_rule:
|
||||
push:
|
||||
branches:
|
||||
- develop
|
||||
schedule:
|
||||
- cron: 29 15 * * 0
|
||||
permissions: read-all
|
||||
jobs:
|
||||
analysis:
|
||||
name: Scorecard analysis
|
||||
permissions:
|
||||
id-token: write
|
||||
security-events: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run analysis
|
||||
uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
publish_results: true
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
retention-days: 5
|
||||
- name: Upload to code-scanning
|
||||
uses: github/codeql-action/upload-sarif@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10
|
||||
with:
|
||||
sarif_file: results.sarif
|
12
.github/workflows/test.yml
vendored
12
.github/workflows/test.yml
vendored
@@ -9,13 +9,13 @@ jobs:
|
||||
unit-test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||
- uses: pnpm/action-setup@v4
|
||||
# uses version from "packageManager" field in package.json
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
cache: pnpm
|
||||
node-version-file: '.node-version'
|
||||
@@ -38,12 +38,8 @@ jobs:
|
||||
run: |
|
||||
pnpm exec vitest run ./packages/mermaid/src/diagrams/gantt/ganttDb.spec.ts --coverage
|
||||
|
||||
- name: Verify out-of-tree build with TypeScript
|
||||
run: |
|
||||
pnpm test:check:tsc
|
||||
|
||||
- name: Upload Coverage to Codecov
|
||||
uses: codecov/codecov-action@13ce06bfc6bbe3ecf90edbbf1bc32fe5978ca1d3 # v5.3.1
|
||||
uses: codecov/codecov-action@v3
|
||||
# Run step only pushes to develop and pull_requests
|
||||
if: ${{ github.event_name == 'pull_request' || github.ref == 'refs/heads/develop' }}
|
||||
with:
|
||||
|
2
.github/workflows/unlock-reopened-issues.yml
vendored
2
.github/workflows/unlock-reopened-issues.yml
vendored
@@ -8,6 +8,6 @@ jobs:
|
||||
triage:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: Dunning-Kruger/unlock-issues@b06b7f7e5c3f2eaa1c6d5d89f40930e4d6d9699e # v1
|
||||
- uses: Dunning-Kruger/unlock-issues@v1
|
||||
with:
|
||||
repo-token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
|
8
.github/workflows/update-browserlist.yml
vendored
8
.github/workflows/update-browserlist.yml
vendored
@@ -8,18 +8,18 @@ jobs:
|
||||
update-browser-list:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
- run: npx update-browserslist-db@latest
|
||||
- name: Commit changes
|
||||
uses: EndBug/add-and-commit@a94899bca583c204427a224a7af87c02f9b325d5 # v9.1.4
|
||||
uses: EndBug/add-and-commit@v9
|
||||
with:
|
||||
author_name: ${{ github.actor }}
|
||||
author_email: ${{ github.actor }}@users.noreply.github.com
|
||||
message: 'chore: update browsers list'
|
||||
push: false
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f # v7.0.6
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
branch: update-browserslist
|
||||
title: Update Browserslist
|
||||
|
70
.github/workflows/validate-lockfile.yml
vendored
70
.github/workflows/validate-lockfile.yml
vendored
@@ -1,70 +0,0 @@
|
||||
name: Validate pnpm-lock.yaml
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'pnpm-lock.yaml'
|
||||
- '**/package.json'
|
||||
- '.github/workflows/validate-lockfile.yml'
|
||||
|
||||
jobs:
|
||||
validate-lockfile:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
|
||||
|
||||
- name: Validate pnpm-lock.yaml entries
|
||||
id: validate # give this step an ID so we can reference its outputs
|
||||
run: |
|
||||
issues=()
|
||||
|
||||
# 1) No tarball references
|
||||
if grep -qF 'tarball:' pnpm-lock.yaml; then
|
||||
issues+=("• Tarball references found (forbidden)")
|
||||
fi
|
||||
|
||||
# 2) No unwanted vitepress paths
|
||||
if grep -qF 'packages/mermaid/src/vitepress' pnpm-lock.yaml; then
|
||||
issues+=("• Disallowed path 'packages/mermaid/src/vitepress' present. Run \`rm -rf packages/mermaid/src/vitepress && pnpm install\` to regenerate.")
|
||||
fi
|
||||
|
||||
# 3) Lockfile only changes when package.json changes
|
||||
git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.sha }} > changed.txt
|
||||
if grep -q '^pnpm-lock.yaml$' changed.txt && ! grep -q 'package.json' changed.txt; then
|
||||
issues+=("• pnpm-lock.yaml changed without any package.json modification")
|
||||
fi
|
||||
|
||||
# If any issues, output them and fail
|
||||
if [ ${#issues[@]} -gt 0 ]; then
|
||||
# Use the new GITHUB_OUTPUT approach to set a multiline output
|
||||
{
|
||||
echo "errors<<EOF"
|
||||
printf '%s\n' "${issues[@]}"
|
||||
echo "EOF"
|
||||
} >> $GITHUB_OUTPUT
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Comment on PR if validation failed
|
||||
if: failure()
|
||||
uses: peter-evans/create-or-update-comment@v4
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
body: |
|
||||
The following issue(s) were detected:
|
||||
${{ steps.validate.outputs.errors }}
|
||||
|
||||
Please address these and push an update.
|
||||
|
||||
_Posted automatically by GitHub Actions_
|
8
.gitignore
vendored
8
.gitignore
vendored
@@ -4,7 +4,6 @@ node_modules/
|
||||
coverage/
|
||||
.idea/
|
||||
.pnpm-store/
|
||||
.instructions/
|
||||
|
||||
dist
|
||||
v8-compile-cache-0
|
||||
@@ -36,7 +35,7 @@ cypress/snapshots/
|
||||
.tsbuildinfo
|
||||
tsconfig.tsbuildinfo
|
||||
|
||||
#knsv*.html
|
||||
knsv*.html
|
||||
local*.html
|
||||
stats/
|
||||
|
||||
@@ -47,9 +46,4 @@ stats/
|
||||
|
||||
demos/dev/**
|
||||
!/demos/dev/example.html
|
||||
!/demos/dev/reload.js
|
||||
tsx-0/**
|
||||
vite.config.ts.timestamp-*
|
||||
|
||||
# autogenereated by langium-cli
|
||||
generated/
|
||||
|
@@ -1,2 +0,0 @@
|
||||
ignored:
|
||||
- DL3002 # TODO: Last USER should not be root
|
4
.husky/commit-msg
Executable file
4
.husky/commit-msg
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
# . "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
# npx --no-install commitlint --edit $1
|
@@ -1,2 +1,4 @@
|
||||
#!/usr/bin/env sh
|
||||
NODE_OPTIONS="--max_old_space_size=8192" pnpm run pre-commit
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
pnpm run pre-commit
|
||||
|
@@ -1 +1 @@
|
||||
22.14.0
|
||||
v20.11.1
|
||||
|
@@ -11,10 +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
|
||||
# TODO: Lots of errors to fix
|
||||
cypress/platform/state-refactor.html
|
||||
|
@@ -3,6 +3,5 @@
|
||||
"printWidth": 100,
|
||||
"singleQuote": true,
|
||||
"useTabs": false,
|
||||
"tabWidth": 2,
|
||||
"trailingComma": "es5"
|
||||
"tabWidth": 2
|
||||
}
|
||||
|
@@ -1,15 +1,13 @@
|
||||
import type { InlineConfig } from 'vite';
|
||||
import { build, type PluginOption } from 'vite';
|
||||
import { build, InlineConfig, type PluginOption } from 'vite';
|
||||
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');
|
||||
@@ -38,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;
|
||||
@@ -47,18 +63,43 @@ interface BuildOptions {
|
||||
|
||||
export const getBuildConfig = ({ minify, core, watch, entryName }: BuildOptions): InlineConfig => {
|
||||
const external: (string | RegExp)[] = ['require', 'fs', 'path'];
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(entryName, packageOptions[entryName]);
|
||||
const { name, file, packageName } = packageOptions[entryName];
|
||||
const output: OutputOptions = [
|
||||
let output: OutputOptions = [
|
||||
{
|
||||
name,
|
||||
format: 'esm',
|
||||
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: {
|
||||
@@ -85,19 +126,16 @@ export const getBuildConfig = ({ minify, core, watch, entryName }: BuildOptions)
|
||||
plugins: [
|
||||
jisonPlugin(),
|
||||
jsonSchemaPlugin(), // handles `.schema.yaml` files
|
||||
// @ts-expect-error According to the type definitions, rollup plugins are incompatible with vite
|
||||
typescript({ compilerOptions: { declaration: false } }),
|
||||
istanbul({
|
||||
exclude: ['node_modules', 'test/', '__mocks__', 'generated'],
|
||||
exclude: ['node_modules', 'test/', '__mocks__'],
|
||||
extension: ['.js', '.ts'],
|
||||
requireEnv: true,
|
||||
forceBuildInstrument: coverage,
|
||||
}),
|
||||
...visualizerOptions(packageName, core),
|
||||
],
|
||||
define: {
|
||||
// Needs to be string
|
||||
includeLargeFeatures: 'true',
|
||||
},
|
||||
};
|
||||
|
||||
if (watch && config.build) {
|
||||
@@ -111,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' }));
|
||||
void build(getBuildConfig({ minify: false, watch, core: false, entryName: 'mermaid' }));
|
||||
build(getBuildConfig({ minify: false, watch, core: false, entryName: 'mermaid' }));
|
||||
if (!mermaidOnly) {
|
||||
void build(getBuildConfig({ minify: false, watch, entryName: 'mermaid-example-diagram' }));
|
||||
void build(getBuildConfig({ minify: false, watch, entryName: 'mermaid-zenuml' }));
|
||||
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,7 +1,6 @@
|
||||
import jison from 'jison';
|
||||
|
||||
export const transformJison = (src: string): string => {
|
||||
// @ts-ignore - Jison is not typed properly
|
||||
const parser = new jison.Generator(src, {
|
||||
moduleType: 'js',
|
||||
'token-stack': true,
|
@@ -1,5 +1,110 @@
|
||||
import type { PluginOption } from 'vite';
|
||||
import { getDefaults, getSchema, loadSchema } from '../.build/jsonSchema.js';
|
||||
import { load, JSON_SCHEMA } from 'js-yaml';
|
||||
import assert from 'node:assert';
|
||||
import Ajv2019, { type JSONSchemaType } from 'ajv/dist/2019.js';
|
||||
import { PluginOption } from 'vite';
|
||||
|
||||
import type { MermaidConfig, BaseDiagramConfig } from '../packages/mermaid/src/config.type.js';
|
||||
|
||||
/**
|
||||
* All of the keys in the mermaid config that have a mermaid diagram config.
|
||||
*/
|
||||
const MERMAID_CONFIG_DIAGRAM_KEYS = [
|
||||
'flowchart',
|
||||
'sequence',
|
||||
'gantt',
|
||||
'journey',
|
||||
'class',
|
||||
'state',
|
||||
'er',
|
||||
'pie',
|
||||
'quadrantChart',
|
||||
'xyChart',
|
||||
'requirement',
|
||||
'mindmap',
|
||||
'timeline',
|
||||
'gitGraph',
|
||||
'c4',
|
||||
'sankey',
|
||||
'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,17 +14,16 @@ 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'));
|
||||
|
||||
app.listen(9000, () => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`Listening on http://localhost:9000`);
|
||||
});
|
||||
}
|
||||
|
||||
void createServer();
|
||||
createServer();
|
||||
|
@@ -1 +0,0 @@
|
||||
./packages/mermaid/CHANGELOG.md
|
1005
CHANGELOG.md
Normal file
1005
CHANGELOG.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,488 +0,0 @@
|
||||
# Mermaid Key Components: Code Examples
|
||||
|
||||
This document provides concrete code examples demonstrating how Mermaid's key components work together.
|
||||
|
||||
## Diagram Type Examples
|
||||
|
||||
### Flowchart Diagram Structure
|
||||
|
||||
```typescript
|
||||
// packages/mermaid/src/diagrams/flowchart/flowDiagram.ts
|
||||
export const diagram = {
|
||||
parser: flowParser, // JISON parser for flowchart syntax
|
||||
get db() {
|
||||
// Database for managing diagram state
|
||||
return new FlowDB();
|
||||
},
|
||||
renderer, // SVG renderer function
|
||||
styles: flowStyles, // CSS styles specific to flowcharts
|
||||
init: (cnf: MermaidConfig) => {
|
||||
if (!cnf.flowchart) {
|
||||
cnf.flowchart = {};
|
||||
}
|
||||
// Configuration initialization
|
||||
cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Sequence Diagram Structure
|
||||
|
||||
```typescript
|
||||
// packages/mermaid/src/diagrams/sequence/sequenceDiagram.ts
|
||||
export const diagram: DiagramDefinition = {
|
||||
parser, // JISON parser for sequence syntax
|
||||
get db() {
|
||||
return new SequenceDB(); // Manages participants, messages, loops
|
||||
},
|
||||
renderer, // Draws actors, lifelines, messages
|
||||
styles, // Sequence-specific styling
|
||||
init: (cnf: MermaidConfig) => {
|
||||
if (!cnf.sequence) {
|
||||
cnf.sequence = {};
|
||||
}
|
||||
if (cnf.wrap) {
|
||||
cnf.sequence.wrap = cnf.wrap;
|
||||
}
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## Core API Examples
|
||||
|
||||
### Main API Usage Pattern
|
||||
|
||||
```typescript
|
||||
// packages/mermaid/src/mermaidAPI.ts
|
||||
|
||||
/**
|
||||
* Parse and validate diagram syntax
|
||||
*/
|
||||
async function parse(text: string, parseOptions?: ParseOptions): Promise<ParseResult> {
|
||||
addDiagrams(); // Load all diagram types
|
||||
const { code, config } = processAndSetConfigs(text);
|
||||
const diagram = await getDiagramFromText(code);
|
||||
return { diagramType: diagram.type, config };
|
||||
}
|
||||
|
||||
/**
|
||||
* Render diagram to SVG
|
||||
*/
|
||||
async function render(
|
||||
id: string,
|
||||
text: string,
|
||||
svgContainingElement?: Element
|
||||
): Promise<RenderResult> {
|
||||
const { diagramType, config } = await parse(text, { suppressErrors: true });
|
||||
|
||||
// Create diagram instance
|
||||
const diagram = new Diagram(text, {}, diagramType);
|
||||
|
||||
// Render to SVG
|
||||
const svgCode = await diagram.renderer.draw(text, id, diagram);
|
||||
|
||||
return {
|
||||
diagramType,
|
||||
svg: svgCode,
|
||||
bindFunctions: diagram.db.bindFunctions,
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Diagram Detection Example
|
||||
|
||||
```typescript
|
||||
// packages/mermaid/src/diagram-api/detectType.ts
|
||||
|
||||
export const detectors: Record<string, DiagramDetector> = {
|
||||
flowchart: {
|
||||
detector: (text: string) => /^\s*graph|flowchart/.test(text),
|
||||
loader: async () => {
|
||||
const { diagram } = await import('../diagrams/flowchart/flowDiagram.js');
|
||||
return { id: 'flowchart', diagram };
|
||||
},
|
||||
},
|
||||
sequence: {
|
||||
detector: (text: string) => /^\s*sequenceDiagram/.test(text),
|
||||
loader: async () => {
|
||||
const { diagram } = await import('../diagrams/sequence/sequenceDiagram.js');
|
||||
return { id: 'sequence', diagram };
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const detectType = function (text: string, config?: MermaidConfig): string {
|
||||
for (const [diagramType, { detector }] of Object.entries(detectors)) {
|
||||
if (detector(text, config)) {
|
||||
return diagramType;
|
||||
}
|
||||
}
|
||||
throw new UnknownDiagramError(`No diagram type detected for text: ${text}`);
|
||||
};
|
||||
```
|
||||
|
||||
## Rendering System Examples
|
||||
|
||||
### Layout Algorithm Integration
|
||||
|
||||
```typescript
|
||||
// packages/mermaid/src/rendering-util/render.ts
|
||||
|
||||
interface LayoutAlgorithm {
|
||||
render(
|
||||
layoutData: LayoutData,
|
||||
svg: SVG,
|
||||
helpers: InternalHelpers,
|
||||
options?: RenderOptions
|
||||
): Promise<void>;
|
||||
}
|
||||
|
||||
const layoutAlgorithms: Record<string, LayoutLoaderDefinition> = {};
|
||||
|
||||
export const registerLayoutLoaders = (loaders: LayoutLoaderDefinition[]) => {
|
||||
for (const loader of loaders) {
|
||||
layoutAlgorithms[loader.name] = loader;
|
||||
}
|
||||
};
|
||||
|
||||
// Default layout loaders
|
||||
const registerDefaultLayoutLoaders = () => {
|
||||
registerLayoutLoaders([
|
||||
{
|
||||
name: 'dagre',
|
||||
loader: async () => await import('./layout-algorithms/dagre/index.js'),
|
||||
},
|
||||
{
|
||||
name: 'elk',
|
||||
loader: async () => await import('./layout-algorithms/elk/index.js'),
|
||||
},
|
||||
]);
|
||||
};
|
||||
|
||||
export const render = async (data4Layout: LayoutData, svg: SVG) => {
|
||||
const layoutDefinition = layoutAlgorithms[data4Layout.layoutAlgorithm];
|
||||
const layoutRenderer = await layoutDefinition.loader();
|
||||
return layoutRenderer.render(data4Layout, svg, internalHelpers);
|
||||
};
|
||||
```
|
||||
|
||||
### Unified Renderer Example
|
||||
|
||||
```typescript
|
||||
// packages/mermaid/src/diagrams/er/erRenderer-unified.ts
|
||||
|
||||
export const draw = async function (text: string, id: string, _version: string, diag: any) {
|
||||
const { securityLevel, er: conf, layout } = getConfig();
|
||||
|
||||
// Extract data from parsed structure into Layout data format
|
||||
const data4Layout = diag.db.getData() as LayoutData;
|
||||
|
||||
// Create the root SVG element
|
||||
const svg = getDiagramElement(id, securityLevel);
|
||||
|
||||
// Configure layout
|
||||
data4Layout.type = diag.type;
|
||||
data4Layout.layoutAlgorithm = getRegisteredLayoutAlgorithm(layout);
|
||||
data4Layout.config.flowchart!.nodeSpacing = conf?.nodeSpacing || 140;
|
||||
data4Layout.config.flowchart!.rankSpacing = conf?.rankSpacing || 80;
|
||||
data4Layout.direction = diag.db.getDirection();
|
||||
data4Layout.markers = ['only_one', 'zero_or_one', 'one_or_more', 'zero_or_more'];
|
||||
data4Layout.diagramId = id;
|
||||
|
||||
// Render using layout algorithm
|
||||
await render(data4Layout, svg);
|
||||
|
||||
// Setup viewport
|
||||
setupViewPortForSVG(svg, conf.padding, conf.useMaxWidth);
|
||||
};
|
||||
```
|
||||
|
||||
## Class Diagram Renderer Examples
|
||||
|
||||
### Traditional Renderer (v2)
|
||||
|
||||
```javascript
|
||||
// packages/mermaid/src/diagrams/class/classRenderer.js
|
||||
|
||||
export const draw = function (text, id, _version, diagObj) {
|
||||
const conf = getConfig().class;
|
||||
|
||||
// Create directed graph using graphlib
|
||||
const g = new graphlib.Graph({
|
||||
multigraph: true,
|
||||
});
|
||||
|
||||
g.setGraph({
|
||||
isMultiGraph: true,
|
||||
});
|
||||
|
||||
// Add classes as nodes
|
||||
classes.forEach(function (classDef) {
|
||||
const node = svgDraw.drawClass(diagram, classDef, conf, diagObj);
|
||||
idCache[node.id] = node;
|
||||
g.setNode(node.id, node);
|
||||
});
|
||||
|
||||
// Add relationships as edges
|
||||
relations.forEach(function (relation) {
|
||||
g.setEdge(
|
||||
getGraphId(relation.id1),
|
||||
getGraphId(relation.id2),
|
||||
{ relation: relation },
|
||||
relation.title || 'DEFAULT'
|
||||
);
|
||||
});
|
||||
|
||||
// Apply layout
|
||||
dagreLayout(g);
|
||||
|
||||
// Position nodes
|
||||
g.nodes().forEach(function (v) {
|
||||
if (v !== undefined && g.node(v) !== undefined) {
|
||||
root
|
||||
.select('#' + (diagObj.db.lookUpDomId(v) || v))
|
||||
.attr(
|
||||
'transform',
|
||||
'translate(' +
|
||||
(g.node(v).x - g.node(v).width / 2) +
|
||||
',' +
|
||||
(g.node(v).y - g.node(v).height / 2) +
|
||||
' )'
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// Draw edges
|
||||
g.edges().forEach(function (e) {
|
||||
if (e !== undefined && g.edge(e) !== undefined) {
|
||||
svgDraw.drawEdge(diagram, g.edge(e), g.edge(e).relation, conf, diagObj);
|
||||
}
|
||||
});
|
||||
};
|
||||
```
|
||||
|
||||
### Modern Unified Renderer (v3)
|
||||
|
||||
```typescript
|
||||
// packages/mermaid/src/diagrams/class/classRenderer-v3-unified.ts
|
||||
|
||||
export const draw = async function (text: string, id: string, _version: string, diag: any) {
|
||||
const { securityLevel, state: conf, layout } = getConfig();
|
||||
|
||||
// Extract data from parsed structure into Layout data format
|
||||
const data4Layout = diag.db.getData() as LayoutData;
|
||||
|
||||
// Create the root SVG element
|
||||
const svg = getDiagramElement(id, securityLevel);
|
||||
|
||||
// Configure layout settings
|
||||
data4Layout.type = diag.type;
|
||||
data4Layout.layoutAlgorithm = getRegisteredLayoutAlgorithm(layout);
|
||||
data4Layout.nodeSpacing = conf?.nodeSpacing || 50;
|
||||
data4Layout.rankSpacing = conf?.rankSpacing || 50;
|
||||
data4Layout.markers = ['aggregation', 'extension', 'composition', 'dependency', 'lollipop'];
|
||||
data4Layout.diagramId = id;
|
||||
|
||||
// Use unified rendering system
|
||||
await render(data4Layout, svg);
|
||||
|
||||
// Add title
|
||||
utils.insertTitle(
|
||||
svg,
|
||||
'classDiagramTitleText',
|
||||
conf?.titleTopMargin ?? 25,
|
||||
diag.db.getDiagramTitle()
|
||||
);
|
||||
|
||||
setupViewPortForSVG(svg, padding, conf?.useMaxWidth);
|
||||
};
|
||||
```
|
||||
|
||||
## Configuration System Example
|
||||
|
||||
### Type-Safe Configuration
|
||||
|
||||
```typescript
|
||||
// packages/mermaid/src/config.type.ts
|
||||
|
||||
export interface MermaidConfig {
|
||||
theme?: 'default' | 'dark' | 'forest' | 'neutral';
|
||||
themeVariables?: any;
|
||||
startOnLoad?: boolean;
|
||||
securityLevel?: 'strict' | 'loose' | 'antiscript' | 'sandbox';
|
||||
deterministicIds?: boolean;
|
||||
fontSize?: number;
|
||||
|
||||
// Diagram-specific configurations
|
||||
flowchart?: FlowchartDiagramConfig;
|
||||
sequence?: SequenceDiagramConfig;
|
||||
class?: ClassDiagramConfig;
|
||||
state?: StateDiagramConfig;
|
||||
er?: ErDiagramConfig;
|
||||
// ... other diagram configs
|
||||
}
|
||||
|
||||
export interface FlowchartDiagramConfig extends BaseDiagramConfig {
|
||||
diagramPadding?: number;
|
||||
htmlLabels?: boolean;
|
||||
nodeSpacing?: number;
|
||||
rankSpacing?: number;
|
||||
curve?: CurveStyle;
|
||||
useMaxWidth?: boolean;
|
||||
defaultRenderer?: 'dagre-d3' | 'dagre-wrapper' | 'elk';
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration API
|
||||
|
||||
```typescript
|
||||
// packages/mermaid/src/config.ts
|
||||
|
||||
let config: MermaidConfig = assignWithDepth({}, defaultConfig);
|
||||
let directives: MermaidConfig = {};
|
||||
let currentConfig: MermaidConfig = assignWithDepth({}, defaultConfig);
|
||||
|
||||
export const getConfig = (): MermaidConfig => currentConfig;
|
||||
|
||||
export const setConfig = (conf: MermaidConfig): MermaidConfig => {
|
||||
updateCurrentConfig(conf);
|
||||
return getConfig();
|
||||
};
|
||||
|
||||
export const reset = (): void => {
|
||||
config = assignWithDepth({}, defaultConfig);
|
||||
directives = {};
|
||||
updateCurrentConfig(config);
|
||||
};
|
||||
|
||||
const updateCurrentConfig = (conf: MermaidConfig): void => {
|
||||
currentConfig = assignWithDepth({}, config, directives, conf);
|
||||
};
|
||||
```
|
||||
|
||||
## Web Integration Example
|
||||
|
||||
### Simple Usage
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="mermaid">
|
||||
graph TD A[Start] --> B{Decision} B -->|Yes| C[Action 1] B -->|No| D[Action 2]
|
||||
</div>
|
||||
|
||||
<script>
|
||||
mermaid.initialize({
|
||||
startOnLoad: true,
|
||||
theme: 'dark',
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
### Advanced Programmatic Usage
|
||||
|
||||
```javascript
|
||||
// Advanced integration example
|
||||
import mermaid from 'mermaid';
|
||||
|
||||
// Initialize with configuration
|
||||
mermaid.initialize({
|
||||
startOnLoad: false,
|
||||
theme: 'default',
|
||||
securityLevel: 'strict',
|
||||
flowchart: {
|
||||
useMaxWidth: true,
|
||||
htmlLabels: true,
|
||||
},
|
||||
sequence: {
|
||||
actorMargin: 50,
|
||||
boxMargin: 10,
|
||||
boxTextMargin: 5,
|
||||
noteMargin: 10,
|
||||
messageMargin: 35,
|
||||
},
|
||||
});
|
||||
|
||||
// Render specific diagram
|
||||
async function renderDiagram(definition, element) {
|
||||
try {
|
||||
const { svg } = await mermaid.render('graphDiv', definition);
|
||||
element.innerHTML = svg;
|
||||
} catch (error) {
|
||||
console.error('Error rendering diagram:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse and validate before rendering
|
||||
async function validateAndRender(definition, element) {
|
||||
try {
|
||||
const parseResult = await mermaid.parse(definition);
|
||||
console.log('Valid diagram type:', parseResult.diagramType);
|
||||
|
||||
const { svg } = await mermaid.render('graphDiv', definition);
|
||||
element.innerHTML = svg;
|
||||
} catch (error) {
|
||||
console.error('Invalid diagram syntax:', error);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Extension Example: Custom Diagram Type
|
||||
|
||||
### Custom Diagram Definition
|
||||
|
||||
```typescript
|
||||
// example-diagram/exampleDiagram.ts
|
||||
import type { DiagramDefinition } from '../../diagram-api/types.js';
|
||||
|
||||
export const diagram: DiagramDefinition = {
|
||||
parser: {
|
||||
parse: (text: string) => {
|
||||
// Custom parsing logic
|
||||
},
|
||||
},
|
||||
get db() {
|
||||
return {
|
||||
clear: () => {},
|
||||
// ... other required DB methods
|
||||
};
|
||||
},
|
||||
renderer: {
|
||||
draw: async (text: string, id: string, version: string) => {
|
||||
// Custom rendering logic
|
||||
const svg = d3.select(`#${id}`);
|
||||
// ... create SVG elements
|
||||
},
|
||||
},
|
||||
styles: () => `
|
||||
.example-class {
|
||||
fill: #ff6b6b;
|
||||
stroke: #333;
|
||||
}
|
||||
`,
|
||||
};
|
||||
```
|
||||
|
||||
### Registration and Usage
|
||||
|
||||
```typescript
|
||||
// Register custom diagram
|
||||
import { registerDiagram } from 'mermaid';
|
||||
import { diagram } from './exampleDiagram.js';
|
||||
|
||||
registerDiagram('example', diagram, (text) => text.includes('example'));
|
||||
|
||||
// Now can use in text:
|
||||
const diagramText = `
|
||||
example
|
||||
nodeA --> nodeB
|
||||
`;
|
||||
```
|
||||
|
||||
This comprehensive set of examples demonstrates how Mermaid's modular architecture enables powerful diagram generation while maintaining extensibility and type safety.
|
@@ -1,210 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Mermaid Functionality Demonstration</title>
|
||||
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
.demo-section {
|
||||
background: white;
|
||||
margin: 20px 0;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.demo-title {
|
||||
color: #333;
|
||||
border-bottom: 2px solid #007acc;
|
||||
padding-bottom: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.mermaid {
|
||||
text-align: center;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.code-block {
|
||||
background: #f8f9fa;
|
||||
border: 1px solid #e9ecef;
|
||||
border-radius: 4px;
|
||||
padding: 15px;
|
||||
font-family: 'Courier New', monospace;
|
||||
margin: 10px 0;
|
||||
overflow-x: auto;
|
||||
}
|
||||
.header {
|
||||
text-align: center;
|
||||
color: #007acc;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<h1>🧜♀️ Mermaid Functionality Demonstration</h1>
|
||||
<p>A showcase of Mermaid's key diagram types and capabilities</p>
|
||||
</div>
|
||||
|
||||
<div class="demo-section">
|
||||
<h2 class="demo-title">1. Flowchart - Decision Flow</h2>
|
||||
<p><strong>Use case:</strong> Process flows, decision trees, algorithm visualization</p>
|
||||
<div class="code-block">
|
||||
flowchart TD A[Start] --> B{Is it working?} B -->|Yes| C[Great!] B -->|No| D[Debug] D -->
|
||||
E[Fix issues] E --> B C --> F[Deploy]
|
||||
</div>
|
||||
<div class="mermaid">
|
||||
flowchart TD A[Start] --> B{Is it working?} B -->|Yes| C[Great!] B -->|No| D[Debug] D -->
|
||||
E[Fix issues] E --> B C --> F[Deploy]
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo-section">
|
||||
<h2 class="demo-title">2. Sequence Diagram - API Interaction</h2>
|
||||
<p><strong>Use case:</strong> API documentation, system interactions, communication flows</p>
|
||||
<div class="code-block">
|
||||
sequenceDiagram participant C as Client participant S as Server participant DB as Database
|
||||
C->>S: Request user data S->>DB: Query user table DB-->>S: Return user data S-->>C: JSON
|
||||
response Note right of C: Client processes data
|
||||
</div>
|
||||
<div class="mermaid">
|
||||
sequenceDiagram participant C as Client participant S as Server participant DB as Database
|
||||
C->>S: Request user data S->>DB: Query user table DB-->>S: Return user data S-->>C: JSON
|
||||
response Note right of C: Client processes data
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo-section">
|
||||
<h2 class="demo-title">3. Class Diagram - Software Architecture</h2>
|
||||
<p>
|
||||
<strong>Use case:</strong> Object-oriented design, software architecture, database schemas
|
||||
</p>
|
||||
<div class="code-block">
|
||||
classDiagram class User { +String name +String email +login() +logout() } class Order { +int
|
||||
id +Date date +float total +calculate() } class Product { +String name +float price +int
|
||||
stock } User ||--o{ Order : places Order }|--|| Product : contains
|
||||
</div>
|
||||
<div class="mermaid">
|
||||
classDiagram class User { +String name +String email +login() +logout() } class Order { +int
|
||||
id +Date date +float total +calculate() } class Product { +String name +float price +int
|
||||
stock } User ||--o{ Order : places Order }|--|| Product : contains
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo-section">
|
||||
<h2 class="demo-title">4. Git Graph - Development Workflow</h2>
|
||||
<p>
|
||||
<strong>Use case:</strong> Git workflow documentation, branching strategies, release
|
||||
processes
|
||||
</p>
|
||||
<div class="code-block">
|
||||
gitGraph commit id: "Initial" commit id: "Setup" branch feature checkout feature commit id:
|
||||
"Feature A" commit id: "Feature B" checkout main merge feature commit id: "Release v1.0"
|
||||
branch hotfix checkout hotfix commit id: "Fix bug" checkout main merge hotfix commit id:
|
||||
"Release v1.1"
|
||||
</div>
|
||||
<div class="mermaid">
|
||||
gitGraph commit id: "Initial" commit id: "Setup" branch feature checkout feature commit id:
|
||||
"Feature A" commit id: "Feature B" checkout main merge feature commit id: "Release v1.0"
|
||||
branch hotfix checkout hotfix commit id: "Fix bug" checkout main merge hotfix commit id:
|
||||
"Release v1.1"
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo-section">
|
||||
<h2 class="demo-title">5. Gantt Chart - Project Timeline</h2>
|
||||
<p><strong>Use case:</strong> Project management, milestone tracking, resource planning</p>
|
||||
<div class="code-block">
|
||||
gantt title Development Timeline dateFormat YYYY-MM-DD section Planning Requirements :done,
|
||||
req, 2024-01-01, 2024-01-07 Design :done, des, 2024-01-08, 2024-01-14 section Development
|
||||
Backend API :active, api, 2024-01-15, 2024-02-15 Frontend :frontend, after api, 20d Testing
|
||||
:test, after frontend, 10d section Deployment Staging :staging, after test, 3d Production
|
||||
:prod, after staging, 2d
|
||||
</div>
|
||||
<div class="mermaid">
|
||||
gantt title Development Timeline dateFormat YYYY-MM-DD section Planning Requirements :done,
|
||||
req, 2024-01-01, 2024-01-07 Design :done, des, 2024-01-08, 2024-01-14 section Development
|
||||
Backend API :active, api, 2024-01-15, 2024-02-15 Frontend :frontend, after api, 20d Testing
|
||||
:test, after frontend, 10d section Deployment Staging :staging, after test, 3d Production
|
||||
:prod, after staging, 2d
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo-section">
|
||||
<h2 class="demo-title">6. State Diagram - System States</h2>
|
||||
<p><strong>Use case:</strong> State machines, user workflows, system behavior modeling</p>
|
||||
<div class="code-block">
|
||||
stateDiagram-v2 [*] --> Idle Idle --> Loading : start_request Loading --> Success :
|
||||
request_success Loading --> Error : request_failed Success --> Idle : reset Error --> Idle :
|
||||
retry Error --> [*] : give_up
|
||||
</div>
|
||||
<div class="mermaid">
|
||||
stateDiagram-v2 [*] --> Idle Idle --> Loading : start_request Loading --> Success :
|
||||
request_success Loading --> Error : request_failed Success --> Idle : reset Error --> Idle :
|
||||
retry Error --> [*] : give_up
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo-section">
|
||||
<h2 class="demo-title">7. Pie Chart - Data Visualization</h2>
|
||||
<p><strong>Use case:</strong> Data visualization, market share, resource allocation</p>
|
||||
<div class="code-block">
|
||||
pie title Technology Stack Usage "JavaScript" : 35 "TypeScript" : 25 "Python" : 20 "Java" :
|
||||
15 "Other" : 5
|
||||
</div>
|
||||
<div class="mermaid">
|
||||
pie title Technology Stack Usage "JavaScript" : 35 "TypeScript" : 25 "Python" : 20 "Java" :
|
||||
15 "Other" : 5
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo-section">
|
||||
<h2 class="demo-title">8. User Journey - UX Flow</h2>
|
||||
<p>
|
||||
<strong>Use case:</strong> User experience mapping, customer journeys, process optimization
|
||||
</p>
|
||||
<div class="code-block">
|
||||
journey title User Registration Journey section Discovery Visit homepage : 5: User Read
|
||||
about features : 4: User Check pricing : 3: User section Registration Click signup : 3: User
|
||||
Fill form : 2: User Verify email : 1: User, System section Onboarding Complete profile : 4:
|
||||
User Take tutorial : 5: User First task : 5: User
|
||||
</div>
|
||||
<div class="mermaid">
|
||||
journey title User Registration Journey section Discovery Visit homepage : 5: User Read
|
||||
about features : 4: User Check pricing : 3: User section Registration Click signup : 3: User
|
||||
Fill form : 2: User Verify email : 1: User, System section Onboarding Complete profile : 4:
|
||||
User Take tutorial : 5: User First task : 5: User
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Initialize Mermaid with configuration
|
||||
mermaid.initialize({
|
||||
startOnLoad: true,
|
||||
theme: 'default',
|
||||
securityLevel: 'loose',
|
||||
flowchart: {
|
||||
useMaxWidth: true,
|
||||
htmlLabels: true,
|
||||
},
|
||||
sequence: {
|
||||
actorMargin: 50,
|
||||
width: 150,
|
||||
height: 65,
|
||||
boxMargin: 10,
|
||||
},
|
||||
gantt: {
|
||||
useMaxWidth: true,
|
||||
leftMargin: 75,
|
||||
gridLineStartPadding: 35,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
15
Dockerfile
15
Dockerfile
@@ -1,13 +1,2 @@
|
||||
FROM node:22.12.0-alpine3.19@sha256:40dc4b415c17b85bea9be05314b4a753f45a4e1716bb31c01182e6c53d51a654
|
||||
|
||||
USER 0:0
|
||||
|
||||
RUN corepack enable \
|
||||
&& corepack enable pnpm
|
||||
|
||||
RUN apk add --no-cache git~=2.43.4 \
|
||||
&& git config --add --system safe.directory /mermaid
|
||||
|
||||
ENV NODE_OPTIONS="--max_old_space_size=8192"
|
||||
|
||||
EXPOSE 9000 3333
|
||||
FROM node:20.11.1-alpine3.19 AS base
|
||||
RUN wget -qO- https://get.pnpm.io/install.sh | ENV="$HOME/.shrc" SHELL="$(which sh)" sh -
|
||||
|
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"drips": {
|
||||
"ethereum": {
|
||||
"ownedBy": "0x0831DDFe60d009d9448CC976157b539089aB821E"
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,249 +0,0 @@
|
||||
# Mermaid: Overview of Main Functionality and Key Components
|
||||
|
||||
## What is Mermaid?
|
||||
|
||||
Mermaid is a JavaScript-based diagramming and charting tool that uses Markdown-inspired text definitions to create and modify complex diagrams. The main purpose of Mermaid is to help documentation catch up with development by enabling users to create easily modifiable diagrams that can be integrated into production scripts and documentation workflows.
|
||||
|
||||
**Core Philosophy**: "Doc-Rot is a Catch-22 that Mermaid helps to solve" - providing a solution to the common problem where diagramming costs precious developer time and gets outdated quickly, but not having diagrams hurts productivity and organizational learning.
|
||||
|
||||
## Main Functionality
|
||||
|
||||
### 1. **Text-to-Diagram Conversion**
|
||||
|
||||
- Converts Markdown-inspired text definitions into SVG diagrams
|
||||
- Supports over 15+ different diagram types
|
||||
- Real-time rendering and preview capabilities
|
||||
- Integration with popular platforms (GitHub, GitLab, etc.)
|
||||
|
||||
### 2. **Interactive Diagram Creation**
|
||||
|
||||
- Live Editor for interactive diagram creation
|
||||
- Web integration module for embedding in web pages
|
||||
- Dynamic rendering and modification capabilities
|
||||
|
||||
### 3. **Extensible Architecture**
|
||||
|
||||
- Plugin system for custom diagram types
|
||||
- Configurable themes and styling
|
||||
- Multiple layout algorithms support
|
||||
- External diagram definition loading
|
||||
|
||||
## Key Components
|
||||
|
||||
### Core Architecture
|
||||
|
||||
#### 1. **Entry Points & API Layer**
|
||||
|
||||
- **`mermaid.ts`**: Main web page integration module, provides the primary interface for users
|
||||
- **`mermaidAPI.ts`**: Core API containing functions for parsing and rendering diagrams
|
||||
- **`Diagram.ts`**: Main diagram abstraction class that handles diagram lifecycle
|
||||
|
||||
#### 2. **Configuration System**
|
||||
|
||||
- **`config.ts`** & **`config.type.ts`**: Centralized configuration management
|
||||
- **`defaultConfig.ts`**: Default configuration values
|
||||
- Supports runtime configuration updates and diagram-specific settings
|
||||
|
||||
#### 3. **Parser & Detection System**
|
||||
|
||||
- **`diagram-api/detectType.ts`**: Automatic diagram type detection from text input
|
||||
- **`diagram-api/loadDiagram.ts`**: Dynamic loading and registration of diagram parsers
|
||||
- **`preprocess.ts`**: Text preprocessing and directive handling
|
||||
|
||||
### Diagram Types (Located in `/src/diagrams/`)
|
||||
|
||||
Mermaid supports a comprehensive set of diagram types, each with its own parser, renderer, and styling:
|
||||
|
||||
#### **Core Diagram Types:**
|
||||
|
||||
1. **Flowchart** - Flow diagrams with nodes, edges, and decision points
|
||||
2. **Sequence** - Interaction diagrams between actors over time
|
||||
3. **Class** - Object-oriented modeling diagrams
|
||||
4. **State** - State machine and statechart diagrams
|
||||
5. **Gantt** - Project timeline and scheduling charts
|
||||
6. **Git** - Git branching and merging visualizations
|
||||
|
||||
#### **Specialized Diagram Types:**
|
||||
|
||||
7. **Pie** - Data visualization pie charts
|
||||
8. **User Journey** - User experience journey mapping
|
||||
9. **C4** - C4 architecture diagrams (Context, Container, Component, Code)
|
||||
10. **ER (Entity-Relationship)** - Database modeling diagrams
|
||||
11. **Mindmap** - Hierarchical mind mapping
|
||||
12. **Architecture** - System architecture diagrams
|
||||
13. **Block** - Block diagrams
|
||||
14. **Kanban** - Kanban board visualization
|
||||
15. **Packet** - Network packet diagrams
|
||||
16. **Quadrant** - Four-quadrant analysis charts
|
||||
17. **Radar** - Radar/spider charts
|
||||
18. **Requirement** - Requirements modeling
|
||||
19. **Sankey** - Flow diagrams showing quantities
|
||||
20. **Timeline** - Chronological event timelines
|
||||
21. **Treemap** - Hierarchical data visualization
|
||||
22. **XYChart** - Scatter plots and line charts
|
||||
|
||||
#### **Diagram Structure Pattern:**
|
||||
|
||||
Each diagram type follows a consistent structure:
|
||||
|
||||
```typescript
|
||||
export const diagram = {
|
||||
parser: parserDefinition, // JISON or custom parser
|
||||
db: databaseClass, // Data management and state
|
||||
renderer: rendererFunction, // SVG rendering logic
|
||||
styles: stylingDefinition, // CSS styling
|
||||
init: initializationFunction, // Setup and configuration
|
||||
};
|
||||
```
|
||||
|
||||
### Rendering System
|
||||
|
||||
#### 1. **Core Rendering (`rendering-util/`)**
|
||||
|
||||
- **`render.ts`**: Main rendering orchestrator with pluggable layout algorithms
|
||||
- **`createGraph.ts`** & **`createText.ts`**: Basic shape and text creation
|
||||
- **`insertElementsForSize.ts`**: Element sizing and positioning
|
||||
- **`setupViewPortForSVG.ts`**: SVG viewport management
|
||||
|
||||
#### 2. **Layout Algorithms (`layout-algorithms/`)**
|
||||
|
||||
- **Dagre**: Default hierarchical layout algorithm
|
||||
- **Elk**: Advanced layout engine with multiple algorithms
|
||||
- **Cose-Bilkent**: Physics-based layout for complex graphs
|
||||
- **Tidy-Tree**: Tree layout algorithm
|
||||
|
||||
#### 3. **Styling & Theming**
|
||||
|
||||
- **`themes/`**: Multiple built-in themes (default, dark, forest, neutral, etc.)
|
||||
- **`styles.ts`**: CSS-in-JS styling system
|
||||
- Theme inheritance and customization capabilities
|
||||
|
||||
### Security & Safety
|
||||
|
||||
#### 1. **Security Levels**
|
||||
|
||||
- **Sandbox Mode**: Renders diagrams in sandboxed iframes to prevent script execution
|
||||
- **Loose Mode**: Standard rendering with sanitization
|
||||
- **Strict Mode**: Enhanced security with limited functionality
|
||||
|
||||
#### 2. **Content Sanitization**
|
||||
|
||||
- **DOMPurify Integration**: XSS protection for user-generated content
|
||||
- Input validation and sanitization
|
||||
- Safe handling of external content
|
||||
|
||||
### Extension & Integration System
|
||||
|
||||
#### 1. **External Diagram Support**
|
||||
|
||||
- Dynamic loading of custom diagram types
|
||||
- Plugin architecture for extending functionality
|
||||
- External diagram definition interface
|
||||
|
||||
#### 2. **Layout Extension**
|
||||
|
||||
- Pluggable layout algorithms
|
||||
- Custom layout loader registration
|
||||
- Runtime algorithm selection
|
||||
|
||||
#### 3. **Icon System**
|
||||
|
||||
- **`icons.ts`**: Icon pack management
|
||||
- SVG icon rendering
|
||||
- Customizable icon libraries
|
||||
|
||||
### Package Structure (Monorepo)
|
||||
|
||||
The repository uses a monorepo structure with pnpm workspaces:
|
||||
|
||||
#### **Main Packages:**
|
||||
|
||||
- **`packages/mermaid/`**: Core Mermaid library
|
||||
- **`packages/mermaid-example-diagram/`**: Example external diagram
|
||||
- **`packages/mermaid-layout-elk/`**: Elk layout algorithm
|
||||
- **`packages/mermaid-layout-tidy-tree/`**: Tidy tree layout
|
||||
- **`packages/mermaid-zenuml/`**: ZenUML integration
|
||||
- **`packages/parser/`**: Parser utilities
|
||||
- **`packages/tiny/`**: Minimal Mermaid build
|
||||
|
||||
#### **Supporting Infrastructure:**
|
||||
|
||||
- **`docs/`**: Documentation and website content
|
||||
- **`demos/`**: Example implementations
|
||||
- **`cypress/`**: End-to-end testing
|
||||
- **`tests/`**: Unit and integration tests
|
||||
|
||||
### Development & Build System
|
||||
|
||||
#### 1. **Build Pipeline**
|
||||
|
||||
- **ESBuild**: Fast JavaScript bundling
|
||||
- **TypeScript**: Type checking and compilation
|
||||
- **Vite**: Development server and hot reloading
|
||||
|
||||
#### 2. **Testing Strategy**
|
||||
|
||||
- **Vitest**: Unit testing framework
|
||||
- **Cypress**: End-to-end visual regression testing
|
||||
- **Applitools**: Visual testing integration
|
||||
- **Argos**: PR visual regression testing
|
||||
|
||||
#### 3. **Code Quality**
|
||||
|
||||
- **ESLint**: JavaScript/TypeScript linting
|
||||
- **Prettier**: Code formatting
|
||||
- **Husky**: Git hooks for pre-commit checks
|
||||
- **CSpell**: Spell checking for documentation
|
||||
|
||||
## Integration Ecosystem
|
||||
|
||||
### Official Integrations
|
||||
|
||||
- **Mermaid Chart**: Commercial diagram editor and collaboration platform
|
||||
- **GitHub**: Native Mermaid support in GitHub Markdown
|
||||
- **GitLab**: Built-in Mermaid rendering
|
||||
|
||||
### Community Integrations
|
||||
|
||||
- **Productivity Tools**: Notion, Confluence, Obsidian, etc.
|
||||
- **Development Tools**: VS Code, IntelliJ, various editors
|
||||
- **Documentation**: GitBook, Docusaurus, VuePress, etc.
|
||||
- **Communication**: Slack, Discord, Microsoft Teams
|
||||
- **CMS/Wiki Systems**: MediaWiki, TiddlyWiki, etc.
|
||||
|
||||
## Usage Patterns
|
||||
|
||||
### 1. **Direct Web Integration**
|
||||
|
||||
```javascript
|
||||
import mermaid from 'mermaid';
|
||||
mermaid.initialize({ startOnLoad: true });
|
||||
```
|
||||
|
||||
### 2. **Programmatic API Usage**
|
||||
|
||||
```javascript
|
||||
const { svg } = await mermaid.render('graphDiv', 'graph TD; A-->B');
|
||||
```
|
||||
|
||||
### 3. **Configuration & Customization**
|
||||
|
||||
```javascript
|
||||
mermaid.initialize({
|
||||
theme: 'dark',
|
||||
flowchart: { useMaxWidth: true },
|
||||
sequence: { actorMargin: 50 },
|
||||
});
|
||||
```
|
||||
|
||||
## Future Extensibility
|
||||
|
||||
The architecture is designed for extensibility through:
|
||||
|
||||
- **Plugin System**: Easy addition of new diagram types
|
||||
- **Layout Algorithms**: Pluggable layout engines
|
||||
- **Theming**: Comprehensive theme customization
|
||||
- **Output Formats**: Support for multiple output formats
|
||||
- **Integration APIs**: Well-defined interfaces for third-party integration
|
||||
|
||||
This modular architecture makes Mermaid a powerful platform for diagram generation that can grow and adapt to new use cases while maintaining backward compatibility and performance.
|
44
README.md
44
README.md
@@ -15,7 +15,7 @@ Generate diagrams from markdown-like text.
|
||||
<a href="https://mermaid.live/"><b>Live Editor!</b></a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://mermaid.js.org">📖 Documentation</a> | <a href="https://mermaid.js.org/intro/">🚀 Getting Started</a> | <a href="https://www.jsdelivr.com/package/npm/mermaid">🌐 CDN</a> | <a href="https://discord.gg/sKeNQX4Wtj" title="Discord invite">🙌 Join Us</a>
|
||||
<a href="https://mermaid.js.org">📖 Documentation</a> | <a href="https://mermaid.js.org/intro/">🚀 Getting Started</a> | <a href="https://www.jsdelivr.com/package/npm/mermaid">🌐 CDN</a> | <a href="https://discord.gg/AgrbSrBer3" title="Discord invite">🙌 Join Us</a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="./README.zh-CN.md">简体中文</a>
|
||||
@@ -33,10 +33,8 @@ Try Live Editor previews of future releases: <a href="https://develop.git.mermai
|
||||
[](https://app.codecov.io/github/mermaid-js/mermaid/tree/develop)
|
||||
[](https://www.jsdelivr.com/package/npm/mermaid)
|
||||
[](https://www.npmjs.com/package/mermaid)
|
||||
[](https://discord.gg/sKeNQX4Wtj)
|
||||
[](https://discord.gg/AgrbSrBer3)
|
||||
[](https://twitter.com/mermaidjs_)
|
||||
[](https://argos-ci.com?utm_source=mermaid&utm_campaign=oss)
|
||||
[](https://securityscorecards.dev/viewer/?uri=github.com/mermaid-js/mermaid)
|
||||
|
||||
<img src="./img/header.png" alt="" />
|
||||
|
||||
@@ -44,7 +42,7 @@ Try Live Editor previews of future releases: <a href="https://develop.git.mermai
|
||||
|
||||
**Thanks to all involved, people committing pull requests, people answering questions! 🙏**
|
||||
|
||||
<a href="https://mermaid.js.org/landing/"><img src="https://github.com/mermaid-js/mermaid/blob/master/docs/intro/img/book-banner-post-release.jpg" alt='Banner for "The Official Guide to Mermaid.js" book'></a>
|
||||
<a href="https://mermaid.js.org/landing/"><img src="https://github.com/mermaid-js/mermaid/blob/master/docs/intro/img/book-banner-post-release.jpg" alt="Explore Mermaid.js in depth, with real-world examples, tips & tricks from the creator... The first official book on Mermaid is available for purchase. Check it out!"></a>
|
||||
|
||||
## Table of content
|
||||
|
||||
@@ -83,10 +81,6 @@ You can also use Mermaid within [GitHub](https://github.blog/2022-02-14-include-
|
||||
|
||||
For a more detailed introduction to Mermaid and some of its more basic uses, look to the [Beginner's Guide](https://mermaid.js.org/intro/getting-started.html), [Usage](https://mermaid.js.org/config/usage.html) and [Tutorials](https://mermaid.js.org/ecosystem/tutorials.html).
|
||||
|
||||
Our PR Visual Regression Testing is powered by [Argos](https://argos-ci.com/?utm_source=mermaid&utm_campaign=oss) with their generous Open Source plan. It makes the process of reviewing PRs with visual changes a breeze.
|
||||
|
||||
[](https://argos-ci.com?utm_source=mermaid&utm_campaign=oss)
|
||||
|
||||
In our release process we rely heavily on visual regression tests using [applitools](https://applitools.com/). Applitools is a great service which has been easy to use and integrate with our tests.
|
||||
|
||||
<a href="https://applitools.com/">
|
||||
@@ -253,34 +247,6 @@ pie
|
||||
|
||||
### Git graph [experimental - <a href="https://mermaid.live/edit#pako:eNqNkMFugzAMhl8F-VyVAR1tOW_aA-zKxSSGRCMJCk6lCvHuNZPKZdM0n-zf3_8r8QIqaIIGMqnB8kfEybQ--y4VnLP8-9RF9Mpkmm40hmlnDKmvkPiH_kfS7nFo_VN0FAf6XwocQGgxa_nGsm1bYEOOWmik1dRjGrmF1q-Cpkkj07u2HCI0PY4zHQATh8-7V9BwTPSE3iwOEd1OjQE1iWkBvk_bzQY7s0Sq4Hs7bHqKo8iGeZqbPN_WR7mpSd1RHpvPVhuMbG7XOq_L-oJlRfW5wteq0qorrpe-PBW9Pr8UJcK6rg-BLYPQ">live editor</a>]
|
||||
|
||||
```
|
||||
gitGraph
|
||||
commit
|
||||
commit
|
||||
branch develop
|
||||
checkout develop
|
||||
commit
|
||||
commit
|
||||
checkout main
|
||||
merge develop
|
||||
commit
|
||||
commit
|
||||
```
|
||||
|
||||
```mermaid
|
||||
gitGraph
|
||||
commit
|
||||
commit
|
||||
branch develop
|
||||
checkout develop
|
||||
commit
|
||||
commit
|
||||
checkout main
|
||||
merge develop
|
||||
commit
|
||||
commit
|
||||
```
|
||||
|
||||
### Bar chart (using gantt chart) [<a href="https://mermaid.js.org/syntax/gantt.html">docs</a> - <a href="https://mermaid.live/edit#pako:eNptkU1vhCAQhv8KIenNugiI4rkf6bmXpvEyFVxJFDYyNt1u9r8X63Z7WQ9m5pknLzieaBeMpQ3dg0dsPUkPOhwteXZIXmJcbCT3xMAxkuh8Z8kIEclyMIB209fqKcwTICFvG4IvFy_oLrZ-g9F26ILfQgvNFN94VaRXQ1iWqpumZBcu1J8p1E1TXDx59eQNr5LyEqjJn6hv5QnGNlxevZJmdLLpy5xJSzut45biYCfb0iaVxvawjNjS1p-TCguG16PvaIPzYjO67e3BwX6GiTY9jPFKH43DMF_hGMDY1J4oHg-_f8hFTJFd8L3br3yZx4QHxENsdrt1nO8dDstH3oVpF50ZYMbhU6ud4qoGLqyqBJRCmO6j0HXPZdGbihUc6Pmc0QP49xD-b5X69ZQv2gjO81IwzWqhC1lKrjJ6pA3nVS7SMiVjrKirWlYp5fs3osgrWeo00lorLWvOzz8JVbXm">live editor</a>]
|
||||
|
||||
```
|
||||
@@ -447,7 +413,7 @@ For public sites, it can be precarious to retrieve text from users on the intern
|
||||
|
||||
As an extra level of security for sites with external users we are happy to introduce a new security level in which the diagram is rendered in a sandboxed iframe preventing javascript in the code from being executed. This is a great step forward for better security.
|
||||
|
||||
_Unfortunately you cannot have a cake and eat it at the same time which in this case means that some of the interactive functionality gets blocked along with the possible malicious code._
|
||||
_Unfortunately you can not have a cake and eat it at the same time which in this case means that some of the interactive functionality gets blocked along with the possible malicious code._
|
||||
|
||||
## Reporting vulnerabilities
|
||||
|
||||
@@ -463,7 +429,7 @@ A quick note from Knut Sveidqvist:
|
||||
>
|
||||
> _Thank you to [Tyler Long](https://github.com/tylerlong) who has been a collaborator since April 2017._
|
||||
>
|
||||
> _Thank you to the ever-growing list of [contributors](https://github.com/mermaid-js/mermaid/graphs/contributors) that brought the project this far!_
|
||||
> _Thank you to the ever-growing list of [contributors](https://github.com/knsv/mermaid/graphs/contributors) that brought the project this far!_
|
||||
|
||||
---
|
||||
|
||||
|
@@ -15,7 +15,7 @@ Mermaid
|
||||
<a href="https://mermaid.live/"><b>实时编辑器!</b></a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://mermaid.js.org">📖 文档</a> | <a href="https://mermaid.js.org/intro/">🚀 入门</a> | <a href="https://www.jsdelivr.com/package/npm/mermaid">🌐 CDN</a> | <a href="https://discord.gg/sKeNQX4Wtj" title="Discord invite">🙌 加入我们</a>
|
||||
<a href="https://mermaid.js.org">📖 文档</a> | <a href="https://mermaid.js.org/intro/">🚀 入门</a> | <a href="https://www.jsdelivr.com/package/npm/mermaid">🌐 CDN</a> | <a href="https://discord.gg/AgrbSrBer3" title="Discord invite">🙌 加入我们</a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="./README.md">English</a>
|
||||
@@ -34,7 +34,7 @@ Mermaid
|
||||
[](https://app.codecov.io/github/mermaid-js/mermaid/tree/develop)
|
||||
[](https://www.jsdelivr.com/package/npm/mermaid)
|
||||
[](https://www.npmjs.com/package/mermaid)
|
||||
[](https://discord.gg/sKeNQX4Wtj)
|
||||
[](https://discord.gg/AgrbSrBer3)
|
||||
[](https://twitter.com/mermaidjs_)
|
||||
|
||||
<img src="./img/header.png" alt="" />
|
||||
@@ -43,13 +43,13 @@ Mermaid
|
||||
|
||||
**感谢所有参与进来提交 PR,解答疑问的人们! 🙏**
|
||||
|
||||
<a href="https://mermaid.js.org/landing/"><img src="https://github.com/mermaid-js/mermaid/blob/master/docs/intro/img/book-banner-post-release.jpg" alt='Banner for "The Official Guide to Mermaid.js" book'></a>
|
||||
<a href="https://mermaid.js.org/landing/"><img src="https://github.com/mermaid-js/mermaid/blob/master/docs/intro/img/book-banner-post-release.jpg" alt="Explore Mermaid.js in depth, with real-world examples, tips & tricks from the creator... The first official book on Mermaid is available for purchase. Check it out!"></a>
|
||||
|
||||
## 关于 Mermaid
|
||||
|
||||
<!-- <Main description> -->
|
||||
|
||||
Mermaid 是一个基于 JavaScript 的图表绘制工具,通过解析类 Markdown 的文本语法来实现图表的创建和动态修改。Mermaid 诞生的主要目的是让文档的更新能够及时跟上开发进度。
|
||||
Mermaid 是一个基于 Javascript 的图表绘制工具,通过解析类 Markdown 的文本语法来实现图表的创建和动态修改。Mermaid 诞生的主要目的是让文档的更新能够及时跟上开发进度。
|
||||
|
||||
> Doc-Rot 是 Mermaid 致力于解决的一个难题。
|
||||
|
||||
@@ -358,7 +358,7 @@ _很不幸的是,鱼与熊掌不可兼得,在这个场景下它意味着在
|
||||
|
||||
> _特别感谢 [d3](https://d3js.org/) 和 [dagre-d3](https://github.com/cpettitt/dagre-d3) 这两个优秀的项目,它们提供了图形布局和绘图工具库!_ > _同样感谢 [js-sequence-diagram](https://bramp.github.io/js-sequence-diagrams) 提供了时序图语法的使用。 感谢 Jessica Peter 提供了甘特图渲染的灵感。_ > _感谢 [Tyler Long](https://github.com/tylerlong) 从 2017 年四月开始成为了项目的合作者。_
|
||||
>
|
||||
> _感谢越来越多的 [贡献者们](https://github.com/mermaid-js/mermaid/graphs/contributors),没有你们,就没有这个项目的今天!_
|
||||
> _感谢越来越多的 [贡献者们](https://github.com/knsv/mermaid/graphs/contributors),没有你们,就没有这个项目的今天!_
|
||||
|
||||
---
|
||||
|
||||
|
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,
|
||||
};
|
13
__mocks__/d3.ts
Normal file
13
__mocks__/d3.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { MockedD3 } from '../packages/mermaid/src/tests/MockedD3.js';
|
||||
|
||||
export const select = function () {
|
||||
return new MockedD3();
|
||||
};
|
||||
|
||||
export const selectAll = function () {
|
||||
return new MockedD3();
|
||||
};
|
||||
|
||||
export const curveBasis = 'basis';
|
||||
export const curveLinear = 'linear';
|
||||
export const curveCardinal = 'cardinal';
|
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,10 +1,7 @@
|
||||
import eyesPlugin from '@applitools/eyes-cypress';
|
||||
import { registerArgosTask } from '@argos-ci/cypress/task';
|
||||
import coverage from '@cypress/code-coverage/task.js';
|
||||
import { defineConfig } from 'cypress';
|
||||
import { addMatchImageSnapshotPlugin } from 'cypress-image-snapshot/plugin.js';
|
||||
import cypressSplit from 'cypress-split';
|
||||
|
||||
import { addMatchImageSnapshotPlugin } from 'cypress-image-snapshot/plugin';
|
||||
import coverage from '@cypress/code-coverage/task';
|
||||
import eyesPlugin from '@applitools/eyes-cypress';
|
||||
export default eyesPlugin(
|
||||
defineConfig({
|
||||
projectId: 'n2sma2',
|
||||
@@ -14,25 +11,16 @@ export default eyesPlugin(
|
||||
specPattern: 'cypress/integration/**/*.{js,ts}',
|
||||
setupNodeEvents(on, config) {
|
||||
coverage(on, config);
|
||||
cypressSplit(on, config);
|
||||
on('before:browser:launch', (browser, launchOptions) => {
|
||||
if (browser.name === 'chrome' && browser.isHeadless) {
|
||||
launchOptions.args.push('--window-size=1440,1024', '--force-device-scale-factor=1');
|
||||
}
|
||||
return launchOptions;
|
||||
});
|
||||
addMatchImageSnapshotPlugin(on, config);
|
||||
// copy any needed variables from process.env to config.env
|
||||
config.env.useAppli = process.env.USE_APPLI ? true : false;
|
||||
config.env.useArgos = process.env.RUN_VISUAL_TEST === 'true';
|
||||
|
||||
if (config.env.useArgos) {
|
||||
registerArgosTask(on, config, {
|
||||
// Enable upload to Argos only when it runs on CI.
|
||||
uploadToArgos: !!process.env.CI,
|
||||
});
|
||||
} else {
|
||||
addMatchImageSnapshotPlugin(on, config);
|
||||
}
|
||||
// do not forget to return the changed config object!
|
||||
return config;
|
||||
},
|
||||
|
@@ -14,7 +14,7 @@ interface CodeObject {
|
||||
mermaid: CypressMermaidConfig;
|
||||
}
|
||||
|
||||
export const utf8ToB64 = (str: string): string => {
|
||||
const utf8ToB64 = (str: string): string => {
|
||||
return Buffer.from(decodeURIComponent(encodeURIComponent(str))).toString('base64');
|
||||
};
|
||||
|
||||
@@ -22,21 +22,20 @@ const batchId: string =
|
||||
'mermaid-batch-' +
|
||||
(Cypress.env('useAppli')
|
||||
? Date.now().toString()
|
||||
: (Cypress.env('CYPRESS_COMMIT') ?? Date.now().toString()));
|
||||
: Cypress.env('CYPRESS_COMMIT') || Date.now().toString());
|
||||
|
||||
export const mermaidUrl = (
|
||||
graphStr: string | string[],
|
||||
options: CypressMermaidConfig,
|
||||
api: boolean
|
||||
): string => {
|
||||
options.handDrawnSeed = 1;
|
||||
const codeObject: CodeObject = {
|
||||
code: graphStr,
|
||||
mermaid: options,
|
||||
};
|
||||
const objStr: string = JSON.stringify(codeObject);
|
||||
let url = `http://localhost:9000/e2e.html?graph=${utf8ToB64(objStr)}`;
|
||||
if (api && typeof graphStr === 'string') {
|
||||
if (api) {
|
||||
url = `http://localhost:9000/xss.html?graph=${graphStr}`;
|
||||
}
|
||||
|
||||
@@ -55,13 +54,16 @@ export const imgSnapshotTest = (
|
||||
): void => {
|
||||
const options: CypressMermaidConfig = {
|
||||
..._options,
|
||||
fontFamily: _options.fontFamily ?? 'courier',
|
||||
fontFamily: _options.fontFamily || 'courier',
|
||||
// @ts-ignore TODO: Fix type of fontSize
|
||||
fontSize: _options.fontSize ?? '16px',
|
||||
fontSize: _options.fontSize || '16px',
|
||||
sequence: {
|
||||
...(_options.sequence ?? {}),
|
||||
...(_options.sequence || {}),
|
||||
actorFontFamily: 'courier',
|
||||
noteFontFamily: _options.sequence?.noteFontFamily ?? 'courier',
|
||||
noteFontFamily:
|
||||
_options.sequence && _options.sequence.noteFontFamily
|
||||
? _options.sequence.noteFontFamily
|
||||
: 'courier',
|
||||
messageFontFamily: 'courier',
|
||||
},
|
||||
};
|
||||
@@ -72,7 +74,7 @@ export const imgSnapshotTest = (
|
||||
|
||||
export const urlSnapshotTest = (
|
||||
url: string,
|
||||
options: CypressMermaidConfig = {},
|
||||
options: CypressMermaidConfig,
|
||||
_api = false,
|
||||
validation?: any
|
||||
): void => {
|
||||
@@ -93,22 +95,8 @@ export const openURLAndVerifyRendering = (
|
||||
options: CypressMermaidConfig,
|
||||
validation?: any
|
||||
): void => {
|
||||
const name: string = (options.name ?? cy.state('runnable').fullTitle()).replace(/\s+/g, '-');
|
||||
|
||||
cy.visit(url);
|
||||
cy.window().should('have.property', 'rendered', true);
|
||||
cy.get('svg').should('be.visible');
|
||||
|
||||
if (validation) {
|
||||
cy.get('svg').should(validation);
|
||||
}
|
||||
|
||||
verifyScreenshot(name);
|
||||
};
|
||||
|
||||
export const verifyScreenshot = (name: string): void => {
|
||||
const useAppli: boolean = Cypress.env('useAppli');
|
||||
const useArgos: boolean = Cypress.env('useArgos');
|
||||
const name: string = (options.name || cy.state('runnable').fullTitle()).replace(/\s+/g, '-');
|
||||
|
||||
if (useAppli) {
|
||||
cy.log(`Opening eyes ${Cypress.spec.name} --- ${name}`);
|
||||
@@ -118,22 +106,22 @@ export const verifyScreenshot = (name: string): void => {
|
||||
batchName: Cypress.spec.name,
|
||||
batchId: batchId + Cypress.spec.name,
|
||||
});
|
||||
}
|
||||
|
||||
cy.visit(url);
|
||||
cy.window().should('have.property', 'rendered', true);
|
||||
cy.get('svg').should('be.visible');
|
||||
|
||||
if (validation) {
|
||||
cy.get('svg').should(validation);
|
||||
}
|
||||
|
||||
if (useAppli) {
|
||||
cy.log(`Check eyes ${Cypress.spec.name}`);
|
||||
cy.eyesCheckWindow('Click!');
|
||||
cy.log(`Closing eyes ${Cypress.spec.name}`);
|
||||
cy.eyesClose();
|
||||
} else if (useArgos) {
|
||||
cy.argosScreenshot(name, {
|
||||
threshold: 0.01,
|
||||
});
|
||||
} else {
|
||||
cy.matchImageSnapshot(name);
|
||||
}
|
||||
};
|
||||
|
||||
export const verifyNumber = (value: number, expected: number, deltaPercent = 10): void => {
|
||||
expect(value).to.be.within(
|
||||
expected * (1 - deltaPercent / 100),
|
||||
expected * (1 + deltaPercent / 100)
|
||||
);
|
||||
};
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { renderGraph, verifyScreenshot } from '../../helpers/util.ts';
|
||||
import { renderGraph } from '../../helpers/util.ts';
|
||||
describe('Configuration', () => {
|
||||
describe('arrowMarkerAbsolute', () => {
|
||||
it('should handle default value false of arrowMarkerAbsolute', () => {
|
||||
@@ -69,9 +69,7 @@ describe('Configuration', () => {
|
||||
.and('include', 'url(#');
|
||||
});
|
||||
});
|
||||
// This has been broken for a long time, but something about the Cypress environment was
|
||||
// rewriting the URL to be relative, causing the test to incorrectly pass.
|
||||
it.skip('should handle arrowMarkerAbsolute explicitly set to "false" as false', () => {
|
||||
it('should handle arrowMarkerAbsolute explicitly set to "false" as false', () => {
|
||||
renderGraph(
|
||||
`graph TD
|
||||
A[Christmas] -->|Get money| B(Go shopping)
|
||||
@@ -114,58 +112,17 @@ describe('Configuration', () => {
|
||||
.first()
|
||||
.should('have.attr', 'marker-end')
|
||||
.should('exist')
|
||||
.and('include', 'url(http\\:\\/\\/localhost');
|
||||
.and('include', 'url(http://localhost');
|
||||
});
|
||||
});
|
||||
it('should not taint the initial configuration when using multiple directives', () => {
|
||||
const url = 'http://localhost:9000/regression/issue-1874.html';
|
||||
cy.visit(url);
|
||||
cy.window().should('have.property', 'rendered', true);
|
||||
verifyScreenshot(
|
||||
|
||||
cy.get('svg');
|
||||
cy.matchImageSnapshot(
|
||||
'configuration.spec-should-not-taint-initial-configuration-when-using-multiple-directives'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('suppressErrorRendering', () => {
|
||||
beforeEach(() => {
|
||||
cy.on('uncaught:exception', (err, runnable) => {
|
||||
return !err.message.includes('Parse error on line');
|
||||
});
|
||||
});
|
||||
|
||||
it('should not render error diagram if suppressErrorRendering is set', () => {
|
||||
const url = 'http://localhost:9000/suppressError.html?suppressErrorRendering=true';
|
||||
cy.visit(url);
|
||||
cy.window().should('have.property', 'rendered', true);
|
||||
cy.get('#test')
|
||||
.find('svg')
|
||||
.should(($svg) => {
|
||||
// all failing diagrams should not appear!
|
||||
expect($svg).to.have.length(2);
|
||||
// none of the diagrams should be error diagrams
|
||||
expect($svg).to.not.contain('Syntax error');
|
||||
});
|
||||
verifyScreenshot(
|
||||
'configuration.spec-should-not-render-error-diagram-if-suppressErrorRendering-is-set'
|
||||
);
|
||||
});
|
||||
|
||||
it('should render error diagram if suppressErrorRendering is not set', () => {
|
||||
const url = 'http://localhost:9000/suppressError.html';
|
||||
cy.visit(url);
|
||||
cy.window().should('have.property', 'rendered', true);
|
||||
cy.get('#test')
|
||||
.find('svg')
|
||||
.should(($svg) => {
|
||||
// all five diagrams should be rendered
|
||||
expect($svg).to.have.length(5);
|
||||
// some of the diagrams should be error diagrams
|
||||
expect($svg).to.contain('Syntax error');
|
||||
});
|
||||
verifyScreenshot(
|
||||
'configuration.spec-should-render-error-diagram-if-suppressErrorRendering-is-not-set'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -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');
|
||||
});
|
||||
});
|
@@ -20,7 +20,7 @@ describe('Interaction', () => {
|
||||
});
|
||||
|
||||
it('Graph: should handle a click on a node with a bound url', () => {
|
||||
// When there is a URL, `cy.contains()` selects the `a` tag instead of the `span` tag. The .node is a child of `a`, so we have to use `find()` instead of `parent`.
|
||||
// When there is a URL, cy.contains selects the a tag instead of the span. The .node is a child of a, so we have to use find instead of parent.
|
||||
cy.contains('URLTest1').find('.node').click();
|
||||
cy.location().should(({ href }) => {
|
||||
expect(href).to.eq('http://localhost:9000/empty.html');
|
||||
@@ -146,7 +146,7 @@ describe('Interaction', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Interaction - security level other, misspelling', () => {
|
||||
describe('Interaction - security level other, missspelling', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('http://localhost:9000/click_security_other.html');
|
||||
});
|
||||
|
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>');
|
||||
});
|
||||
});
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user