mirror of
				https://github.com/mermaid-js/mermaid.git
				synced 2025-10-29 18:04:09 +01:00 
			
		
		
		
	Compare commits
	
		
			207 Commits
		
	
	
		
			release/10
			...
			sidv/prior
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 5dc3850c52 | ||
|   | 927217d77c | ||
|   | 0fec0ef624 | ||
|   | b5f3cdc0b0 | ||
|   | 510549f365 | ||
|   | e8ee5f548f | ||
|   | 862d20ce9d | ||
|   | c56025ec3b | ||
|   | 6ce543e118 | ||
|   | 0c0f7a739e | ||
|   | 33e94d3f35 | ||
|   | 5fdbf5d891 | ||
|   | 6d0d8ac8e6 | ||
| ![renovate[bot]](/assets/img/avatar_default.png)  | adff22c1e2 | ||
|   | aa5d586bd6 | ||
|   | b12b8a9278 | ||
|   | 3c13386e5d | ||
|   | a177141962 | ||
|   | 92f1644550 | ||
|   | 07dcb64b22 | ||
|   | 0f2b941e2d | ||
|   | c89557d85c | ||
|   | e8ad72a980 | ||
|   | a8fe640546 | ||
|   | 01bbcc597a | ||
|   | 6fb5641afc | ||
|   | fe32bcbf7c | ||
|   | f47e920a97 | ||
|   | 1571b25d29 | ||
|   | 4a92fc5c92 | ||
|   | 8d6317b49a | ||
|   | ee49c4b660 | ||
|   | 72038a68a9 | ||
|   | 051260e9a8 | ||
|   | 3cf0a2b290 | ||
|   | adfb60e045 | ||
|   | ac595eb96c | ||
|   | 79bae62ce0 | ||
|   | 3038ce5864 | ||
|   | c8a826dfce | ||
|   | fadae38bec | ||
|   | d1fba9c567 | ||
|   | c2e26baf4d | ||
|   | f6b1e049f1 | ||
|   | 71478f5a64 | ||
|   | c9ace33cf1 | ||
|   | 30646d80f1 | ||
| ![renovate[bot]](/assets/img/avatar_default.png)  | 6e74e91b5d | ||
|   | eb4bd314b6 | ||
|   | 7a3ce3e337 | ||
|   | d1045ed644 | ||
|   | 396ea3cec2 | ||
|   | 51d076a83b | ||
|   | 65daab2aaf | ||
|   | dff8b783b8 | ||
|   | 78c1a3d980 | ||
|   | 23cbf50413 | ||
|   | 7c7f3dd8be | ||
|   | 172d90e731 | ||
|   | dff13439f6 | ||
|   | b61ea4b8aa | ||
|   | b5fd8fb7c1 | ||
|   | 4ba3e2cff3 | ||
|   | a818f3e3ae | ||
|   | 58bad981be | ||
|   | 6a5b7c40bd | ||
|   | 6e6e92a1d1 | ||
|   | f5bd1e0809 | ||
| ![renovate[bot]](/assets/img/avatar_default.png)  | 0d4faef758 | ||
|   | 0c5cf72235 | ||
|   | fff25e7e2c | ||
|   | 2a8323f951 | ||
|   | 390e22cc0b | ||
|   | a3ee21d7fc | ||
|   | 8f2a5064cb | ||
|   | 77667b94d3 | ||
|   | b85a48f7f7 | ||
|   | 34f1db399f | ||
| ![renovate[bot]](/assets/img/avatar_default.png)  | e8a04faa36 | ||
|   | d714ecb4d7 | ||
|   | 54ca3e789f | ||
|   | cb06962c85 | ||
|   | e98aa55577 | ||
|   | 672a0edc59 | ||
|   | 3394541b41 | ||
|   | 54ab3fc3b2 | ||
|   | 36a727d44e | ||
|   | 06d2ba8398 | ||
|   | 5f117fc2b2 | ||
|   | d7ec9e7b0d | ||
|   | ff4d68fd55 | ||
|   | 9637b0c187 | ||
|   | 7960f94eba | ||
|   | 3f486ac0e1 | ||
|   | b36cdaceca | ||
|   | 3b8c48dd26 | ||
|   | af73818c90 | ||
|   | 77e700832f | ||
|   | 111e067df5 | ||
|   | 880d0ebb50 | ||
|   | b268bd21e1 | ||
|   | bc247b1d46 | ||
|   | f31cddee0c | ||
|   | b232975064 | ||
|   | 3389ecdfea | ||
|   | 99a79e15f3 | ||
|   | 31ec3d1496 | ||
|   | d97e31a38c | ||
|   | f12b19216b | ||
|   | 345e82abee | ||
|   | 995449cbf6 | ||
|   | ce3d9fcdde | ||
|   | c279a9f9ed | ||
|   | cdb4639aa4 | ||
|   | 2a9eb7f123 | ||
|   | 1fec55d5f7 | ||
|   | 4559ba625c | ||
|   | 49a197eaa8 | ||
|   | 3abe7cfc45 | ||
|   | 0239e49d92 | ||
|   | 99beeba261 | ||
|   | a1673d3aca | ||
|   | 672a289909 | ||
|   | dc22189eef | ||
|   | 5f740312fe | ||
|   | 123d53c265 | ||
|   | b928e60d8b | ||
|   | 9688269027 | ||
|   | 91eb824c21 | ||
|   | 3c90894e38 | ||
|   | 271b779995 | ||
|   | 52b33f6f47 | ||
|   | 5aee43d05b | ||
|   | 7b29a380fc | ||
|   | 997c23befa | ||
|   | 4ce26296d6 | ||
|   | 4342759da7 | ||
|   | 25f2d224f1 | ||
|   | 0abb4f8c6f | ||
|   | 697ac18872 | ||
|   | fc229cf274 | ||
|   | b48136d994 | ||
|   | 77ba7c987a | ||
|   | 84f3baf013 | ||
|   | 44b93c039a | ||
|   | 4d5313699e | ||
|   | cd198290d7 | ||
|   | 60ed7d3273 | ||
|   | 9bcfba6620 | ||
|   | 7ea3c64268 | ||
|   | 2b6a34e9e0 | ||
|   | 458b90c78d | ||
|   | dd284c0986 | ||
|   | 21539dfb6a | ||
|   | 91785b8284 | ||
|   | f202770b70 | ||
|   | 8186a54962 | ||
|   | 866909b803 | ||
|   | 408910e6e8 | ||
|   | 24c8e575f4 | ||
|   | 8d0ca2c876 | ||
|   | fc96ebefd4 | ||
|   | 394330175f | ||
|   | f946c3da06 | ||
|   | 156fbd1958 | ||
|   | 7dd0d126e2 | ||
|   | 205360c109 | ||
|   | 984a0e6d06 | ||
|   | eb63568ceb | ||
|   | cc6f896b69 | ||
|   | 83e47a7216 | ||
|   | 1d64549cce | ||
|   | 4ae361bd1f | ||
|   | 6502496a2c | ||
|   | 8678ceeb3c | ||
|   | 9cb62f4d2e | ||
|   | 6c0ef54e18 | ||
|   | fd731c5ccd | ||
|   | cbe9490dc0 | ||
|   | 82054bfabc | ||
|   | 963dd75c39 | ||
|   | 1c24617f98 | ||
|   | 1559c2ca21 | ||
|   | 6141722b1f | ||
|   | 222d8eed4e | ||
|   | 718d52a72c | ||
|   | fe1a06271a | ||
|   | bd2370555b | ||
|   | 86c9ee4e90 | ||
|   | b26bcf1343 | ||
|   | 5d5c6275f9 | ||
|   | 9c1a47d1fc | ||
|   | 13852b7f4e | ||
|   | 4fd7a88a15 | ||
|   | 5c2a6b5eb1 | ||
|   | 9cbebbb8a0 | ||
|   | e26d987c4e | ||
|   | 53669efaf8 | ||
|   | b68f45ef59 | ||
|   | 8f44de651b | ||
|   | 2ede244da0 | ||
|   | 77a181978e | ||
|   | 170bbce0d3 | ||
|   | fc99d9be41 | ||
|   | 9fb9bed806 | ||
|   | 01b2f80a95 | ||
|   | da7ff777d1 | 
							
								
								
									
										30
									
								
								.build/common.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								.build/common.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| /** | ||||
|  * Shared common options for both ESBuild and Vite | ||||
|  */ | ||||
| export const packageOptions = { | ||||
|   parser: { | ||||
|     name: 'mermaid-parser', | ||||
|     packageName: 'parser', | ||||
|     file: 'index.ts', | ||||
|   }, | ||||
|   mermaid: { | ||||
|     name: 'mermaid', | ||||
|     packageName: 'mermaid', | ||||
|     file: 'mermaid.ts', | ||||
|   }, | ||||
|   'mermaid-example-diagram': { | ||||
|     name: 'mermaid-example-diagram', | ||||
|     packageName: 'mermaid-example-diagram', | ||||
|     file: 'detector.ts', | ||||
|   }, | ||||
|   'mermaid-zenuml': { | ||||
|     name: 'mermaid-zenuml', | ||||
|     packageName: 'mermaid-zenuml', | ||||
|     file: 'detector.ts', | ||||
|   }, | ||||
|   'mermaid-flowchart-elk': { | ||||
|     name: 'mermaid-flowchart-elk', | ||||
|     packageName: 'mermaid-flowchart-elk', | ||||
|     file: 'detector.ts', | ||||
|   }, | ||||
| } as const; | ||||
							
								
								
									
										5
									
								
								.build/generateLangium.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.build/generateLangium.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| import { generate } from 'langium-cli'; | ||||
|  | ||||
| export async function generateLangium() { | ||||
|   await generate({ file: `./packages/parser/langium-config.json` }); | ||||
| } | ||||
							
								
								
									
										123
									
								
								.build/jsonSchema.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								.build/jsonSchema.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,123 @@ | ||||
| import { load, JSON_SCHEMA } from 'js-yaml'; | ||||
| import assert from 'node:assert'; | ||||
| import Ajv2019, { type JSONSchemaType } from 'ajv/dist/2019.js'; | ||||
|  | ||||
| import type { MermaidConfig, BaseDiagramConfig } from '../packages/mermaid/src/config.type.js'; | ||||
|  | ||||
| /** | ||||
|  * All of the keys in the mermaid config that have a mermaid diagram config. | ||||
|  */ | ||||
| const MERMAID_CONFIG_DIAGRAM_KEYS = [ | ||||
|   'flowchart', | ||||
|   'sequence', | ||||
|   'gantt', | ||||
|   'journey', | ||||
|   'class', | ||||
|   'state', | ||||
|   'er', | ||||
|   'pie', | ||||
|   'quadrantChart', | ||||
|   'xyChart', | ||||
|   'requirement', | ||||
|   'mindmap', | ||||
|   'timeline', | ||||
|   'gitGraph', | ||||
|   'c4', | ||||
|   'sankey', | ||||
| ] 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)};`; | ||||
| }; | ||||
							
								
								
									
										9
									
								
								.build/langium-cli.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								.build/langium-cli.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| declare module 'langium-cli' { | ||||
|   export interface GenerateOptions { | ||||
|     file?: string; | ||||
|     mode?: 'development' | 'production'; | ||||
|     watch?: boolean; | ||||
|   } | ||||
|  | ||||
|   export function generate(options: GenerateOptions): Promise<boolean>; | ||||
| } | ||||
							
								
								
									
										65
									
								
								.esbuild/build.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								.esbuild/build.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,65 @@ | ||||
| import { build } from 'esbuild'; | ||||
| import { mkdir, writeFile } from 'node:fs/promises'; | ||||
| import { MermaidBuildOptions, defaultOptions, getBuildConfig } from './util.js'; | ||||
| import { packageOptions } from '../.build/common.js'; | ||||
| import { generateLangium } from '../.build/generateLangium.js'; | ||||
|  | ||||
| const shouldVisualize = process.argv.includes('--visualize'); | ||||
|  | ||||
| const buildPackage = async (entryName: keyof typeof packageOptions) => { | ||||
|   const commonOptions = { ...defaultOptions, entryName } as const; | ||||
|   const buildConfigs = [ | ||||
|     // package.mjs | ||||
|     { ...commonOptions }, | ||||
|     // package.min.mjs | ||||
|     { | ||||
|       ...commonOptions, | ||||
|       minify: true, | ||||
|       metafile: shouldVisualize, | ||||
|     }, | ||||
|     // package.core.mjs | ||||
|     { ...commonOptions, core: true }, | ||||
|   ]; | ||||
|  | ||||
|   if (entryName === 'mermaid') { | ||||
|     const iifeOptions: MermaidBuildOptions = { ...commonOptions, format: 'iife' }; | ||||
|     buildConfigs.push( | ||||
|       // mermaid.js | ||||
|       { ...iifeOptions }, | ||||
|       // mermaid.min.js | ||||
|       { ...iifeOptions, minify: true, metafile: shouldVisualize } | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   const results = await Promise.all(buildConfigs.map((option) => build(getBuildConfig(option)))); | ||||
|  | ||||
|   if (shouldVisualize) { | ||||
|     for (const { metafile } of results) { | ||||
|       if (!metafile) { | ||||
|         continue; | ||||
|       } | ||||
|       const fileName = Object.keys(metafile.outputs) | ||||
|         .filter((file) => !file.includes('chunks') && file.endsWith('js'))[0] | ||||
|         .replace('dist/', ''); | ||||
|       // Upload metafile into https://esbuild.github.io/analyze/ | ||||
|       await writeFile(`stats/${fileName}.meta.json`, JSON.stringify(metafile)); | ||||
|     } | ||||
|   } | ||||
| }; | ||||
|  | ||||
| const handler = (e) => { | ||||
|   console.error(e); | ||||
|   process.exit(1); | ||||
| }; | ||||
|  | ||||
| const main = async () => { | ||||
|   await generateLangium(); | ||||
|   await mkdir('stats').catch(() => {}); | ||||
|   const packageNames = Object.keys(packageOptions) as (keyof typeof packageOptions)[]; | ||||
|   // it should build `parser` before `mermaid` because it's a dependecy | ||||
|   for (const pkg of packageNames) { | ||||
|     await buildPackage(pkg).catch(handler); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| void main(); | ||||
							
								
								
									
										15
									
								
								.esbuild/jisonPlugin.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								.esbuild/jisonPlugin.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| import { readFile } from 'node:fs/promises'; | ||||
| import { transformJison } from '../.build/jisonTransformer.js'; | ||||
| import { Plugin } from 'esbuild'; | ||||
|  | ||||
| export const jisonPlugin: Plugin = { | ||||
|   name: 'jison', | ||||
|   setup(build) { | ||||
|     build.onLoad({ filter: /\.jison$/ }, async (args) => { | ||||
|       // Load the file from the file system | ||||
|       const source = await readFile(args.path, 'utf8'); | ||||
|       const contents = transformJison(source); | ||||
|       return { contents, warnings: [] }; | ||||
|     }); | ||||
|   }, | ||||
| }; | ||||
							
								
								
									
										35
									
								
								.esbuild/jsonSchemaPlugin.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								.esbuild/jsonSchemaPlugin.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| import type { JSONSchemaType } from 'ajv/dist/2019.js'; | ||||
| import type { MermaidConfig } from '../packages/mermaid/src/config.type.js'; | ||||
| import { readFile } from 'node:fs/promises'; | ||||
| import { getDefaults, getSchema, loadSchema } from '../.build/jsonSchema.js'; | ||||
|  | ||||
| /** | ||||
|  * ESBuild plugin that handles JSON Schemas saved as a `.schema.yaml` file. | ||||
|  * | ||||
|  * Use `my-example.schema.yaml?only-defaults=true` to only load the default values. | ||||
|  */ | ||||
|  | ||||
| export const jsonSchemaPlugin = { | ||||
|   name: 'json-schema-plugin', | ||||
|   setup(build) { | ||||
|     let schema: JSONSchemaType<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; | ||||
							
								
								
									
										116
									
								
								.esbuild/server.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								.esbuild/server.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,116 @@ | ||||
| import express from 'express'; | ||||
| import type { NextFunction, Request, Response } from 'express'; | ||||
| import cors from 'cors'; | ||||
| import { getBuildConfig, defaultOptions } from './util.js'; | ||||
| import { context } from 'esbuild'; | ||||
| import chokidar from 'chokidar'; | ||||
| import { generateLangium } from '../.build/generateLangium.js'; | ||||
| import { packageOptions } from '../.build/common.js'; | ||||
|  | ||||
| const parserCtx = await context( | ||||
|   getBuildConfig({ ...defaultOptions, minify: false, core: false, entryName: 'parser' }) | ||||
| ); | ||||
| const mermaidCtx = await context( | ||||
|   getBuildConfig({ ...defaultOptions, minify: false, core: false, entryName: 'mermaid' }) | ||||
| ); | ||||
| const mermaidIIFECtx = await context( | ||||
|   getBuildConfig({ | ||||
|     ...defaultOptions, | ||||
|     minify: false, | ||||
|     core: false, | ||||
|     entryName: 'mermaid', | ||||
|     format: 'iife', | ||||
|   }) | ||||
| ); | ||||
| const externalCtx = await context( | ||||
|   getBuildConfig({ | ||||
|     ...defaultOptions, | ||||
|     minify: false, | ||||
|     core: false, | ||||
|     entryName: 'mermaid-example-diagram', | ||||
|   }) | ||||
| ); | ||||
| const zenumlCtx = await context( | ||||
|   getBuildConfig({ ...defaultOptions, minify: false, core: false, entryName: 'mermaid-zenuml' }) | ||||
| ); | ||||
| const contexts = [parserCtx, mermaidCtx, mermaidIIFECtx, externalCtx, zenumlCtx]; | ||||
|  | ||||
| const rebuildAll = async () => { | ||||
|   console.time('Rebuild time'); | ||||
|   await Promise.all(contexts.map((ctx) => ctx.rebuild())); | ||||
|   console.timeEnd('Rebuild time'); | ||||
| }; | ||||
|  | ||||
| let clients: { id: number; response: Response }[] = []; | ||||
| function eventsHandler(request: Request, response: Response, next: NextFunction) { | ||||
|   const headers = { | ||||
|     'Content-Type': 'text/event-stream', | ||||
|     Connection: 'keep-alive', | ||||
|     'Cache-Control': 'no-cache', | ||||
|   }; | ||||
|   response.writeHead(200, headers); | ||||
|   const clientId = Date.now(); | ||||
|   clients.push({ | ||||
|     id: clientId, | ||||
|     response, | ||||
|   }); | ||||
|   request.on('close', () => { | ||||
|     clients = clients.filter((client) => client.id !== clientId); | ||||
|   }); | ||||
| } | ||||
|  | ||||
| let timeoutId: NodeJS.Timeout | undefined = undefined; | ||||
|  | ||||
| /** | ||||
|  * Debounce file change events to avoid rebuilding multiple times. | ||||
|  */ | ||||
| function handleFileChange() { | ||||
|   if (timeoutId !== undefined) { | ||||
|     clearTimeout(timeoutId); | ||||
|   } | ||||
|   timeoutId = setTimeout(async () => { | ||||
|     await rebuildAll(); | ||||
|     sendEventsToAll(); | ||||
|     timeoutId = undefined; | ||||
|   }, 100); | ||||
| } | ||||
|  | ||||
| function sendEventsToAll() { | ||||
|   clients.forEach(({ response }) => response.write(`data: ${Date.now()}\n\n`)); | ||||
| } | ||||
|  | ||||
| async function createServer() { | ||||
|   await generateLangium(); | ||||
|   handleFileChange(); | ||||
|   const app = express(); | ||||
|   chokidar | ||||
|     .watch('**/src/**/*.{js,ts,langium,yaml,json}', { | ||||
|       ignoreInitial: true, | ||||
|       ignored: [/node_modules/, /dist/, /docs/, /coverage/], | ||||
|     }) | ||||
|     .on('all', async (event, path) => { | ||||
|       // Ignore other events. | ||||
|       if (!['add', 'change'].includes(event)) { | ||||
|         return; | ||||
|       } | ||||
|       if (/\.langium$/.test(path)) { | ||||
|         await generateLangium(); | ||||
|       } | ||||
|       console.log(`${path} changed. Rebuilding...`); | ||||
|       handleFileChange(); | ||||
|     }); | ||||
|  | ||||
|   app.use(cors()); | ||||
|   app.get('/events', eventsHandler); | ||||
|   for (const { packageName } of Object.values(packageOptions)) { | ||||
|     app.use(express.static(`./packages/${packageName}/dist`)); | ||||
|   } | ||||
|   app.use(express.static('demos')); | ||||
|   app.use(express.static('cypress/platform')); | ||||
|  | ||||
|   app.listen(9000, () => { | ||||
|     console.log(`Listening on http://localhost:9000`); | ||||
|   }); | ||||
| } | ||||
|  | ||||
| createServer(); | ||||
							
								
								
									
										98
									
								
								.esbuild/util.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								.esbuild/util.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,98 @@ | ||||
| import { resolve } from 'path'; | ||||
| import { fileURLToPath } from 'url'; | ||||
| import type { BuildOptions } from 'esbuild'; | ||||
| import { readFileSync } from 'fs'; | ||||
| import jsonSchemaPlugin from './jsonSchemaPlugin.js'; | ||||
| import { packageOptions } from '../.build/common.js'; | ||||
| import { jisonPlugin } from './jisonPlugin.js'; | ||||
|  | ||||
| const __dirname = fileURLToPath(new URL('.', import.meta.url)); | ||||
|  | ||||
| export interface MermaidBuildOptions { | ||||
|   minify: boolean; | ||||
|   core: boolean; | ||||
|   metafile: boolean; | ||||
|   format: 'esm' | 'iife'; | ||||
|   entryName: keyof typeof packageOptions; | ||||
| } | ||||
|  | ||||
| export const defaultOptions: Omit<MermaidBuildOptions, 'entryName'> = { | ||||
|   minify: false, | ||||
|   metafile: false, | ||||
|   core: false, | ||||
|   format: 'esm', | ||||
| } as const; | ||||
|  | ||||
| const buildOptions = (override: BuildOptions): BuildOptions => { | ||||
|   return { | ||||
|     bundle: true, | ||||
|     minify: true, | ||||
|     keepNames: true, | ||||
|     platform: 'browser', | ||||
|     tsconfig: 'tsconfig.json', | ||||
|     resolveExtensions: ['.ts', '.js', '.json', '.jison', '.yaml'], | ||||
|     external: ['require', 'fs', 'path'], | ||||
|     outdir: 'dist', | ||||
|     plugins: [jisonPlugin, jsonSchemaPlugin], | ||||
|     sourcemap: 'external', | ||||
|     ...override, | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| const getFileName = (fileName: string, { core, format, minify }: MermaidBuildOptions) => { | ||||
|   if (core) { | ||||
|     fileName += '.core'; | ||||
|   } else if (format === 'esm') { | ||||
|     fileName += '.esm'; | ||||
|   } | ||||
|   if (minify) { | ||||
|     fileName += '.min'; | ||||
|   } | ||||
|   return fileName; | ||||
| }; | ||||
|  | ||||
| export const getBuildConfig = (options: MermaidBuildOptions): BuildOptions => { | ||||
|   const { core, entryName, metafile, format, minify } = options; | ||||
|   const external: string[] = ['require', 'fs', 'path']; | ||||
|   const { name, file, packageName } = packageOptions[entryName]; | ||||
|   const outFileName = getFileName(name, options); | ||||
|   let output: BuildOptions = buildOptions({ | ||||
|     absWorkingDir: resolve(__dirname, `../packages/${packageName}`), | ||||
|     entryPoints: { | ||||
|       [outFileName]: `src/${file}`, | ||||
|     }, | ||||
|     metafile, | ||||
|     minify, | ||||
|     logLevel: 'info', | ||||
|     chunkNames: `chunks/${outFileName}/[name]-[hash]`, | ||||
|   }); | ||||
|  | ||||
|   if (core) { | ||||
|     const { dependencies } = JSON.parse( | ||||
|       readFileSync(resolve(__dirname, `../packages/${packageName}/package.json`), 'utf-8') | ||||
|     ); | ||||
|     // Core build is used to generate file without bundled dependencies. | ||||
|     // This is used by downstream projects to bundle dependencies themselves. | ||||
|     // Ignore dependencies and any dependencies of dependencies | ||||
|     external.push(...Object.keys(dependencies)); | ||||
|     output.external = external; | ||||
|   } | ||||
|  | ||||
|   if (format === 'iife') { | ||||
|     output.format = 'iife'; | ||||
|     output.splitting = false; | ||||
|     output.globalName = '__esbuild_esm_mermaid'; | ||||
|     // Workaround for removing the .default access in esbuild IIFE. | ||||
|     // https://github.com/mermaid-js/mermaid/pull/4109#discussion_r1292317396 | ||||
|     output.footer = { | ||||
|       js: 'globalThis.mermaid = globalThis.__esbuild_esm_mermaid.default;', | ||||
|     }; | ||||
|     output.outExtension = { '.js': '.js' }; | ||||
|   } else { | ||||
|     output.format = 'esm'; | ||||
|     output.splitting = true; | ||||
|     output.outExtension = { '.js': '.mjs' }; | ||||
|   } | ||||
|  | ||||
|   return output; | ||||
| }; | ||||
| @@ -6,3 +6,6 @@ cypress/plugins/index.js | ||||
| coverage | ||||
| *.json | ||||
| node_modules | ||||
|  | ||||
| # autogenereated by langium-cli | ||||
| generated/ | ||||
|   | ||||
							
								
								
									
										26
									
								
								.github/pr-labeler.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								.github/pr-labeler.yml
									
									
									
									
										vendored
									
									
								
							| @@ -1,4 +1,22 @@ | ||||
| 'Type: Bug / Error': ['bug/*', fix/*] | ||||
| 'Type: Enhancement': ['feature/*', 'feat/*'] | ||||
| 'Type: Other': ['other/*', 'chore/*', 'test/*', 'refactor/*'] | ||||
| 'Area: Documentation': ['docs/*'] | ||||
| # yaml-language-server: $schema=https://raw.githubusercontent.com/release-drafter/release-drafter/master/schema.json | ||||
| autolabeler: | ||||
|   - label: 'Type: Bug / Error' | ||||
|     branch: | ||||
|       - '/bug\/.+/' | ||||
|       - '/fix\/.+/' | ||||
|   - label: 'Type: Enhancement' | ||||
|     branch: | ||||
|       - '/feature\/.+/' | ||||
|       - '/feat\/.+/' | ||||
|   - label: 'Type: Other' | ||||
|     branch: | ||||
|       - '/other\/.+/' | ||||
|       - '/chore\/.+/' | ||||
|       - '/test\/.+/' | ||||
|       - '/refactor\/.+/' | ||||
|   - label: 'Area: Documentation' | ||||
|     branch: | ||||
|       - '/docs\/.+/' | ||||
|  | ||||
| template: | | ||||
|   This field is unused, as we only use this config file for labeling PRs. | ||||
|   | ||||
							
								
								
									
										2
									
								
								.github/release-drafter.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/release-drafter.yml
									
									
									
									
										vendored
									
									
								
							| @@ -25,8 +25,6 @@ categories: | ||||
| change-template: '- $TITLE (#$NUMBER) @$AUTHOR' | ||||
| sort-by: title | ||||
| sort-direction: ascending | ||||
| branches: | ||||
|   - develop | ||||
| exclude-labels: | ||||
|   - 'Skip changelog' | ||||
| no-changes-template: 'This release contains minor changes and bugfixes.' | ||||
|   | ||||
							
								
								
									
										6
									
								
								.github/workflows/build-docs.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.github/workflows/build-docs.yml
									
									
									
									
										vendored
									
									
								
							| @@ -16,12 +16,12 @@ jobs: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: Checkout | ||||
|         uses: actions/checkout@v3 | ||||
|         uses: actions/checkout@v4 | ||||
|  | ||||
|       - uses: pnpm/action-setup@v2 | ||||
|  | ||||
|       - name: Setup Node.js | ||||
|         uses: actions/setup-node@v3 | ||||
|         uses: actions/setup-node@v4 | ||||
|         with: | ||||
|           cache: pnpm | ||||
|           node-version: 18 | ||||
| @@ -29,7 +29,7 @@ jobs: | ||||
|       - name: Install Packages | ||||
|         run: pnpm install --frozen-lockfile | ||||
|  | ||||
|       - name: Verify release verion | ||||
|       - name: Verify release version | ||||
|         if: ${{ github.event_name == 'push' && (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/release')) }} | ||||
|         run: pnpm --filter mermaid run docs:verify-version | ||||
|  | ||||
|   | ||||
							
								
								
									
										4
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							| @@ -19,13 +19,13 @@ jobs: | ||||
|       matrix: | ||||
|         node-version: [18.x] | ||||
|     steps: | ||||
|       - uses: actions/checkout@v3 | ||||
|       - uses: actions/checkout@v4 | ||||
|  | ||||
|       - uses: pnpm/action-setup@v2 | ||||
|         # uses version from "packageManager" field in package.json | ||||
|  | ||||
|       - name: Setup Node.js ${{ matrix.node-version }} | ||||
|         uses: actions/setup-node@v3 | ||||
|         uses: actions/setup-node@v4 | ||||
|         with: | ||||
|           cache: pnpm | ||||
|           node-version: ${{ matrix.node-version }} | ||||
|   | ||||
							
								
								
									
										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@v3 | ||||
|         uses: actions/checkout@v4 | ||||
|  | ||||
|       - name: Check for difference in README.md and docs/README.md | ||||
|         run: | | ||||
|   | ||||
							
								
								
									
										2
									
								
								.github/workflows/checks.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/checks.yml
									
									
									
									
										vendored
									
									
								
							| @@ -15,7 +15,7 @@ jobs: | ||||
|     name: check tests | ||||
|     if: github.repository_owner == 'mermaid-js' | ||||
|     steps: | ||||
|       - uses: actions/checkout@v3 | ||||
|       - uses: actions/checkout@v4 | ||||
|         with: | ||||
|           fetch-depth: 0 | ||||
|       - uses: testomatio/check-tests@stable | ||||
|   | ||||
							
								
								
									
										2
									
								
								.github/workflows/codeql.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/codeql.yml
									
									
									
									
										vendored
									
									
								
							| @@ -29,7 +29,7 @@ jobs: | ||||
|  | ||||
|     steps: | ||||
|       - name: Checkout repository | ||||
|         uses: actions/checkout@v3 | ||||
|         uses: actions/checkout@v4 | ||||
|  | ||||
|       # Initializes the CodeQL tools for scanning. | ||||
|       - name: Initialize CodeQL | ||||
|   | ||||
							
								
								
									
										4
									
								
								.github/workflows/dependency-review.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/dependency-review.yml
									
									
									
									
										vendored
									
									
								
							| @@ -1,6 +1,6 @@ | ||||
| # Dependency Review Action | ||||
| # | ||||
| # This Action will scan dependency manifest files that change as part of a Pull Reqest, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging. | ||||
| # This Action will scan dependency manifest files that change as part of a Pull Request, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging. | ||||
| # | ||||
| # Source repository: https://github.com/actions/dependency-review-action | ||||
| # Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement | ||||
| @@ -15,6 +15,6 @@ jobs: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: 'Checkout Repository' | ||||
|         uses: actions/checkout@v3 | ||||
|         uses: actions/checkout@v4 | ||||
|       - name: 'Dependency Review' | ||||
|         uses: actions/dependency-review-action@v3 | ||||
|   | ||||
							
								
								
									
										4
									
								
								.github/workflows/e2e-applitools.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/e2e-applitools.yml
									
									
									
									
										vendored
									
									
								
							| @@ -30,13 +30,13 @@ jobs: | ||||
|         run: | | ||||
|           echo "::error,title=Not using Applitols::APPLITOOLS_API_KEY is empty, disabling Applitools for this run." | ||||
|  | ||||
|       - uses: actions/checkout@v3 | ||||
|       - uses: actions/checkout@v4 | ||||
|  | ||||
|       - uses: pnpm/action-setup@v2 | ||||
|         # uses version from "packageManager" field in package.json | ||||
|  | ||||
|       - name: Setup Node.js ${{ matrix.node-version }} | ||||
|         uses: actions/setup-node@v3 | ||||
|         uses: actions/setup-node@v4 | ||||
|         with: | ||||
|           node-version: ${{ matrix.node-version }} | ||||
|  | ||||
|   | ||||
							
								
								
									
										4
									
								
								.github/workflows/e2e.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/e2e.yml
									
									
									
									
										vendored
									
									
								
							| @@ -17,13 +17,13 @@ jobs: | ||||
|         node-version: [18.x] | ||||
|         containers: [1, 2, 3, 4] | ||||
|     steps: | ||||
|       - uses: actions/checkout@v3 | ||||
|       - uses: actions/checkout@v4 | ||||
|  | ||||
|       - uses: pnpm/action-setup@v2 | ||||
|         # uses version from "packageManager" field in package.json | ||||
|  | ||||
|       - name: Setup Node.js ${{ matrix.node-version }} | ||||
|         uses: actions/setup-node@v3 | ||||
|         uses: actions/setup-node@v4 | ||||
|         with: | ||||
|           node-version: ${{ matrix.node-version }} | ||||
|  | ||||
|   | ||||
							
								
								
									
										2
									
								
								.github/workflows/link-checker.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/link-checker.yml
									
									
									
									
										vendored
									
									
								
							| @@ -26,7 +26,7 @@ jobs: | ||||
|       # lychee only uses the GITHUB_TOKEN to avoid rate-limiting | ||||
|       contents: read | ||||
|     steps: | ||||
|       - uses: actions/checkout@v3 | ||||
|       - uses: actions/checkout@v4 | ||||
|  | ||||
|       - name: Restore lychee cache | ||||
|         uses: actions/cache@v3 | ||||
|   | ||||
							
								
								
									
										4
									
								
								.github/workflows/lint.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/lint.yml
									
									
									
									
										vendored
									
									
								
							| @@ -20,13 +20,13 @@ jobs: | ||||
|       matrix: | ||||
|         node-version: [18.x] | ||||
|     steps: | ||||
|       - uses: actions/checkout@v3 | ||||
|       - uses: actions/checkout@v4 | ||||
|  | ||||
|       - uses: pnpm/action-setup@v2 | ||||
|         # uses version from "packageManager" field in package.json | ||||
|  | ||||
|       - name: Setup Node.js ${{ matrix.node-version }} | ||||
|         uses: actions/setup-node@v3 | ||||
|         uses: actions/setup-node@v4 | ||||
|         with: | ||||
|           cache: pnpm | ||||
|           node-version: ${{ matrix.node-version }} | ||||
|   | ||||
| @@ -1,23 +0,0 @@ | ||||
| name: Validate PR Labeler Configuration | ||||
| on: | ||||
|   push: | ||||
|     paths: | ||||
|       - .github/workflows/pr-labeler-config-validator.yml | ||||
|       - .github/workflows/pr-labeler.yml | ||||
|       - .github/pr-labeler.yml | ||||
|   pull_request: | ||||
|     paths: | ||||
|       - .github/workflows/pr-labeler-config-validator.yml | ||||
|       - .github/workflows/pr-labeler.yml | ||||
|       - .github/pr-labeler.yml | ||||
|  | ||||
| jobs: | ||||
|   pr-labeler: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: Checkout Repository | ||||
|         uses: actions/checkout@v3 | ||||
|       - name: Validate Configuration | ||||
|         uses: Yash-Singh1/pr-labeler-config-validator@releases/v0.0.3 | ||||
|         with: | ||||
|           configuration-path: .github/pr-labeler.yml | ||||
							
								
								
									
										22
									
								
								.github/workflows/pr-labeler.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								.github/workflows/pr-labeler.yml
									
									
									
									
										vendored
									
									
								
							| @@ -1,13 +1,31 @@ | ||||
| name: Apply labels to PR | ||||
| on: | ||||
|   pull_request_target: | ||||
|     types: [opened] | ||||
|     # required for pr-labeler to support PRs from forks | ||||
|     # ===================== ⛔ ☢️ 🚫 ⚠️ Warning ⚠️ 🚫 ☢️ ⛔ ======================= | ||||
|     # Be very careful what you put in this GitHub Action workflow file to avoid | ||||
|     # malicious PRs from getting access to the Mermaid-js repo. | ||||
|     # | ||||
|     # Please read the following first before reviewing/merging: | ||||
|     # - https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target | ||||
|     # - https://securitylab.github.com/research/github-actions-preventing-pwn-requests/ | ||||
|     types: [opened, reopened, synchronize] | ||||
|  | ||||
| permissions: | ||||
|   contents: read | ||||
|  | ||||
| jobs: | ||||
|   pr-labeler: | ||||
|     runs-on: ubuntu-latest | ||||
|     permissions: | ||||
|       contents: read # read permission is required to read config file | ||||
|       pull-requests: write # write permission is required to label PRs | ||||
|     steps: | ||||
|       - name: Label PR | ||||
|         uses: TimonVS/pr-labeler-action@v4 | ||||
|         uses: release-drafter/release-drafter@v5 | ||||
|         with: | ||||
|           config-name: pr-labeler.yml | ||||
|           disable-autolabeler: false | ||||
|           disable-releaser: true | ||||
|         env: | ||||
|           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||||
|   | ||||
							
								
								
									
										4
									
								
								.github/workflows/publish-docs.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/publish-docs.yml
									
									
									
									
										vendored
									
									
								
							| @@ -23,12 +23,12 @@ jobs: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: Checkout | ||||
|         uses: actions/checkout@v3 | ||||
|         uses: actions/checkout@v4 | ||||
|  | ||||
|       - uses: pnpm/action-setup@v2 | ||||
|  | ||||
|       - name: Setup Node.js | ||||
|         uses: actions/setup-node@v3 | ||||
|         uses: actions/setup-node@v4 | ||||
|         with: | ||||
|           cache: pnpm | ||||
|           node-version: 18 | ||||
|   | ||||
							
								
								
									
										10
									
								
								.github/workflows/release-draft.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								.github/workflows/release-draft.yml
									
									
									
									
										vendored
									
									
								
							| @@ -5,11 +5,19 @@ on: | ||||
|     branches: | ||||
|       - develop | ||||
|  | ||||
| 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: toolmantim/release-drafter@v5 | ||||
|         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@v3 | ||||
|       - uses: actions/checkout@v4 | ||||
|         with: | ||||
|           fetch-depth: 0 | ||||
|  | ||||
|       - uses: pnpm/action-setup@v2 | ||||
|  | ||||
|       - name: Setup Node.js | ||||
|         uses: actions/setup-node@v3 | ||||
|         uses: actions/setup-node@v4 | ||||
|         with: | ||||
|           cache: pnpm | ||||
|           node-version: 18.x | ||||
|   | ||||
							
								
								
									
										4
									
								
								.github/workflows/release-publish.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/release-publish.yml
									
									
									
									
										vendored
									
									
								
							| @@ -8,14 +8,14 @@ jobs: | ||||
|   publish: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - uses: actions/checkout@v3 | ||||
|       - uses: actions/checkout@v4 | ||||
|       - uses: fregante/setup-git-user@v2 | ||||
|  | ||||
|       - uses: pnpm/action-setup@v2 | ||||
|         # uses version from "packageManager" field in package.json | ||||
|  | ||||
|       - name: Setup Node.js v18 | ||||
|         uses: actions/setup-node@v3 | ||||
|         uses: actions/setup-node@v4 | ||||
|         with: | ||||
|           cache: pnpm | ||||
|           node-version: 18.x | ||||
|   | ||||
							
								
								
									
										4
									
								
								.github/workflows/test.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/test.yml
									
									
									
									
										vendored
									
									
								
							| @@ -12,13 +12,13 @@ jobs: | ||||
|       matrix: | ||||
|         node-version: [18.x] | ||||
|     steps: | ||||
|       - uses: actions/checkout@v3 | ||||
|       - uses: actions/checkout@v4 | ||||
|  | ||||
|       - uses: pnpm/action-setup@v2 | ||||
|         # uses version from "packageManager" field in package.json | ||||
|  | ||||
|       - name: Setup Node.js ${{ matrix.node-version }} | ||||
|         uses: actions/setup-node@v3 | ||||
|         uses: actions/setup-node@v4 | ||||
|         with: | ||||
|           cache: pnpm | ||||
|           node-version: ${{ matrix.node-version }} | ||||
|   | ||||
							
								
								
									
										2
									
								
								.github/workflows/update-browserlist.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/update-browserlist.yml
									
									
									
									
										vendored
									
									
								
							| @@ -8,7 +8,7 @@ jobs: | ||||
|   update-browser-list: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - uses: actions/checkout@v3 | ||||
|       - uses: actions/checkout@v4 | ||||
|       - run: npx browserslist@latest --update-db | ||||
|       - name: Commit changes | ||||
|         uses: EndBug/add-and-commit@v9 | ||||
|   | ||||
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -46,3 +46,7 @@ stats/ | ||||
|  | ||||
| demos/dev/** | ||||
| !/demos/dev/example.html | ||||
| !/demos/dev/reload.js | ||||
|  | ||||
| # autogenereated by langium-cli | ||||
| generated/ | ||||
|   | ||||
| @@ -10,3 +10,6 @@ stats | ||||
| .nyc_output | ||||
| # Autogenerated by `pnpm run --filter mermaid types:build-config` | ||||
| packages/mermaid/src/config.type.ts | ||||
|  | ||||
| # autogenereated by langium-cli | ||||
| generated/ | ||||
|   | ||||
| @@ -3,11 +3,12 @@ import { resolve } from 'path'; | ||||
| import { fileURLToPath } from 'url'; | ||||
| import jisonPlugin from './jisonPlugin.js'; | ||||
| import jsonSchemaPlugin from './jsonSchemaPlugin.js'; | ||||
| import { readFileSync } from 'fs'; | ||||
| import typescript from '@rollup/plugin-typescript'; | ||||
| import { visualizer } from 'rollup-plugin-visualizer'; | ||||
| import type { TemplateType } from 'rollup-plugin-visualizer/dist/plugin/template-types.js'; | ||||
| import istanbul from 'vite-plugin-istanbul'; | ||||
| import { packageOptions } from '../.build/common.js'; | ||||
| import { generateLangium } from '../.build/generateLangium.js'; | ||||
|  | ||||
| const visualize = process.argv.includes('--visualize'); | ||||
| const watch = process.argv.includes('--watch'); | ||||
| @@ -36,24 +37,6 @@ const visualizerOptions = (packageName: string, core = false): PluginOption[] => | ||||
|   ); | ||||
| }; | ||||
|  | ||||
| const packageOptions = { | ||||
|   mermaid: { | ||||
|     name: 'mermaid', | ||||
|     packageName: 'mermaid', | ||||
|     file: 'mermaid.ts', | ||||
|   }, | ||||
|   'mermaid-example-diagram': { | ||||
|     name: 'mermaid-example-diagram', | ||||
|     packageName: 'mermaid-example-diagram', | ||||
|     file: 'detector.ts', | ||||
|   }, | ||||
|   'mermaid-zenuml': { | ||||
|     name: 'mermaid-zenuml', | ||||
|     packageName: 'mermaid-zenuml', | ||||
|     file: 'detector.ts', | ||||
|   }, | ||||
| }; | ||||
|  | ||||
| interface BuildOptions { | ||||
|   minify: boolean | 'esbuild'; | ||||
|   core?: boolean; | ||||
| @@ -72,34 +55,8 @@ export const getBuildConfig = ({ minify, core, watch, entryName }: BuildOptions) | ||||
|       sourcemap, | ||||
|       entryFileNames: `${name}.esm${minify ? '.min' : ''}.mjs`, | ||||
|     }, | ||||
|     { | ||||
|       name, | ||||
|       format: 'umd', | ||||
|       sourcemap, | ||||
|       entryFileNames: `${name}${minify ? '.min' : ''}.js`, | ||||
|     }, | ||||
|   ]; | ||||
|  | ||||
|   if (core) { | ||||
|     const { dependencies } = JSON.parse( | ||||
|       readFileSync(resolve(__dirname, `../packages/${packageName}/package.json`), 'utf-8') | ||||
|     ); | ||||
|     // Core build is used to generate file without bundled dependencies. | ||||
|     // This is used by downstream projects to bundle dependencies themselves. | ||||
|     // Ignore dependencies and any dependencies of dependencies | ||||
|     // Adapted from the RegEx used by `rollup-plugin-node` | ||||
|     external.push(new RegExp('^(?:' + Object.keys(dependencies).join('|') + ')(?:/.+)?$')); | ||||
|     // This needs to be an array. Otherwise vite will build esm & umd with same name and overwrite esm with umd. | ||||
|     output = [ | ||||
|       { | ||||
|         name, | ||||
|         format: 'esm', | ||||
|         sourcemap, | ||||
|         entryFileNames: `${name}.core.mjs`, | ||||
|       }, | ||||
|     ]; | ||||
|   } | ||||
|  | ||||
|   const config: InlineConfig = { | ||||
|     configFile: false, | ||||
|     build: { | ||||
| @@ -126,7 +83,7 @@ export const getBuildConfig = ({ minify, core, watch, entryName }: BuildOptions) | ||||
|       // @ts-expect-error According to the type definitions, rollup plugins are incompatible with vite | ||||
|       typescript({ compilerOptions: { declaration: false } }), | ||||
|       istanbul({ | ||||
|         exclude: ['node_modules', 'test/', '__mocks__'], | ||||
|         exclude: ['node_modules', 'test/', '__mocks__', 'generated'], | ||||
|         extension: ['.js', '.ts'], | ||||
|         requireEnv: true, | ||||
|         forceBuildInstrument: coverage, | ||||
| @@ -146,24 +103,28 @@ export const getBuildConfig = ({ minify, core, watch, entryName }: BuildOptions) | ||||
|  | ||||
| const buildPackage = async (entryName: keyof typeof packageOptions) => { | ||||
|   await build(getBuildConfig({ minify: false, entryName })); | ||||
|   await build(getBuildConfig({ minify: 'esbuild', entryName })); | ||||
|   await build(getBuildConfig({ minify: false, core: true, entryName })); | ||||
| }; | ||||
|  | ||||
| const main = async () => { | ||||
|   const packageNames = Object.keys(packageOptions) as (keyof typeof packageOptions)[]; | ||||
|   for (const pkg of packageNames.filter((pkg) => !mermaidOnly || pkg === 'mermaid')) { | ||||
|   for (const pkg of packageNames.filter( | ||||
|     (pkg) => !mermaidOnly || pkg === 'mermaid' || pkg === 'parser' | ||||
|   )) { | ||||
|     await buildPackage(pkg); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| await generateLangium(); | ||||
|  | ||||
| if (watch) { | ||||
|   await build(getBuildConfig({ minify: false, watch, core: false, entryName: 'parser' })); | ||||
|   build(getBuildConfig({ minify: false, watch, core: false, entryName: 'mermaid' })); | ||||
|   if (!mermaidOnly) { | ||||
|     build(getBuildConfig({ minify: false, watch, entryName: 'mermaid-example-diagram' })); | ||||
|     build(getBuildConfig({ minify: false, watch, entryName: 'mermaid-zenuml' })); | ||||
|   } | ||||
| } else if (visualize) { | ||||
|   await build(getBuildConfig({ minify: false, watch, core: false, entryName: 'parser' })); | ||||
|   await build(getBuildConfig({ minify: false, core: true, entryName: 'mermaid' })); | ||||
|   await build(getBuildConfig({ minify: false, core: false, entryName: 'mermaid' })); | ||||
| } else { | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| import { transformJison } from './jisonTransformer.js'; | ||||
| import { transformJison } from '../.build/jisonTransformer.js'; | ||||
|  | ||||
| const fileRegex = /\.(jison)$/; | ||||
|  | ||||
| export default function jison() { | ||||
|   return { | ||||
|     name: 'jison', | ||||
|  | ||||
|     transform(src: string, id: string) { | ||||
|       if (fileRegex.test(id)) { | ||||
|         return { | ||||
|   | ||||
| @@ -1,109 +1,5 @@ | ||||
| import { load, JSON_SCHEMA } from 'js-yaml'; | ||||
| import assert from 'node:assert'; | ||||
| import Ajv2019, { type JSONSchemaType } from 'ajv/dist/2019.js'; | ||||
| import { PluginOption } from 'vite'; | ||||
|  | ||||
| import type { MermaidConfig, BaseDiagramConfig } from '../packages/mermaid/src/config.type.js'; | ||||
|  | ||||
| /** | ||||
|  * All of the keys in the mermaid config that have a mermaid diagram config. | ||||
|  */ | ||||
| const MERMAID_CONFIG_DIAGRAM_KEYS = [ | ||||
|   'flowchart', | ||||
|   'sequence', | ||||
|   'gantt', | ||||
|   'journey', | ||||
|   'class', | ||||
|   'state', | ||||
|   'er', | ||||
|   'pie', | ||||
|   'quadrantChart', | ||||
|   'xyChart', | ||||
|   'requirement', | ||||
|   'mindmap', | ||||
|   'timeline', | ||||
|   'gitGraph', | ||||
|   'c4', | ||||
|   'sankey', | ||||
| ] as const; | ||||
|  | ||||
| /** | ||||
|  * Generate default values from the JSON Schema. | ||||
|  * | ||||
|  * AJV does not support nested default values yet (or default values with $ref), | ||||
|  * so we need to manually find them (this may be fixed in ajv v9). | ||||
|  * | ||||
|  * @param mermaidConfigSchema - The Mermaid JSON Schema to use. | ||||
|  * @returns The default mermaid config object. | ||||
|  */ | ||||
| function generateDefaults(mermaidConfigSchema: JSONSchemaType<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; | ||||
| } | ||||
| import { getDefaults, getSchema, loadSchema } from '../.build/jsonSchema.js'; | ||||
|  | ||||
| /** | ||||
|  * Vite plugin that handles JSON Schemas saved as a `.schema.yaml` file. | ||||
| @@ -120,32 +16,13 @@ export default function jsonSchemaPlugin(): PluginOption { | ||||
|         return; | ||||
|       } | ||||
|  | ||||
|       if (idAsUrl.searchParams.get('only-defaults')) { | ||||
|         const jsonSchema = load(src, { | ||||
|           filename: idAsUrl.pathname, | ||||
|           // only allow JSON types in our YAML doc (will probably be default in YAML 1.3) | ||||
|           // e.g. `true` will be parsed a boolean `true`, `True` will be parsed as string `"True"`. | ||||
|           schema: JSON_SCHEMA, | ||||
|         }) as JSONSchemaType<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 | ||||
|         }; | ||||
|       } | ||||
|       const jsonSchema = loadSchema(src, idAsUrl.pathname); | ||||
|       return { | ||||
|         code: idAsUrl.searchParams.get('only-defaults') | ||||
|           ? getDefaults(jsonSchema) | ||||
|           : getSchema(jsonSchema), | ||||
|         map: null, // no source map | ||||
|       }; | ||||
|     }, | ||||
|   }; | ||||
| } | ||||
|   | ||||
| @@ -14,6 +14,7 @@ async function createServer() { | ||||
|   }); | ||||
|  | ||||
|   app.use(cors()); | ||||
|   app.use(express.static('./packages/parser/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')); | ||||
|   | ||||
							
								
								
									
										18
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								README.md
									
									
									
									
									
								
							| @@ -44,6 +44,22 @@ Try Live Editor previews of future releases: <a href="https://develop.git.mermai | ||||
|  | ||||
| <a href="https://mermaid-js.github.io/mermaid/landing/"><img src="https://github.com/mermaid-js/mermaid/blob/master/docs/intro/img/book-banner-post-release.jpg" alt="Explore Mermaid.js in depth, with real-world examples, tips & tricks from the creator... The first official book on Mermaid is available for purchase. Check it out!"></a> | ||||
|  | ||||
| ## Table of content | ||||
|  | ||||
| <details> | ||||
| <summary>Expand contents</summary> | ||||
|  | ||||
| - [About](#about) | ||||
| - [Examples](#examples) | ||||
| - [Release](#release) | ||||
| - [Related projects](#related-projects) | ||||
| - [Contributors](#contributors) | ||||
| - [Security and safe diagrams](#security-and-safe-diagrams) | ||||
| - [Reporting vulnerabilities](#reporting-vulnerabilities) | ||||
| - [Appreciation](#appreciation) | ||||
|  | ||||
| </details> | ||||
|  | ||||
| ## About | ||||
|  | ||||
| <!-- <Main description>   --> | ||||
| @@ -58,7 +74,7 @@ Mermaid addresses this problem by enabling users to create easily modifiable dia | ||||
| <br/> | ||||
|  | ||||
| Mermaid allows even non-programmers to easily create detailed diagrams through the [Mermaid Live Editor](https://mermaid.live/).<br/> | ||||
| [Tutorials](./docs/config/Tutorials.md) has video tutorials. | ||||
| For video tutorials, visit our [Tutorials](./docs/config/Tutorials.md) page. | ||||
| Use Mermaid with your favorite applications, check out the list of [Integrations and Usages of Mermaid](./docs/ecosystem/integrations-community.md). | ||||
|  | ||||
| You can also use Mermaid within [GitHub](https://github.blog/2022-02-14-include-diagrams-markdown-files-mermaid/) as well many of your other favorite applications—check out the list of [Integrations and Usages of Mermaid](./docs/ecosystem/integrations-community.md). | ||||
|   | ||||
| @@ -61,6 +61,7 @@ | ||||
|     "gzipped", | ||||
|     "huynh", | ||||
|     "huynhicode", | ||||
|     "iife", | ||||
|     "inkdrop", | ||||
|     "jaoude", | ||||
|     "jgreywolf", | ||||
| @@ -74,6 +75,7 @@ | ||||
|     "knut", | ||||
|     "knutsveidqvist", | ||||
|     "laganeckas", | ||||
|     "langium", | ||||
|     "linetype", | ||||
|     "lintstagedrc", | ||||
|     "logmsg", | ||||
| @@ -85,6 +87,7 @@ | ||||
|     "mdbook", | ||||
|     "mermaidjs", | ||||
|     "mermerd", | ||||
|     "metafile", | ||||
|     "mindaugas", | ||||
|     "mindmap", | ||||
|     "mindmaps", | ||||
| @@ -98,6 +101,7 @@ | ||||
|     "nirname", | ||||
|     "npmjs", | ||||
|     "orlandoni", | ||||
|     "outdir", | ||||
|     "pathe", | ||||
|     "pbrolin", | ||||
|     "phpbb", | ||||
|   | ||||
							
								
								
									
										11
									
								
								cypress/integration/other/iife.spec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								cypress/integration/other/iife.spec.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| describe('IIFE', () => { | ||||
|   beforeEach(() => { | ||||
|     cy.visit('http://localhost:9000/iife.html'); | ||||
|   }); | ||||
|  | ||||
|   it('should render when using mermaid.min.js', () => { | ||||
|     cy.window().should('have.property', 'rendered', true); | ||||
|     cy.get('svg').should('be.visible'); | ||||
|     cy.get('#d2').should('contain', 'Hello'); | ||||
|   }); | ||||
| }); | ||||
| @@ -1,16 +0,0 @@ | ||||
| describe('Sequencediagram', () => { | ||||
|   it('should render a simple sequence diagrams', () => { | ||||
|     const url = 'http://localhost:9000/webpackUsage.html'; | ||||
|  | ||||
|     cy.visit(url); | ||||
|     cy.get('body').find('svg').should('have.length', 1); | ||||
|   }); | ||||
|   it('should handle html escapings properly', () => { | ||||
|     const url = 'http://localhost:9000/webpackUsage.html?test-html-escaping=true'; | ||||
|  | ||||
|     cy.visit(url); | ||||
|     cy.get('body').find('svg').should('have.length', 1); | ||||
|  | ||||
|     cy.get('g.label > foreignobject > div').should('not.contain.text', '<b>'); | ||||
|   }); | ||||
| }); | ||||
| @@ -501,4 +501,16 @@ describe('Class diagram', () => { | ||||
|         B : -methods() | ||||
|       `); | ||||
|   }); | ||||
|  | ||||
|   it('should handle notes with anchor tag having target attribute', () => { | ||||
|     renderGraph( | ||||
|       `classDiagram | ||||
|         class test { } | ||||
|         note for test "<a href='https://mermaid.js.org/' target="_blank"><code>note about mermaid</code></a>"` | ||||
|     ); | ||||
|  | ||||
|     cy.get('svg').then((svg) => { | ||||
|       cy.get('a').should('have.attr', 'target', '_blank').should('have.attr', 'rel', 'noopener'); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| <html> | ||||
|   <head> | ||||
|     <meta charset="utf-8" /> | ||||
|     <script src="./viewer.js" type="module"></script> | ||||
|     <script type="module" src="./viewer.js"></script> | ||||
|     <link | ||||
|       href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap" | ||||
|       rel="stylesheet" | ||||
|   | ||||
| @@ -11,8 +11,7 @@ example-diagram | ||||
|     <!-- <script src="//cdn.jsdelivr.net/npm/mermaid@9.1.7/dist/mermaid.min.js"></script> --> | ||||
|     <!-- <script type="module" src="./external-diagrams-mindmap.mjs" /> --> | ||||
|     <script type="module"> | ||||
|       import exampleDiagram from '../../packages/mermaid-example-diagram/dist/mermaid-example-diagram.core.mjs'; | ||||
|       // import example from '../../packages/mermaid-example-diagram/src/detector'; | ||||
|       import exampleDiagram from './mermaid-example-diagram.esm.mjs'; | ||||
|       import mermaid from './mermaid.esm.mjs'; | ||||
|  | ||||
|       await mermaid.registerExternalDiagrams([exampleDiagram]); | ||||
|   | ||||
							
								
								
									
										29
									
								
								cypress/platform/iife.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								cypress/platform/iife.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| <html> | ||||
|   <body> | ||||
|     <pre id="diagram" class="mermaid"> | ||||
| graph TB | ||||
|       a --> b | ||||
|       a --> c | ||||
|       b --> d | ||||
|       c --> d | ||||
|     </pre> | ||||
|  | ||||
|     <div id="d2"></div> | ||||
|  | ||||
|     <script src="/mermaid.min.js"></script> | ||||
|     <script> | ||||
|       mermaid.initialize({ | ||||
|         startOnLoad: true, | ||||
|       }); | ||||
|       const value = `graph TD\nHello --> World`; | ||||
|       const el = document.getElementById('d2'); | ||||
|       mermaid.render('did', value).then(({ svg }) => { | ||||
|         console.log(svg); | ||||
|         el.innerHTML = svg; | ||||
|         if (window.Cypress) { | ||||
|           window.rendered = true; | ||||
|         } | ||||
|       }); | ||||
|     </script> | ||||
|   </body> | ||||
| </html> | ||||
| @@ -17,20 +17,20 @@ | ||||
|     graph TB | ||||
|       Function-->URL | ||||
|       click Function clickByFlow "Add a div" | ||||
|       click URL "http://localhost:9000/webpackUsage.html" "Visit <strong>mermaid docs</strong>" | ||||
|       click URL "http://localhost:9000/info.html" "Visit <strong>mermaid docs</strong>" | ||||
|       </pre> | ||||
|       <pre id="FirstLine" class="mermaid2"> | ||||
|   graph TB | ||||
|     1Function-->2URL | ||||
|     click 1Function clickByFlow "Add a div" | ||||
|     click 2URL "http://localhost:9000/webpackUsage.html" "Visit <strong>mermaid docs</strong>" | ||||
|     click 2URL "http://localhost:9000/info.html" "Visit <strong>mermaid docs</strong>" | ||||
|       </pre> | ||||
|  | ||||
|       <pre id="FirstLine" class="mermaid2"> | ||||
|   classDiagram | ||||
|     class Test | ||||
|     class ShapeLink | ||||
|     link ShapeLink "http://localhost:9000/webpackUsage.html" "This is a tooltip for a link" | ||||
|     link ShapeLink "http://localhost:9000/info.html" "This is a tooltip for a link" | ||||
|     class ShapeCallback | ||||
|     callback ShapeCallback "clickByClass" "This is a tooltip for a callback" | ||||
|       </pre> | ||||
| @@ -42,7 +42,7 @@ | ||||
|       <pre id="FirstLine" class="mermaid"> | ||||
|   classDiagram-v2 | ||||
|     class ShapeLink | ||||
|     link ShapeLink "http://localhost:9000/webpackUsage.html" "This is a tooltip for a link" | ||||
|     link ShapeLink "http://localhost:9000/info.html" "This is a tooltip for a link" | ||||
|       </pre> | ||||
|     </div> | ||||
|  | ||||
| @@ -77,7 +77,7 @@ | ||||
|     Calling a Callback (look at the console log) :cl2, after cl1, 3d | ||||
|     Calling a Callback with args :cl3, after cl1, 3d | ||||
|  | ||||
|     click cl1 href "http://localhost:9000/webpackUsage.html" | ||||
|     click cl1 href "http://localhost:9000/info.html" | ||||
|     click cl2 call clickByGantt() | ||||
|     click cl3 call clickByGantt("test1", test2, test3) | ||||
|  | ||||
| @@ -102,9 +102,15 @@ | ||||
|         div.className = 'created-by-gant-click'; | ||||
|         div.style = 'padding: 20px; background: green; color: white;'; | ||||
|         div.innerText = 'Clicked By Gant'; | ||||
|         if (arg1) div.innerText += ' ' + arg1; | ||||
|         if (arg2) div.innerText += ' ' + arg2; | ||||
|         if (arg3) div.innerText += ' ' + arg3; | ||||
|         if (arg1) { | ||||
|           div.innerText += ' ' + arg1; | ||||
|         } | ||||
|         if (arg2) { | ||||
|           div.innerText += ' ' + arg2; | ||||
|         } | ||||
|         if (arg3) { | ||||
|           div.innerText += ' ' + arg3; | ||||
|         } | ||||
|  | ||||
|         document.getElementsByTagName('body')[0].appendChild(div); | ||||
|       } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import mermaid2 from './mermaid.esm.mjs'; | ||||
| import externalExample from '../../packages/mermaid-example-diagram/dist/mermaid-example-diagram.core.mjs'; | ||||
| import zenUml from '../../packages/mermaid-zenuml/dist/mermaid-zenuml.core.mjs'; | ||||
| import mermaid from './mermaid.esm.mjs'; | ||||
| import externalExample from './mermaid-example-diagram.esm.mjs'; | ||||
| import zenUml from './mermaid-zenuml.esm.mjs'; | ||||
|  | ||||
| function b64ToUtf8(str) { | ||||
|   return decodeURIComponent(escape(window.atob(str))); | ||||
| @@ -45,9 +45,9 @@ const contentLoaded = async function () { | ||||
|       document.getElementsByTagName('body')[0].appendChild(div); | ||||
|     } | ||||
|  | ||||
|     await mermaid2.registerExternalDiagrams([externalExample, zenUml]); | ||||
|     mermaid2.initialize(graphObj.mermaid); | ||||
|     await mermaid2.run(); | ||||
|     await mermaid.registerExternalDiagrams([externalExample, zenUml]); | ||||
|     mermaid.initialize(graphObj.mermaid); | ||||
|     await mermaid.run(); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| @@ -95,18 +95,14 @@ const contentLoadedApi = async function () { | ||||
|         divs[i] = div; | ||||
|       } | ||||
|  | ||||
|       const defaultE2eCnf = { theme: 'forest' }; | ||||
|       const defaultE2eCnf = { theme: 'forest', startOnLoad: false }; | ||||
|  | ||||
|       const cnf = merge(defaultE2eCnf, graphObj.mermaid); | ||||
|  | ||||
|       mermaid2.initialize(cnf); | ||||
|       mermaid.initialize(cnf); | ||||
|  | ||||
|       for (let i = 0; i < numCodes; i++) { | ||||
|         const { svg, bindFunctions } = await mermaid2.render( | ||||
|           'newid' + i, | ||||
|           graphObj.code[i], | ||||
|           divs[i] | ||||
|         ); | ||||
|         const { svg, bindFunctions } = await mermaid.render('newid' + i, graphObj.code[i], divs[i]); | ||||
|         div.innerHTML = svg; | ||||
|         bindFunctions(div); | ||||
|       } | ||||
| @@ -114,18 +110,21 @@ const contentLoadedApi = async function () { | ||||
|       const div = document.createElement('div'); | ||||
|       div.id = 'block'; | ||||
|       div.className = 'mermaid'; | ||||
|       console.warn('graphObj.mermaid', graphObj.mermaid); | ||||
|       console.warn('graphObj', graphObj); | ||||
|       document.getElementsByTagName('body')[0].appendChild(div); | ||||
|       mermaid2.initialize(graphObj.mermaid); | ||||
|  | ||||
|       const { svg, bindFunctions } = await mermaid2.render('newid', graphObj.code, div); | ||||
|       mermaid.initialize(graphObj.mermaid); | ||||
|       const { svg, bindFunctions } = await mermaid.render('newid', graphObj.code, div); | ||||
|       div.innerHTML = svg; | ||||
|       console.log(div.innerHTML); | ||||
|       bindFunctions(div); | ||||
|     } | ||||
|   } | ||||
| }; | ||||
|  | ||||
| if (typeof document !== 'undefined') { | ||||
|   mermaid.initialize({ | ||||
|     startOnLoad: false, | ||||
|   }); | ||||
|   /*! | ||||
|    * Wait for document loaded before starting the execution | ||||
|    */ | ||||
|   | ||||
| @@ -1,19 +0,0 @@ | ||||
| <!DOCTYPE html> | ||||
| <html> | ||||
|   <head> | ||||
|     <style> | ||||
|       /* .mermaid { | ||||
|     font-family: "trebuchet ms", verdana, arial;; | ||||
|   } */ | ||||
|       /* .mermaid { | ||||
|     font-family: 'arial'; | ||||
|   } */ | ||||
|     </style> | ||||
|   </head> | ||||
|   <body> | ||||
|     <div id="graph-to-be"></div> | ||||
|     <script type="module" charset="utf-8"> | ||||
|       import './bundle-test.js'; | ||||
|     </script> | ||||
|   </body> | ||||
| </html> | ||||
| @@ -1,6 +1,5 @@ | ||||
| <html> | ||||
|   <head> | ||||
|     <script src="./viewer.js" type="module"></script> | ||||
|     <link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" /> | ||||
|     <style> | ||||
|       .malware { | ||||
| @@ -33,12 +32,6 @@ | ||||
|     </script> | ||||
|   </head> | ||||
|   <body> | ||||
|     <script type="module"> | ||||
|       import mermaid from './mermaid.esm.mjs'; | ||||
|       mermaid.initialize({ | ||||
|         startOnLoad: false, | ||||
|         useMaxWidth: true, | ||||
|       }); | ||||
|     </script> | ||||
|     <script type="module" src="./viewer.js"></script> | ||||
|   </body> | ||||
| </html> | ||||
|   | ||||
| @@ -5,6 +5,8 @@ | ||||
|     <title>Mermaid development page</title> | ||||
|   </head> | ||||
|   <body> | ||||
|     <pre class="mermaid">info</pre> | ||||
|  | ||||
|     <pre id="diagram" class="mermaid"> | ||||
| graph TB | ||||
|       a --> b | ||||
| @@ -30,5 +32,7 @@ graph TB | ||||
|       console.log(svg); | ||||
|       el.innerHTML = svg; | ||||
|     </script> | ||||
|  | ||||
|     <script src="/dev/reload.js"></script> | ||||
|   </body> | ||||
| </html> | ||||
|   | ||||
							
								
								
									
										22
									
								
								demos/dev/reload.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								demos/dev/reload.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| // Connect to the server and reload the page if the server sends a reload message | ||||
| const connectToEvents = () => { | ||||
|   const events = new EventSource('/events'); | ||||
|   const loadTime = Date.now(); | ||||
|   events.onmessage = (event) => { | ||||
|     const time = JSON.parse(event.data); | ||||
|     if (time && time > loadTime) { | ||||
|       location.reload(); | ||||
|     } | ||||
|   }; | ||||
|   events.onerror = (error) => { | ||||
|     console.error(error); | ||||
|     events.close(); | ||||
|     // Try to reconnect after 1 second in case of errors | ||||
|     setTimeout(connectToEvents, 1000); | ||||
|   }; | ||||
|   events.onopen = () => { | ||||
|     console.log('Connected to live reload server'); | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| setTimeout(connectToEvents, 500); | ||||
							
								
								
									
										35
									
								
								demos/flowchart-elk.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								demos/flowchart-elk.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| <!DOCTYPE html> | ||||
| <html lang="en"> | ||||
|   <head> | ||||
|     <meta charset="utf-8" /> | ||||
|     <meta http-equiv="X-UA-Compatible" content="IE=edge" /> | ||||
|     <title>Mermaid Flowchart ELK Test Page</title> | ||||
|   </head> | ||||
|  | ||||
|   <body> | ||||
|     <h1>Flowchart ELK</h1> | ||||
|     <pre class="mermaid"> | ||||
| 		flowchart-elk TD | ||||
|       A([Start]) ==> B[Step 1] | ||||
|       B ==> C{Flow 1} | ||||
|       C -- Choice 1.1 --> D[Step 2.1] | ||||
|       C -- Choice 1.3 --> I[Step 2.3] | ||||
|       C == Choice 1.2 ==> E[Step 2.2] | ||||
|       D --> F{Flow 2} | ||||
|       E ==> F{Flow 2} | ||||
|       F{Flow 2} == Choice 2.1 ==> H[Feedback node] | ||||
|       H[Feedback node] ==> B[Step 1] | ||||
|       F{Flow 2} == Choice 2.2 ==> G((Finish)) | ||||
|        | ||||
|     </pre> | ||||
|  | ||||
|     <script type="module"> | ||||
|       import mermaid from './mermaid.esm.mjs'; | ||||
|       import flowchartELK from './mermaid-flowchart-elk.esm.mjs'; | ||||
|       await mermaid.registerExternalDiagrams([flowchartELK]); | ||||
|       mermaid.initialize({ | ||||
|         logLevel: 3, | ||||
|       }); | ||||
|     </script> | ||||
|   </body> | ||||
| </html> | ||||
| @@ -37,7 +37,7 @@ | ||||
|     </pre> | ||||
|  | ||||
|     <script type="module"> | ||||
|       import mermaid from './mermaid.esm.mjs'; | ||||
|       import mermaid from '/mermaid.esm.mjs'; | ||||
|       mermaid.initialize({ | ||||
|         theme: 'forest', | ||||
|         logLevel: 3, | ||||
|   | ||||
| @@ -164,6 +164,13 @@ | ||||
|       end | ||||
|     </pre> | ||||
|  | ||||
|     <pre class="mermaid"> | ||||
|     sequenceDiagram | ||||
|       actor Alice | ||||
|       actor John | ||||
|       Alice-xJohn: Hello John, how are you? | ||||
|       John--xAlice: Great! | ||||
|     </pre> | ||||
|     <script type="module"> | ||||
|       import mermaid from './mermaid.esm.mjs'; | ||||
|       mermaid.initialize({ | ||||
|   | ||||
| @@ -10,9 +10,8 @@ | ||||
|  | ||||
| ## First search to see if someone has already asked (and hopefully been answered) or suggested the same thing. | ||||
|  | ||||
| - Search in Discussions | ||||
| - Search in open Issues | ||||
| - Search in closed Issues | ||||
| - [Search in Discussions](https://github.com/orgs/mermaid-js/discussions) | ||||
| - [Search in Issues (Open & Closed)](https://github.com/mermaid-js/mermaid/issues?q=is%3Aissue) | ||||
|  | ||||
| If you find an open issue or discussion thread that is similar to your question but isn't answered, you can let us know that you are also interested in it. | ||||
| Use the GitHub reactions to add a thumbs-up to the issue or discussion thread. | ||||
|   | ||||
| @@ -10,8 +10,8 @@ When mermaid starts, configuration is extracted to determine a configuration to | ||||
|  | ||||
| - The default configuration | ||||
| - Overrides at the site level are set by the initialize call, and will be applied to all diagrams in the site/app. The term for this is the **siteConfig**. | ||||
| - Frontmatter (v10.5.0+) - diagram authors can update select configuration parameters in the frontmatter of the diagram. These are applied to the render config. | ||||
| - Directives (Deprecated by Frontmatter) - diagram authors can update select configuration parameters directly in the diagram code via directives. These are applied to the render config. | ||||
| - Frontmatter (v10.5.0+) - diagram authors can update selected configuration parameters in the frontmatter of the diagram. These are applied to the render config. | ||||
| - Directives (Deprecated by Frontmatter) - diagram authors can update selected configuration parameters directly in the diagram code via directives. These are applied to the render config. | ||||
|  | ||||
| **The render config** is configuration that is used when rendering by applying these configurations. | ||||
|  | ||||
|   | ||||
| @@ -16,4 +16,4 @@ | ||||
|  | ||||
| #### Defined in | ||||
|  | ||||
| [mermaidAPI.ts:59](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L59) | ||||
| [mermaidAPI.ts:60](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L60) | ||||
|   | ||||
| @@ -39,7 +39,7 @@ bindFunctions?.(div); // To call bindFunctions only if it's present. | ||||
|  | ||||
| #### Defined in | ||||
|  | ||||
| [mermaidAPI.ts:79](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L79) | ||||
| [mermaidAPI.ts:80](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L80) | ||||
|  | ||||
| --- | ||||
|  | ||||
| @@ -51,4 +51,4 @@ The svg code for the rendered graph. | ||||
|  | ||||
| #### Defined in | ||||
|  | ||||
| [mermaidAPI.ts:69](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L69) | ||||
| [mermaidAPI.ts:70](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L70) | ||||
|   | ||||
| @@ -25,7 +25,7 @@ Renames and re-exports [mermaidAPI](mermaidAPI.md#mermaidapi) | ||||
|  | ||||
| #### Defined in | ||||
|  | ||||
| [mermaidAPI.ts:63](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L63) | ||||
| [mermaidAPI.ts:64](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L64) | ||||
|  | ||||
| ## Variables | ||||
|  | ||||
| @@ -96,7 +96,7 @@ mermaid.initialize(config); | ||||
|  | ||||
| #### Defined in | ||||
|  | ||||
| [mermaidAPI.ts:641](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L641) | ||||
| [mermaidAPI.ts:603](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L603) | ||||
|  | ||||
| ## Functions | ||||
|  | ||||
| @@ -127,7 +127,7 @@ Return the last node appended | ||||
|  | ||||
| #### Defined in | ||||
|  | ||||
| [mermaidAPI.ts:299](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L299) | ||||
| [mermaidAPI.ts:263](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L263) | ||||
|  | ||||
| --- | ||||
|  | ||||
| @@ -153,7 +153,7 @@ the cleaned up svgCode | ||||
|  | ||||
| #### Defined in | ||||
|  | ||||
| [mermaidAPI.ts:245](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L245) | ||||
| [mermaidAPI.ts:209](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L209) | ||||
|  | ||||
| --- | ||||
|  | ||||
| @@ -178,7 +178,7 @@ the string with all the user styles | ||||
|  | ||||
| #### Defined in | ||||
|  | ||||
| [mermaidAPI.ts:175](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L175) | ||||
| [mermaidAPI.ts:139](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L139) | ||||
|  | ||||
| --- | ||||
|  | ||||
| @@ -201,7 +201,7 @@ the string with all the user styles | ||||
|  | ||||
| #### Defined in | ||||
|  | ||||
| [mermaidAPI.ts:222](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L222) | ||||
| [mermaidAPI.ts:186](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L186) | ||||
|  | ||||
| --- | ||||
|  | ||||
| @@ -228,47 +228,7 @@ with an enclosing block that has each of the cssClasses followed by !important; | ||||
|  | ||||
| #### Defined in | ||||
|  | ||||
| [mermaidAPI.ts:160](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L160) | ||||
|  | ||||
| --- | ||||
|  | ||||
| ### decodeEntities | ||||
|  | ||||
| ▸ **decodeEntities**(`text`): `string` | ||||
|  | ||||
| #### Parameters | ||||
|  | ||||
| | Name   | Type     | Description        | | ||||
| | :----- | :------- | :----------------- | | ||||
| | `text` | `string` | text to be decoded | | ||||
|  | ||||
| #### Returns | ||||
|  | ||||
| `string` | ||||
|  | ||||
| #### Defined in | ||||
|  | ||||
| [mermaidAPI.ts:146](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L146) | ||||
|  | ||||
| --- | ||||
|  | ||||
| ### encodeEntities | ||||
|  | ||||
| ▸ **encodeEntities**(`text`): `string` | ||||
|  | ||||
| #### Parameters | ||||
|  | ||||
| | Name   | Type     | Description        | | ||||
| | :----- | :------- | :----------------- | | ||||
| | `text` | `string` | text to be encoded | | ||||
|  | ||||
| #### Returns | ||||
|  | ||||
| `string` | ||||
|  | ||||
| #### Defined in | ||||
|  | ||||
| [mermaidAPI.ts:117](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L117) | ||||
| [mermaidAPI.ts:124](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L124) | ||||
|  | ||||
| --- | ||||
|  | ||||
| @@ -294,7 +254,7 @@ Put the svgCode into an iFrame. Return the iFrame code | ||||
|  | ||||
| #### Defined in | ||||
|  | ||||
| [mermaidAPI.ts:276](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L276) | ||||
| [mermaidAPI.ts:240](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L240) | ||||
|  | ||||
| --- | ||||
|  | ||||
| @@ -319,4 +279,4 @@ Remove any existing elements from the given document | ||||
|  | ||||
| #### Defined in | ||||
|  | ||||
| [mermaidAPI.ts:349](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L349) | ||||
| [mermaidAPI.ts:313](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L313) | ||||
|   | ||||
| @@ -64,7 +64,7 @@ Example: | ||||
|  | ||||
| ```html | ||||
| <script type="module"> | ||||
|   import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; | ||||
|   import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs'; | ||||
| </script> | ||||
| ``` | ||||
|  | ||||
| @@ -83,7 +83,7 @@ Example: | ||||
|       B-->D(fa:fa-spinner); | ||||
|     </pre> | ||||
|     <script type="module"> | ||||
|       import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; | ||||
|       import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs'; | ||||
|     </script> | ||||
|   </body> | ||||
| </html> | ||||
|   | ||||
| @@ -35,12 +35,19 @@ Below are a list of community plugins and integrations created with Mermaid. | ||||
| - [Notion](https://notion.so) ✅ | ||||
| - [Observable](https://observablehq.com/@observablehq/mermaid) ✅ | ||||
| - [Obsidian](https://help.obsidian.md/Editing+and+formatting/Advanced+formatting+syntax#Diagram) ✅ | ||||
| - [NotesHub](https://noteshub.app) ✅ | ||||
| - [GitBook](https://gitbook.com) | ||||
|   - [Mermaid Plugin](https://github.com/JozoVilcek/gitbook-plugin-mermaid) | ||||
|   - [Markdown with Mermaid CLI](https://github.com/miao1007/gitbook-plugin-mermaid-cli) | ||||
|   - [Mermaid plugin for GitBook](https://github.com/wwformat/gitbook-plugin-mermaid-pdf) | ||||
| - [LiveBook](https://livebook.dev) ✅ | ||||
| - [Atlassian Products](https://www.atlassian.com) | ||||
|   - [Mermaid for Confluence](https://marketplace.atlassian.com/apps/1224722/mermaid-for-confluence?hosting=cloud&tab=overview) | ||||
|   - [Mermaid Integration for Confluence](https://marketplace.atlassian.com/apps/1222792/mermaid-integration-for-confluence?hosting=cloud&tab=overview) | ||||
|   - [Mermaid Diagrams for Confluence](https://marketplace.atlassian.com/apps/1226945/mermaid-diagrams-for-confluence?hosting=cloud&tab=overview) | ||||
|   - [Mermaid Macro for Confluence](https://marketplace.atlassian.com/apps/1231150/mermaid-macro-for-confluence?hosting=cloud&tab=overview) | ||||
|   - [EliteSoft Mermaid Charts and Diagrams](https://marketplace.atlassian.com/apps/1227286/elitesoft-mermaid-charts-and-diagrams?hosting=cloud&tab=overview) | ||||
|   - [Mermaid for Jira Cloud - Draw UML diagrams easily](https://marketplace.atlassian.com/apps/1223053/mermaid-for-jira-cloud-draw-uml-diagrams-easily?hosting=cloud&tab=overview) | ||||
|   - [Mermaid Charts & Diagrams for Confluence](https://marketplace.atlassian.com/apps/1222572/) | ||||
|   - [Mermaid Charts & Diagrams for Jira](https://marketplace.atlassian.com/apps/1224537/) | ||||
|   - [Mermaid Live Editor for Confluence Cloud](https://marketplace.atlassian.com/apps/1231571/mermaid-live-editor-for-confluence?hosting=cloud&tab=overview) | ||||
| @@ -99,6 +106,8 @@ Communication tools and platforms | ||||
|   - [phpbb-ext-mermaid](https://github.com/AlfredoRamos/phpbb-ext-mermaid) | ||||
| - [NodeBB](https://nodebb.org) | ||||
|   - [Mermaid Plugin](https://www.npmjs.com/package/nodebb-plugin-mermaid) | ||||
| - [Slack](https://slack.com) | ||||
|   - [Mermaid for Slack](https://github.com/JackuB/mermaid-for-slack) | ||||
|  | ||||
| ### Wikis | ||||
|  | ||||
| @@ -169,6 +178,7 @@ Communication tools and platforms | ||||
|  | ||||
| ### Document Generation | ||||
|  | ||||
| - [Docusaurus](https://docusaurus.io/docs/markdown-features/diagrams) ✅ | ||||
| - [Swimm - Up-to-date diagrams with Swimm, the knowledge management tool for code](https://docs.swimm.io/Features/diagrams-and-charts) | ||||
| - [Sphinx](https://www.sphinx-doc.org/en/master/) | ||||
|   - [sphinxcontrib-mermaid](https://github.com/mgaitan/sphinxcontrib-mermaid) | ||||
|   | ||||
| @@ -128,7 +128,7 @@ b. The importing of mermaid library through the `mermaid.esm.mjs` or `mermaid.es | ||||
| ```html | ||||
| <body> | ||||
|   <script type="module"> | ||||
|     import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; | ||||
|     import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs'; | ||||
|     mermaid.initialize({ startOnLoad: true }); | ||||
|   </script> | ||||
| </body> | ||||
| @@ -168,7 +168,7 @@ Rendering in Mermaid is initialized by `mermaid.initialize()` call. However, doi | ||||
|     </pre> | ||||
|  | ||||
|     <script type="module"> | ||||
|       import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; | ||||
|       import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs'; | ||||
|       mermaid.initialize({ startOnLoad: true }); | ||||
|     </script> | ||||
|   </body> | ||||
|   | ||||
| @@ -317,7 +317,7 @@ To select a version: | ||||
|  | ||||
| Replace `<version>` with the desired version number. | ||||
|  | ||||
| Latest Version: <https://cdn.jsdelivr.net/npm/mermaid@10> | ||||
| Latest Version: <https://cdn.jsdelivr.net/npm/mermaid@11> | ||||
|  | ||||
| ## Deploying Mermaid | ||||
|  | ||||
| @@ -335,12 +335,12 @@ To Deploy Mermaid: | ||||
|  | ||||
| ```html | ||||
| <script type="module"> | ||||
|   import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; | ||||
|   import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs'; | ||||
|   mermaid.initialize({ startOnLoad: true }); | ||||
| </script> | ||||
| ``` | ||||
|  | ||||
| **Doing so commands the mermaid parser to look for the `<div>` or `<pre>` tags with `class="mermaid"`. From these tags, mermaid tries read the diagram/chart definitions and render them into SVG charts.** | ||||
| **Doing so commands the mermaid parser to look for the `<div>` or `<pre>` tags with `class="mermaid"`. From these tags, mermaid tries to read the diagram/chart definitions and render them into SVG charts.** | ||||
|  | ||||
| **Examples can be found in** [Other examples](../syntax/examples.md) | ||||
|  | ||||
|   | ||||
| @@ -399,7 +399,7 @@ UpdateRelStyle(customerA, bankA, $offsetY="60") | ||||
|     title Component diagram for Internet Banking System - API Application | ||||
|  | ||||
|     Container(spa, "Single Page Application", "javascript and angular", "Provides all the internet banking functionality to customers via their web browser.") | ||||
|     Container(ma, "Mobile App", "Xamarin", "Provides a limited subset ot the internet banking functionality to customers via their mobile mobile device.") | ||||
|     Container(ma, "Mobile App", "Xamarin", "Provides a limited subset to the internet banking functionality to customers via their mobile mobile device.") | ||||
|     ContainerDb(db, "Database", "Relational Database Schema", "Stores user registration information, hashed authentication credentials, access logs, etc.") | ||||
|     System_Ext(mbs, "Mainframe Banking System", "Stores all of the core banking information about customers, accounts, transactions, etc.") | ||||
|  | ||||
| @@ -439,7 +439,7 @@ UpdateRelStyle(customerA, bankA, $offsetY="60") | ||||
|     title Component diagram for Internet Banking System - API Application | ||||
|  | ||||
|     Container(spa, "Single Page Application", "javascript and angular", "Provides all the internet banking functionality to customers via their web browser.") | ||||
|     Container(ma, "Mobile App", "Xamarin", "Provides a limited subset ot the internet banking functionality to customers via their mobile mobile device.") | ||||
|     Container(ma, "Mobile App", "Xamarin", "Provides a limited subset to the internet banking functionality to customers via their mobile mobile device.") | ||||
|     ContainerDb(db, "Database", "Relational Database Schema", "Stores user registration information, hashed authentication credentials, access logs, etc.") | ||||
|     System_Ext(mbs, "Mainframe Banking System", "Stores all of the core banking information about customers, accounts, transactions, etc.") | ||||
|  | ||||
|   | ||||
| @@ -425,8 +425,6 @@ And `Link` can be one of: | ||||
|  | ||||
| A namespace groups classes. | ||||
|  | ||||
| Code: | ||||
|  | ||||
| ```mermaid-example | ||||
| classDiagram | ||||
| namespace BaseShapes { | ||||
|   | ||||
| @@ -467,7 +467,7 @@ flowchart TB | ||||
|     A & B--> C & D | ||||
| ``` | ||||
|  | ||||
| If you describe the same diagram using the the basic syntax, it will take four lines. A | ||||
| If you describe the same diagram using the basic syntax, it will take four lines. A | ||||
| word of warning, one could go overboard with this making the flowchart harder to read in | ||||
| markdown form. The Swedish word `lagom` comes to mind. It means, not too much and not too little. | ||||
| This goes for expressive syntaxes as well. | ||||
|   | ||||
| @@ -300,7 +300,7 @@ From version 9.4.0 you can simplify this code to: | ||||
|  | ||||
| ```html | ||||
| <script type="module"> | ||||
|   import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; | ||||
|   import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs'; | ||||
| </script> | ||||
| ``` | ||||
|  | ||||
|   | ||||
| @@ -469,7 +469,7 @@ You can use this method to add mermaid including the timeline diagram to a web p | ||||
|  | ||||
| ```html | ||||
| <script type="module"> | ||||
|   import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; | ||||
|   import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs'; | ||||
| </script> | ||||
| ``` | ||||
|  | ||||
|   | ||||
							
								
								
									
										22
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								package.json
									
									
									
									
									
								
							| @@ -4,7 +4,7 @@ | ||||
|   "version": "10.2.4", | ||||
|   "description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.", | ||||
|   "type": "module", | ||||
|   "packageManager": "pnpm@8.9.2", | ||||
|   "packageManager": "pnpm@8.10.4", | ||||
|   "keywords": [ | ||||
|     "diagram", | ||||
|     "markdown", | ||||
| @@ -15,15 +15,15 @@ | ||||
|     "git graph" | ||||
|   ], | ||||
|   "scripts": { | ||||
|     "build:vite": "ts-node-esm --transpileOnly .vite/build.ts", | ||||
|     "build:mermaid": "pnpm build:vite --mermaid", | ||||
|     "build:viz": "pnpm build:mermaid --visualize", | ||||
|     "build:types": "tsc -p ./packages/mermaid/tsconfig.json --emitDeclarationOnly && tsc -p ./packages/mermaid-zenuml/tsconfig.json --emitDeclarationOnly && tsc -p ./packages/mermaid-example-diagram/tsconfig.json --emitDeclarationOnly", | ||||
|     "build": "pnpm build:esbuild && pnpm build:types", | ||||
|     "build:esbuild": "pnpm run -r clean && ts-node-esm --transpileOnly .esbuild/build.ts", | ||||
|     "build:mermaid": "pnpm build:esbuild --mermaid", | ||||
|     "build:viz": "pnpm build:esbuild --visualize", | ||||
|     "build:types": "tsc -p ./packages/parser/tsconfig.json --emitDeclarationOnly && tsc -p ./packages/mermaid/tsconfig.json --emitDeclarationOnly && tsc -p ./packages/mermaid-zenuml/tsconfig.json --emitDeclarationOnly && tsc -p ./packages/mermaid-example-diagram/tsconfig.json --emitDeclarationOnly && tsc -p ./packages/mermaid-flowchart-elk/tsconfig.json --emitDeclarationOnly", | ||||
|     "build:types:watch": "tsc -p ./packages/mermaid/tsconfig.json --emitDeclarationOnly --watch", | ||||
|     "build:watch": "pnpm build:vite --watch", | ||||
|     "build": "pnpm run -r clean && pnpm build:types && pnpm build:vite", | ||||
|     "dev": "concurrently \"pnpm build:vite --watch\" \"ts-node-esm .vite/server.ts\"", | ||||
|     "dev:coverage": "pnpm coverage:cypress:clean && VITE_COVERAGE=true pnpm dev", | ||||
|     "dev": "ts-node-esm --transpileOnly .esbuild/server.ts", | ||||
|     "dev:vite": "ts-node-esm --transpileOnly .vite/server.ts", | ||||
|     "dev:coverage": "pnpm coverage:cypress:clean && VITE_COVERAGE=true pnpm dev:vite", | ||||
|     "release": "pnpm build", | ||||
|     "lint": "eslint --cache --cache-strategy content --ignore-path .gitignore . && pnpm lint:jison && prettier --cache --check .", | ||||
|     "lint:fix": "eslint --cache --cache-strategy content --fix --ignore-path .gitignore . && prettier --write . && ts-node-esm scripts/fixCSpell.ts", | ||||
| @@ -32,8 +32,8 @@ | ||||
|     "cypress": "cypress run", | ||||
|     "cypress:open": "cypress open", | ||||
|     "e2e": "start-server-and-test dev http://localhost:9000/ cypress", | ||||
|     "e2e:coverage": "start-server-and-test dev:coverage http://localhost:9000/ cypress", | ||||
|     "coverage:cypress:clean": "rimraf .nyc_output coverage/cypress", | ||||
|     "e2e:coverage": "pnpm coverage:cypress:clean && VITE_COVERAGE=true pnpm e2e", | ||||
|     "coverage:merge": "ts-node-esm scripts/coverage.ts", | ||||
|     "coverage": "pnpm test:coverage --run && pnpm e2e:coverage && pnpm coverage:merge", | ||||
|     "ci": "vitest run", | ||||
| @@ -83,6 +83,7 @@ | ||||
|     "@vitest/spy": "^0.34.0", | ||||
|     "@vitest/ui": "^0.34.0", | ||||
|     "ajv": "^8.12.0", | ||||
|     "chokidar": "^3.5.3", | ||||
|     "concurrently": "^8.0.1", | ||||
|     "cors": "^2.8.5", | ||||
|     "cypress": "^12.10.0", | ||||
| @@ -107,6 +108,7 @@ | ||||
|     "jison": "^0.4.18", | ||||
|     "js-yaml": "^4.1.0", | ||||
|     "jsdom": "^22.0.0", | ||||
|     "langium-cli": "2.0.1", | ||||
|     "lint-staged": "^13.2.1", | ||||
|     "nyc": "^15.1.0", | ||||
|     "path-browserify": "^1.0.1", | ||||
|   | ||||
| @@ -43,8 +43,7 @@ | ||||
|     "cytoscape-cose-bilkent": "^4.1.0", | ||||
|     "cytoscape-fcose": "^2.1.0", | ||||
|     "d3": "^7.0.0", | ||||
|     "khroma": "^2.0.0", | ||||
|     "non-layered-tidy-tree-layout": "^2.0.2" | ||||
|     "khroma": "^2.0.0" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@types/cytoscape": "^3.19.9", | ||||
|   | ||||
							
								
								
									
										55
									
								
								packages/mermaid-flowchart-elk/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								packages/mermaid-flowchart-elk/package.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | ||||
| { | ||||
|   "name": "@mermaid-js/flowchart-elk", | ||||
|   "version": "1.0.0", | ||||
|   "description": "Flowchart plugin for mermaid with ELK layout", | ||||
|   "module": "dist/mermaid-flowchart-elk.core.mjs", | ||||
|   "types": "dist/packages/mermaid-flowchart-elk/src/detector.d.ts", | ||||
|   "type": "module", | ||||
|   "exports": { | ||||
|     ".": { | ||||
|       "import": "./dist/mermaid-flowchart-elk.core.mjs", | ||||
|       "types": "./dist/packages/mermaid-flowchart-elk/src/detector.d.ts" | ||||
|     }, | ||||
|     "./*": "./*" | ||||
|   }, | ||||
|   "keywords": [ | ||||
|     "diagram", | ||||
|     "markdown", | ||||
|     "flowchart", | ||||
|     "elk", | ||||
|     "mermaid" | ||||
|   ], | ||||
|   "scripts": { | ||||
|     "prepublishOnly": "pnpm -w run build" | ||||
|   }, | ||||
|   "repository": { | ||||
|     "type": "git", | ||||
|     "url": "https://github.com/mermaid-js/mermaid" | ||||
|   }, | ||||
|   "author": "Knut Sveidqvist", | ||||
|   "license": "MIT", | ||||
|   "standard": { | ||||
|     "ignore": [ | ||||
|       "**/parser/*.js", | ||||
|       "dist/**/*.js", | ||||
|       "cypress/**/*.js" | ||||
|     ], | ||||
|     "globals": [ | ||||
|       "page" | ||||
|     ] | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "d3": "^7.4.0", | ||||
|     "dagre-d3-es": "7.0.10", | ||||
|     "khroma": "^2.0.0", | ||||
|     "elkjs": "^0.8.2" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "concurrently": "^8.0.0", | ||||
|     "rimraf": "^5.0.0", | ||||
|     "mermaid": "workspace:*" | ||||
|   }, | ||||
|   "files": [ | ||||
|     "dist" | ||||
|   ] | ||||
| } | ||||
							
								
								
									
										32
									
								
								packages/mermaid-flowchart-elk/src/detector.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								packages/mermaid-flowchart-elk/src/detector.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| import type { | ||||
|   ExternalDiagramDefinition, | ||||
|   DiagramDetector, | ||||
|   DiagramLoader, | ||||
| } from '../../mermaid/src/diagram-api/types.js'; | ||||
|  | ||||
| const id = 'flowchart-elk'; | ||||
|  | ||||
| const detector: DiagramDetector = (txt, config): boolean => { | ||||
|   if ( | ||||
|     // If diagram explicitly states flowchart-elk | ||||
|     /^\s*flowchart-elk/.test(txt) || | ||||
|     // If a flowchart/graph diagram has their default renderer set to elk | ||||
|     (/^\s*flowchart|graph/.test(txt) && config?.flowchart?.defaultRenderer === 'elk') | ||||
|   ) { | ||||
|     return true; | ||||
|   } | ||||
|   return false; | ||||
| }; | ||||
|  | ||||
| const loader: DiagramLoader = async () => { | ||||
|   const { diagram } = await import('./diagram-definition.js'); | ||||
|   return { id, diagram }; | ||||
| }; | ||||
|  | ||||
| const plugin: ExternalDiagramDefinition = { | ||||
|   id, | ||||
|   detector, | ||||
|   loader, | ||||
| }; | ||||
|  | ||||
| export default plugin; | ||||
							
								
								
									
										12
									
								
								packages/mermaid-flowchart-elk/src/diagram-definition.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								packages/mermaid-flowchart-elk/src/diagram-definition.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| // @ts-ignore: JISON typing missing | ||||
| import parser from '../../mermaid/src/diagrams/flowchart/parser/flow.jison'; | ||||
| import * as db from '../../mermaid/src/diagrams/flowchart/flowDb.js'; | ||||
| import styles from '../../mermaid/src/diagrams/flowchart/styles.js'; | ||||
| import renderer from './flowRenderer-elk.js'; | ||||
|  | ||||
| export const diagram = { | ||||
|   db, | ||||
|   renderer, | ||||
|   parser, | ||||
|   styles, | ||||
| }; | ||||
| @@ -1,16 +1,16 @@ | ||||
| import { select, line, curveLinear } from 'd3'; | ||||
| import { insertNode } from '../../../dagre-wrapper/nodes.js'; | ||||
| import insertMarkers from '../../../dagre-wrapper/markers.js'; | ||||
| import { insertEdgeLabel } from '../../../dagre-wrapper/edges.js'; | ||||
| import { insertNode } from '../../mermaid/src/dagre-wrapper/nodes.js'; | ||||
| import insertMarkers from '../../mermaid/src/dagre-wrapper/markers.js'; | ||||
| import { insertEdgeLabel } from '../../mermaid/src/dagre-wrapper/edges.js'; | ||||
| import { findCommonAncestor } from './render-utils.js'; | ||||
| import { labelHelper } from '../../../dagre-wrapper/shapes/util.js'; | ||||
| import { getConfig } from '../../../config.js'; | ||||
| import { log } from '../../../logger.js'; | ||||
| import { setupGraphViewbox } from '../../../setupGraphViewbox.js'; | ||||
| import common from '../../common/common.js'; | ||||
| import { interpolateToCurve, getStylesFromArray } from '../../../utils.js'; | ||||
| import { labelHelper } from '../../mermaid/src/dagre-wrapper/shapes/util.js'; | ||||
| import { getConfig } from '../../mermaid/src/config.js'; | ||||
| import { log } from '../../mermaid/src/logger.js'; | ||||
| import { setupGraphViewbox } from '../../mermaid/src/setupGraphViewbox.js'; | ||||
| import common from '../../mermaid/src/diagrams/common/common.js'; | ||||
| import { interpolateToCurve, getStylesFromArray } from '../../mermaid/src/utils.js'; | ||||
| import ELK from 'elkjs/lib/elk.bundled.js'; | ||||
| import { getLineFunctionsWithOffset } from '../../../utils/lineWithOffset.js'; | ||||
| import { getLineFunctionsWithOffset } from '../../mermaid/src/utils/lineWithOffset.js'; | ||||
| 
 | ||||
| const elk = new ELK(); | ||||
| 
 | ||||
| @@ -695,7 +695,7 @@ const addMarkersToEdge = function (svgPath, edgeData, diagramType, arrowMarkerAb | ||||
|  * | ||||
|  * @param text | ||||
|  * @param diagObj | ||||
|  * @returns {Record<string, import('../../../diagram-api/types.js').DiagramStyleClassDef>} ClassDef styles | ||||
|  * @returns {Record<string, import('../../mermaid/src/diagram-api/types.js').DiagramStyleClassDef>} ClassDef styles | ||||
|  */ | ||||
| export const getClasses = function (text, diagObj) { | ||||
|   log.info('Extracting classes'); | ||||
							
								
								
									
										9
									
								
								packages/mermaid-flowchart-elk/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								packages/mermaid-flowchart-elk/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| { | ||||
|   "extends": "../../tsconfig.json", | ||||
|   "compilerOptions": { | ||||
|     "rootDir": "../..", | ||||
|     "outDir": "./dist" | ||||
|   }, | ||||
|   "include": ["./src/**/*.ts"], | ||||
|   "typeRoots": ["./src/types"] | ||||
| } | ||||
| @@ -19,6 +19,7 @@ | ||||
|     "mermaid" | ||||
|   ], | ||||
|   "scripts": { | ||||
|     "clean": "rimraf dist", | ||||
|     "prepublishOnly": "pnpm -w run build" | ||||
|   }, | ||||
|   "repository": { | ||||
|   | ||||
| @@ -5,7 +5,6 @@ | ||||
|  * This is a dummy parser that satisfies the mermaid API logic. | ||||
|  */ | ||||
| export default { | ||||
|   parser: { yy: {} }, | ||||
|   parse: () => { | ||||
|     // no op | ||||
|   }, | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|   "name": "mermaid", | ||||
|   "version": "10.6.0", | ||||
|   "version": "11.0.0-alpha.2", | ||||
|   "description": "Markdown-ish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.", | ||||
|   "type": "module", | ||||
|   "module": "./dist/mermaid.core.mjs", | ||||
| @@ -60,8 +60,6 @@ | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "@braintree/sanitize-url": "^6.0.1", | ||||
|     "@types/d3-scale": "^4.0.3", | ||||
|     "@types/d3-scale-chromatic": "^3.0.0", | ||||
|     "cytoscape": "^3.23.0", | ||||
|     "cytoscape-cose-bilkent": "^4.1.0", | ||||
|     "cytoscape-fcose": "^2.1.0", | ||||
| @@ -70,15 +68,13 @@ | ||||
|     "dagre-d3-es": "7.0.10", | ||||
|     "dayjs": "^1.11.7", | ||||
|     "dompurify": "^3.0.5", | ||||
|     "elkjs": "^0.8.2", | ||||
|     "khroma": "^2.0.0", | ||||
|     "lodash-es": "^4.17.21", | ||||
|     "mdast-util-from-markdown": "^1.3.0", | ||||
|     "non-layered-tidy-tree-layout": "^2.0.2", | ||||
|     "mermaid-parser": "workspace:^", | ||||
|     "stylis": "^4.1.3", | ||||
|     "ts-dedent": "^2.2.0", | ||||
|     "uuid": "^9.0.0", | ||||
|     "web-worker": "^1.2.0" | ||||
|     "uuid": "^9.0.0" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@adobe/jsonschema2md": "^7.1.4", | ||||
| @@ -86,6 +82,7 @@ | ||||
|     "@types/d3": "^7.4.0", | ||||
|     "@types/d3-sankey": "^0.12.1", | ||||
|     "@types/d3-scale": "^4.0.3", | ||||
|     "@types/d3-scale-chromatic": "^3.0.0", | ||||
|     "@types/d3-selection": "^3.0.5", | ||||
|     "@types/d3-shape": "^3.1.1", | ||||
|     "@types/dompurify": "^3.0.2", | ||||
|   | ||||
| @@ -1,8 +1,10 @@ | ||||
| import * as configApi from './config.js'; | ||||
| import { log } from './logger.js'; | ||||
| import { getDiagram, registerDiagram } from './diagram-api/diagramAPI.js'; | ||||
| import { detectType, getDiagramLoader } from './diagram-api/detectType.js'; | ||||
| import { detectType, getDiagramLoaderAndPriority } from './diagram-api/detectType.js'; | ||||
| import { UnknownDiagramError } from './errors.js'; | ||||
| import { encodeEntities } from './utils.js'; | ||||
|  | ||||
| import type { DetailedError } from './utils.js'; | ||||
| import type { DiagramDefinition, DiagramMetadata } from './diagram-api/types.js'; | ||||
|  | ||||
| @@ -21,6 +23,7 @@ export class Diagram { | ||||
|  | ||||
|   private detectError?: UnknownDiagramError; | ||||
|   constructor(public text: string, public metadata: Pick<DiagramMetadata, 'title'> = {}) { | ||||
|     this.text = encodeEntities(text); | ||||
|     this.text += '\n'; | ||||
|     const cnf = configApi.getConfig(); | ||||
|     try { | ||||
| @@ -35,7 +38,10 @@ export class Diagram { | ||||
|     this.db = diagram.db; | ||||
|     this.renderer = diagram.renderer; | ||||
|     this.parser = diagram.parser; | ||||
|     this.parser.parser.yy = this.db; | ||||
|     if (this.parser.parser) { | ||||
|       // The parser.parser.yy is only present in JISON parsers. So, we'll only set if required. | ||||
|       this.parser.parser.yy = this.db; | ||||
|     } | ||||
|     this.init = diagram.init; | ||||
|     this.parse(); | ||||
|   } | ||||
| @@ -86,14 +92,14 @@ export const getDiagramFromText = async ( | ||||
|     // Trying to find the diagram | ||||
|     getDiagram(type); | ||||
|   } catch (error) { | ||||
|     const loader = getDiagramLoader(type); | ||||
|     const { loader, priority } = getDiagramLoaderAndPriority(type); | ||||
|     if (!loader) { | ||||
|       throw new UnknownDiagramError(`Diagram ${type} not found.`); | ||||
|     } | ||||
|     // Diagram not available, loading it. | ||||
|     // new diagram will try getDiagram again and if fails then it is a valid throw | ||||
|     const { id, diagram } = await loader(); | ||||
|     registerDiagram(id, diagram); | ||||
|     registerDiagram(id, diagram, priority); | ||||
|   } | ||||
|   return new Diagram(text, metadata); | ||||
| }; | ||||
|   | ||||
| @@ -61,7 +61,7 @@ export interface MermaidConfig { | ||||
|    * You may also use `themeCSS` to override this value. | ||||
|    * | ||||
|    */ | ||||
|   theme?: string | 'default' | 'forest' | 'dark' | 'neutral' | 'null'; | ||||
|   theme?: 'default' | 'forest' | 'dark' | 'neutral' | 'null'; | ||||
|   themeVariables?: any; | ||||
|   themeCSS?: string; | ||||
|   /** | ||||
| @@ -82,26 +82,11 @@ export interface MermaidConfig { | ||||
|    * This option decides the amount of logging to be used by mermaid. | ||||
|    * | ||||
|    */ | ||||
|   logLevel?: | ||||
|     | number | ||||
|     | string | ||||
|     | 0 | ||||
|     | 2 | ||||
|     | 1 | ||||
|     | 'trace' | ||||
|     | 'debug' | ||||
|     | 'info' | ||||
|     | 'warn' | ||||
|     | 'error' | ||||
|     | 'fatal' | ||||
|     | 3 | ||||
|     | 4 | ||||
|     | 5 | ||||
|     | undefined; | ||||
|   logLevel?: 'trace' | 0 | 'debug' | 1 | 'info' | 2 | 'warn' | 3 | 'error' | 4 | 'fatal' | 5; | ||||
|   /** | ||||
|    * Level of trust for parsed diagram | ||||
|    */ | ||||
|   securityLevel?: string | 'strict' | 'loose' | 'antiscript' | 'sandbox' | undefined; | ||||
|   securityLevel?: 'strict' | 'loose' | 'antiscript' | 'sandbox'; | ||||
|   /** | ||||
|    * Dictates whether mermaid starts on Page load | ||||
|    */ | ||||
| @@ -912,7 +897,7 @@ export interface ErDiagramConfig extends BaseDiagramConfig { | ||||
|   /** | ||||
|    * Directional bias for layout of entities | ||||
|    */ | ||||
|   layoutDirection?: string | 'TB' | 'BT' | 'LR' | 'RL'; | ||||
|   layoutDirection?: 'TB' | 'BT' | 'LR' | 'RL'; | ||||
|   /** | ||||
|    * The minimum width of an entity box. Expressed in pixels. | ||||
|    */ | ||||
| @@ -977,7 +962,7 @@ export interface StateDiagramConfig extends BaseDiagramConfig { | ||||
|    * Decides which rendering engine that is to be used for the rendering. | ||||
|    * | ||||
|    */ | ||||
|   defaultRenderer?: string | 'dagre-d3' | 'dagre-wrapper' | 'elk'; | ||||
|   defaultRenderer?: 'dagre-d3' | 'dagre-wrapper' | 'elk'; | ||||
| } | ||||
| /** | ||||
|  * This interface was referenced by `MermaidConfig`'s JSON-Schema | ||||
| @@ -1001,7 +986,7 @@ export interface ClassDiagramConfig extends BaseDiagramConfig { | ||||
|    * Decides which rendering engine that is to be used for the rendering. | ||||
|    * | ||||
|    */ | ||||
|   defaultRenderer?: string | 'dagre-d3' | 'dagre-wrapper' | 'elk'; | ||||
|   defaultRenderer?: 'dagre-d3' | 'dagre-wrapper' | 'elk'; | ||||
|   nodeSpacing?: number; | ||||
|   rankSpacing?: number; | ||||
|   /** | ||||
| @@ -1061,7 +1046,7 @@ export interface JourneyDiagramConfig extends BaseDiagramConfig { | ||||
|   /** | ||||
|    * Multiline message alignment | ||||
|    */ | ||||
|   messageAlign?: string | 'left' | 'center' | 'right'; | ||||
|   messageAlign?: 'left' | 'center' | 'right'; | ||||
|   /** | ||||
|    * Prolongs the edge of the diagram downwards. | ||||
|    * | ||||
| @@ -1140,7 +1125,7 @@ export interface TimelineDiagramConfig extends BaseDiagramConfig { | ||||
|   /** | ||||
|    * Multiline message alignment | ||||
|    */ | ||||
|   messageAlign?: string | 'left' | 'center' | 'right'; | ||||
|   messageAlign?: 'left' | 'center' | 'right'; | ||||
|   /** | ||||
|    * Prolongs the edge of the diagram downwards. | ||||
|    * | ||||
| @@ -1251,7 +1236,7 @@ export interface GanttDiagramConfig extends BaseDiagramConfig { | ||||
|    * Controls the display mode. | ||||
|    * | ||||
|    */ | ||||
|   displayMode?: string | 'compact'; | ||||
|   displayMode?: '' | 'compact'; | ||||
|   /** | ||||
|    * On which day a week-based interval should start | ||||
|    * | ||||
| @@ -1310,7 +1295,7 @@ export interface SequenceDiagramConfig extends BaseDiagramConfig { | ||||
|   /** | ||||
|    * Multiline message alignment | ||||
|    */ | ||||
|   messageAlign?: string | 'left' | 'center' | 'right'; | ||||
|   messageAlign?: 'left' | 'center' | 'right'; | ||||
|   /** | ||||
|    * Mirror actors under diagram | ||||
|    * | ||||
| @@ -1367,7 +1352,7 @@ export interface SequenceDiagramConfig extends BaseDiagramConfig { | ||||
|   /** | ||||
|    * This sets the text alignment of actor-attached notes | ||||
|    */ | ||||
|   noteAlign?: string | 'left' | 'center' | 'right'; | ||||
|   noteAlign?: 'left' | 'center' | 'right'; | ||||
|   /** | ||||
|    * This sets the font size of actor messages | ||||
|    */ | ||||
| @@ -1443,7 +1428,7 @@ export interface FlowchartDiagramConfig extends BaseDiagramConfig { | ||||
|    * Defines how mermaid renders curves for flowcharts. | ||||
|    * | ||||
|    */ | ||||
|   curve?: string | 'basis' | 'linear' | 'cardinal'; | ||||
|   curve?: 'basis' | 'linear' | 'cardinal'; | ||||
|   /** | ||||
|    * Represents the padding between the labels and the shape | ||||
|    * | ||||
| @@ -1455,7 +1440,7 @@ export interface FlowchartDiagramConfig extends BaseDiagramConfig { | ||||
|    * Decides which rendering engine that is to be used for the rendering. | ||||
|    * | ||||
|    */ | ||||
|   defaultRenderer?: string | 'dagre-d3' | 'dagre-wrapper' | 'elk'; | ||||
|   defaultRenderer?: 'dagre-d3' | 'dagre-wrapper' | 'elk'; | ||||
|   /** | ||||
|    * Width of nodes where text is wrapped. | ||||
|    * | ||||
|   | ||||
| @@ -2,7 +2,7 @@ import { select } from 'd3'; | ||||
| import { log } from '../logger.js'; | ||||
| import { getConfig } from '../diagram-api/diagramAPI.js'; | ||||
| import { evaluate } from '../diagrams/common/common.js'; | ||||
| import { decodeEntities } from '../mermaidAPI.js'; | ||||
| import { decodeEntities } from '../utils.js'; | ||||
|  | ||||
| /** | ||||
|  * @param dom | ||||
|   | ||||
| @@ -1,9 +1,9 @@ | ||||
| import createLabel from '../createLabel.js'; | ||||
| import { createText } from '../../rendering-util/createText.js'; | ||||
| import { getConfig } from '../../diagram-api/diagramAPI.js'; | ||||
| import { decodeEntities } from '../../mermaidAPI.js'; | ||||
| import { select } from 'd3'; | ||||
| import { evaluate, sanitizeText } from '../../diagrams/common/common.js'; | ||||
| import { decodeEntities } from '../../utils.js'; | ||||
|  | ||||
| export const labelHelper = async (parent, node, _classes, isNode) => { | ||||
|   let classes; | ||||
|   | ||||
| @@ -61,23 +61,37 @@ export const detectType = function (text: string, config?: MermaidConfig): strin | ||||
|  * The first detector to return `true` is the diagram that will be loaded | ||||
|  * and used, so put more specific detectors at the beginning! | ||||
|  * | ||||
|  * If two diagrams are registered with the same id, | ||||
|  * the one with higher `priority` property will be used. | ||||
|  * | ||||
|  * @param diagrams - Diagrams to lazy load, and their detectors, in order of importance. | ||||
|  */ | ||||
| export const registerLazyLoadedDiagrams = (...diagrams: ExternalDiagramDefinition[]) => { | ||||
|   for (const { id, detector, loader } of diagrams) { | ||||
|     addDetector(id, detector, loader); | ||||
|   for (const { id, detector, priority, loader } of diagrams) { | ||||
|     addDetector(id, detector, priority ?? 0, loader); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| export const addDetector = (key: string, detector: DiagramDetector, loader?: DiagramLoader) => { | ||||
|   if (detectors[key]) { | ||||
|     log.error(`Detector with key ${key} already exists`); | ||||
|   } else { | ||||
|     detectors[key] = { detector, loader }; | ||||
| export const addDetector = ( | ||||
|   key: string, | ||||
|   detector: DiagramDetector, | ||||
|   priority: number, | ||||
|   loader?: DiagramLoader | ||||
| ) => { | ||||
|   if (detectors[key] && priority <= detectors[key].priority) { | ||||
|     log.error( | ||||
|       `Detector with key ${key} already exists with priority ${detectors[key].priority}. Cannot add new detector with priority ${priority}` | ||||
|     ); | ||||
|     return; | ||||
|   } | ||||
|   log.debug(`Detector with key ${key} added${loader ? ' with loader' : ''}`); | ||||
|  | ||||
|   detectors[key] = { detector, loader, priority }; | ||||
|   log.debug( | ||||
|     `Detector with key ${key} added with priority ${priority} ${loader ? 'and loader' : ''}` | ||||
|   ); | ||||
| }; | ||||
|  | ||||
| export const getDiagramLoader = (key: string) => { | ||||
|   return detectors[key].loader; | ||||
| export const getDiagramLoaderAndPriority = (key: string) => { | ||||
|   const { loader, priority } = detectors[key]; | ||||
|   return { loader, priority }; | ||||
| }; | ||||
|   | ||||
| @@ -31,7 +31,7 @@ export const addDiagrams = () => { | ||||
|   // This is added here to avoid race-conditions. | ||||
|   // We could optimize the loading logic somehow. | ||||
|   hasLoadedDiagrams = true; | ||||
|   registerDiagram('error', errorDiagram, (text) => { | ||||
|   registerDiagram('error', errorDiagram, 0, (text) => { | ||||
|     return text.toLowerCase().trim() === 'error'; | ||||
|   }); | ||||
|   registerDiagram( | ||||
| @@ -50,7 +50,6 @@ export const addDiagrams = () => { | ||||
|         }, | ||||
|       }, | ||||
|       parser: { | ||||
|         parser: { yy: {} }, | ||||
|         parse: () => { | ||||
|           throw new Error( | ||||
|             'Diagrams beginning with --- are not valid. ' + | ||||
| @@ -61,6 +60,7 @@ export const addDiagrams = () => { | ||||
|       }, | ||||
|       init: () => null, // no op | ||||
|     }, | ||||
|     0, | ||||
|     (text) => { | ||||
|       return text.toLowerCase().trimStart().startsWith('---'); | ||||
|     } | ||||
|   | ||||
| @@ -39,7 +39,6 @@ describe('DiagramAPI', () => { | ||||
|           parse: (_text) => { | ||||
|             return; | ||||
|           }, | ||||
|           parser: { yy: {} }, | ||||
|         }, | ||||
|         renderer: { | ||||
|           draw: () => { | ||||
| @@ -48,6 +47,7 @@ describe('DiagramAPI', () => { | ||||
|         }, | ||||
|         styles: {}, | ||||
|       }, | ||||
|       0, | ||||
|       detector | ||||
|     ); | ||||
|     expect(getDiagram('loki')).not.toBeNull(); | ||||
|   | ||||
| @@ -29,7 +29,7 @@ export const getCommonDb = () => { | ||||
|   return _commonDb; | ||||
| }; | ||||
|  | ||||
| const diagrams: Record<string, DiagramDefinition> = {}; | ||||
| const diagrams: Record<string, DiagramDefinition & { priority: number }> = {}; | ||||
| export interface Detectors { | ||||
|   [key: string]: DiagramDetector; | ||||
| } | ||||
| @@ -37,7 +37,8 @@ export interface Detectors { | ||||
| /** | ||||
|  * Registers the given diagram with Mermaid. | ||||
|  * | ||||
|  * Can be used for third-party custom diagrams. | ||||
|  * To be used internally by Mermaid. | ||||
|  * Use `mermaid.registerExternalDiagrams` to register external diagrams. | ||||
|  * | ||||
|  * @param id - A unique ID for the given diagram. | ||||
|  * @param diagram - The diagram definition. | ||||
| @@ -46,14 +47,17 @@ export interface Detectors { | ||||
| export const registerDiagram = ( | ||||
|   id: string, | ||||
|   diagram: DiagramDefinition, | ||||
|   priority: number, | ||||
|   detector?: DiagramDetector | ||||
| ) => { | ||||
|   if (diagrams[id]) { | ||||
|     throw new Error(`Diagram ${id} already registered.`); | ||||
|   if (diagrams[id] && priority <= diagrams[id].priority) { | ||||
|     throw new Error( | ||||
|       `Diagram ${id} already registered with priority ${diagrams[id].priority}. Cannot add new diagram with priority ${priority}` | ||||
|     ); | ||||
|   } | ||||
|   diagrams[id] = diagram; | ||||
|   diagrams[id] = { ...diagram, priority }; | ||||
|   if (detector) { | ||||
|     addDetector(id, detector); | ||||
|     addDetector(id, detector, priority); | ||||
|   } | ||||
|   addStylesForDiagram(id, diagram.styles); | ||||
|  | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| import type { MermaidConfig } from '../config.type.js'; | ||||
| import type { GanttDiagramConfig, MermaidConfig } from '../config.type.js'; | ||||
| import { frontMatterRegex } from './regexes.js'; | ||||
| // The "* as yaml" part is necessary for tree-shaking | ||||
| import * as yaml from 'js-yaml'; | ||||
| @@ -6,7 +6,7 @@ import * as yaml from 'js-yaml'; | ||||
| interface FrontMatterMetadata { | ||||
|   title?: string; | ||||
|   // Allows custom display modes. Currently used for compact mode in gantt charts. | ||||
|   displayMode?: string; | ||||
|   displayMode?: GanttDiagramConfig['displayMode']; | ||||
|   config?: MermaidConfig; | ||||
| } | ||||
|  | ||||
| @@ -44,7 +44,7 @@ export function extractFrontMatter(text: string): FrontMatterResult { | ||||
|  | ||||
|   // Only add properties that are explicitly supported, if they exist | ||||
|   if (parsed.displayMode) { | ||||
|     metadata.displayMode = parsed.displayMode.toString(); | ||||
|     metadata.displayMode = parsed.displayMode.toString() as GanttDiagramConfig['displayMode']; | ||||
|   } | ||||
|   if (parsed.title) { | ||||
|     metadata.title = parsed.title.toString(); | ||||
|   | ||||
| @@ -6,7 +6,7 @@ export const loadRegisteredDiagrams = async () => { | ||||
|   log.debug(`Loading registered diagrams`); | ||||
|   // Load all lazy loaded diagrams in parallel | ||||
|   const results = await Promise.allSettled( | ||||
|     Object.entries(detectors).map(async ([key, { detector, loader }]) => { | ||||
|     Object.entries(detectors).map(async ([key, { detector, loader, priority }]) => { | ||||
|       if (loader) { | ||||
|         try { | ||||
|           getDiagram(key); | ||||
| @@ -14,7 +14,7 @@ export const loadRegisteredDiagrams = async () => { | ||||
|           try { | ||||
|             // Register diagram if it is not already registered | ||||
|             const { diagram, id } = await loader(); | ||||
|             registerDiagram(id, diagram, detector); | ||||
|             registerDiagram(id, diagram, priority, detector); | ||||
|           } catch (err) { | ||||
|             // Remove failed diagram from detectors | ||||
|             log.error(`Failed to load external diagram with key ${key}. Removing from detectors.`); | ||||
|   | ||||
| @@ -76,13 +76,23 @@ export interface DiagramDefinition { | ||||
|  | ||||
| export interface DetectorRecord { | ||||
|   detector: DiagramDetector; | ||||
|   priority: number; | ||||
|   loader?: DiagramLoader; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * External diagrams, which are not bundled with mermaid should expose the following to be registered using the `mermaid.registerExternalDiagrams` function. | ||||
|  * | ||||
|  * @param id - An ID for the given diagram. If two diagrams are registered with the same ID, the one with the higher priority will be used. | ||||
|  * @param detector - Function that returns `true` if a given mermaid text satisfies with this diagram definition. | ||||
|  * @param loader - Function that returns a promise of the diagram definition. | ||||
|  * @param priority - The priority of the diagram. Optional, defaults to 0. | ||||
|  */ | ||||
| export interface ExternalDiagramDefinition { | ||||
|   id: string; | ||||
|   detector: DiagramDetector; | ||||
|   loader: DiagramLoader; | ||||
|   priority?: number; | ||||
| } | ||||
|  | ||||
| export type DiagramDetector = (text: string, config?: MermaidConfig) => boolean; | ||||
| @@ -105,7 +115,7 @@ export type DrawDefinition = ( | ||||
|  | ||||
| export interface ParserDefinition { | ||||
|   parse: (text: string) => void; | ||||
|   parser: { yy: DiagramDB }; | ||||
|   parser?: { yy: DiagramDB }; | ||||
| } | ||||
|  | ||||
| export type HTML = d3.Selection<HTMLIFrameElement, unknown, Element | null, unknown>; | ||||
|   | ||||
| @@ -21,6 +21,7 @@ describe('diagram detection', () => { | ||||
|     addDetector( | ||||
|       'loki', | ||||
|       (str) => str.startsWith('loki'), | ||||
|       0, | ||||
|       () => | ||||
|         Promise.resolve({ | ||||
|           id: 'loki', | ||||
| @@ -30,9 +31,6 @@ describe('diagram detection', () => { | ||||
|               parse: () => { | ||||
|                 // no-op | ||||
|               }, | ||||
|               parser: { | ||||
|                 yy: {}, | ||||
|               }, | ||||
|             }, | ||||
|             renderer: { | ||||
|               draw: () => { | ||||
| @@ -48,6 +46,37 @@ describe('diagram detection', () => { | ||||
|     expect(diagram.type).toBe('loki'); | ||||
|   }); | ||||
|  | ||||
|   test('should allow external diagrams to override internal ones with same ID', async () => { | ||||
|     addDetector( | ||||
|       'flowchart-elk', | ||||
|       (str) => str.startsWith('flowchart-elk'), | ||||
|       1, | ||||
|       () => | ||||
|         Promise.resolve({ | ||||
|           id: 'flowchart-elk', | ||||
|           diagram: { | ||||
|             db: { | ||||
|               getDiagramTitle: () => 'overridden', | ||||
|             }, | ||||
|             parser: { | ||||
|               parse: () => { | ||||
|                 // no-op | ||||
|               }, | ||||
|             }, | ||||
|             renderer: { | ||||
|               draw: () => { | ||||
|                 // no-op | ||||
|               }, | ||||
|             }, | ||||
|             styles: {}, | ||||
|           }, | ||||
|         }) | ||||
|     ); | ||||
|     const diagram = (await getDiagramFromText('flowchart-elk TD; A-->B')) as Diagram; | ||||
|     expect(diagram).toBeInstanceOf(Diagram); | ||||
|     expect(diagram.db.getDiagramTitle?.()).toBe('overridden'); | ||||
|   }); | ||||
|  | ||||
|   test('should throw the right error for incorrect diagram', async () => { | ||||
|     await expect(getDiagramFromText('graph TD; A-->')).rejects.toThrowErrorMatchingInlineSnapshot(` | ||||
|       "Parse error on line 2: | ||||
| @@ -69,4 +98,18 @@ Expecting 'TXT', got 'NEWLINE'" | ||||
|       '"No diagram type detected matching given configuration for text: thor TD; A-->B"' | ||||
|     ); | ||||
|   }); | ||||
|  | ||||
|   test('should consider entity codes when present in diagram defination', async () => { | ||||
|     const diagram = await getDiagramFromText(`sequenceDiagram | ||||
|     A->>B: I #9829; you! | ||||
|     B->>A: I #9829; you #infin; times more!`); | ||||
|     // @ts-ignore: we need to add types for sequenceDb which will be done in separate PR | ||||
|     const messages = diagram.db?.getMessages?.(); | ||||
|     if (!messages) { | ||||
|       throw new Error('Messages not found!'); | ||||
|     } | ||||
|  | ||||
|     expect(messages[0].message).toBe('I fl°°9829¶ß you!'); | ||||
|     expect(messages[1].message).toBe('I fl°°9829¶ß you fl°infin¶ß times more!'); | ||||
|   }); | ||||
| }); | ||||
|   | ||||
| @@ -231,7 +231,7 @@ export const addRelations = function (relations: ClassRelation[], g: graphlib.Gr | ||||
|       //Set relationship style and line type | ||||
|       classes: 'relation', | ||||
|       pattern: edge.relation.lineType == 1 ? 'dashed' : 'solid', | ||||
|       id: 'id' + cnt, | ||||
|       id: `id_${edge.id1}_${edge.id2}_${cnt}`, | ||||
|       // Set link type for rendering | ||||
|       arrowhead: edge.type === 'arrow_open' ? 'none' : 'normal', | ||||
|       //Set edge extra labels | ||||
|   | ||||
| @@ -681,3 +681,82 @@ describe('given text representing a method, ', function () { | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
|  | ||||
| describe('given text representing an attribute', () => { | ||||
|   describe('when the attribute has no modifiers', () => { | ||||
|     it('should parse the display text correctly', () => { | ||||
|       const str = 'name String'; | ||||
|  | ||||
|       const displayDetails = new ClassMember(str, 'attribute').getDisplayDetails(); | ||||
|  | ||||
|       expect(displayDetails.displayText).toBe('name String'); | ||||
|       expect(displayDetails.cssStyle).toBe(''); | ||||
|     }); | ||||
|   }); | ||||
|  | ||||
|   describe('when the attribute has public "+" modifier', () => { | ||||
|     it('should parse the display text correctly', () => { | ||||
|       const str = '+name String'; | ||||
|  | ||||
|       const displayDetails = new ClassMember(str, 'attribute').getDisplayDetails(); | ||||
|  | ||||
|       expect(displayDetails.displayText).toBe('+name String'); | ||||
|       expect(displayDetails.cssStyle).toBe(''); | ||||
|     }); | ||||
|   }); | ||||
|  | ||||
|   describe('when the attribute has protected "#" modifier', () => { | ||||
|     it('should parse the display text correctly', () => { | ||||
|       const str = '#name String'; | ||||
|  | ||||
|       const displayDetails = new ClassMember(str, 'attribute').getDisplayDetails(); | ||||
|  | ||||
|       expect(displayDetails.displayText).toBe('#name String'); | ||||
|       expect(displayDetails.cssStyle).toBe(''); | ||||
|     }); | ||||
|   }); | ||||
|  | ||||
|   describe('when the attribute has private "-" modifier', () => { | ||||
|     it('should parse the display text correctly', () => { | ||||
|       const str = '-name String'; | ||||
|  | ||||
|       const displayDetails = new ClassMember(str, 'attribute').getDisplayDetails(); | ||||
|  | ||||
|       expect(displayDetails.displayText).toBe('-name String'); | ||||
|       expect(displayDetails.cssStyle).toBe(''); | ||||
|     }); | ||||
|   }); | ||||
|  | ||||
|   describe('when the attribute has internal "~" modifier', () => { | ||||
|     it('should parse the display text correctly', () => { | ||||
|       const str = '~name String'; | ||||
|  | ||||
|       const displayDetails = new ClassMember(str, 'attribute').getDisplayDetails(); | ||||
|  | ||||
|       expect(displayDetails.displayText).toBe('~name String'); | ||||
|       expect(displayDetails.cssStyle).toBe(''); | ||||
|     }); | ||||
|   }); | ||||
|  | ||||
|   describe('when the attribute has static "$" modifier', () => { | ||||
|     it('should parse the display text correctly and apply static css style', () => { | ||||
|       const str = 'name String$'; | ||||
|  | ||||
|       const displayDetails = new ClassMember(str, 'attribute').getDisplayDetails(); | ||||
|  | ||||
|       expect(displayDetails.displayText).toBe('name String'); | ||||
|       expect(displayDetails.cssStyle).toBe(staticCssStyle); | ||||
|     }); | ||||
|   }); | ||||
|  | ||||
|   describe('when the attribute has abstract "*" modifier', () => { | ||||
|     it('should parse the display text correctly and apply abstract css style', () => { | ||||
|       const str = 'name String*'; | ||||
|  | ||||
|       const displayDetails = new ClassMember(str, 'attribute').getDisplayDetails(); | ||||
|  | ||||
|       expect(displayDetails.displayText).toBe('name String'); | ||||
|       expect(displayDetails.cssStyle).toBe(abstractCssStyle); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
|   | ||||
| @@ -106,7 +106,7 @@ export class ClassMember { | ||||
|         this.visibility = firstChar as Visibility; | ||||
|       } | ||||
|  | ||||
|       if (lastChar.match(/[*?]/)) { | ||||
|       if (lastChar.match(/[$*]/)) { | ||||
|         potentialClassifier = lastChar; | ||||
|       } | ||||
|  | ||||
|   | ||||
| @@ -38,6 +38,20 @@ describe('when securityLevel is antiscript, all script must be removed', () => { | ||||
|     compareRemoveScript(`<img onerror="alert('hello');">`, `<img>`); | ||||
|   }); | ||||
|  | ||||
|   it('should detect unsecured target attribute, if value is _blank then generate a secured link', () => { | ||||
|     compareRemoveScript( | ||||
|       `<a href="https://mermaid.js.org/" target="_blank">note about mermaid</a>`, | ||||
|       `<a href="https://mermaid.js.org/" target="_blank" rel="noopener">note about mermaid</a>` | ||||
|     ); | ||||
|   }); | ||||
|  | ||||
|   it('should detect unsecured target attribute from links', () => { | ||||
|     compareRemoveScript( | ||||
|       `<a href="https://mermaid.js.org/" target="_self">note about mermaid</a>`, | ||||
|       `<a href="https://mermaid.js.org/" target="_self">note about mermaid</a>` | ||||
|     ); | ||||
|   }); | ||||
|  | ||||
|   it('should detect iframes', () => { | ||||
|     compareRemoveScript( | ||||
|       `<iframe src="http://abc.com/script1.js"></iframe> | ||||
|   | ||||
| @@ -25,7 +25,27 @@ export const getRows = (s?: string): string[] => { | ||||
|  * @returns The safer text | ||||
|  */ | ||||
| export const removeScript = (txt: string): string => { | ||||
|   return DOMPurify.sanitize(txt); | ||||
|   const TEMPORARY_ATTRIBUTE = 'data-temp-href-target'; | ||||
|  | ||||
|   DOMPurify.addHook('beforeSanitizeAttributes', (node: Element) => { | ||||
|     if (node.tagName === 'A' && node.hasAttribute('target')) { | ||||
|       node.setAttribute(TEMPORARY_ATTRIBUTE, node.getAttribute('target') || ''); | ||||
|     } | ||||
|   }); | ||||
|  | ||||
|   const sanitizedText = DOMPurify.sanitize(txt); | ||||
|  | ||||
|   DOMPurify.addHook('afterSanitizeAttributes', (node: Element) => { | ||||
|     if (node.tagName === 'A' && node.hasAttribute(TEMPORARY_ATTRIBUTE)) { | ||||
|       node.setAttribute('target', node.getAttribute(TEMPORARY_ATTRIBUTE) || ''); | ||||
|       node.removeAttribute(TEMPORARY_ATTRIBUTE); | ||||
|       if (node.getAttribute('target') === '_blank') { | ||||
|         node.setAttribute('rel', 'noopener'); | ||||
|       } | ||||
|     } | ||||
|   }); | ||||
|  | ||||
|   return sanitizedText; | ||||
| }; | ||||
|  | ||||
| const sanitizeMore = (text: string, config: MermaidConfig) => { | ||||
|   | ||||
							
								
								
									
										15
									
								
								packages/mermaid/src/diagrams/common/populateCommonDb.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								packages/mermaid/src/diagrams/common/populateCommonDb.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| import type { DiagramAST } from 'mermaid-parser'; | ||||
|  | ||||
| import type { DiagramDB } from '../../diagram-api/types.js'; | ||||
|  | ||||
| export function populateCommonDb(ast: DiagramAST, db: DiagramDB) { | ||||
|   if (ast.accDescr) { | ||||
|     db.setAccDescription?.(ast.accDescr); | ||||
|   } | ||||
|   if (ast.accTitle) { | ||||
|     db.setAccTitle?.(ast.accTitle); | ||||
|   } | ||||
|   if (ast.title) { | ||||
|     db.setDiagramTitle?.(ast.title); | ||||
|   } | ||||
| } | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user