diff --git a/.build/common.ts b/.build/common.ts index e9d0ebfa69..274977fa26 100644 --- a/.build/common.ts +++ b/.build/common.ts @@ -22,4 +22,9 @@ export const packageOptions = { packageName: 'mermaid-zenuml', file: 'detector.ts', }, + 'mermaid-flowchart-elk': { + name: 'mermaid-flowchart-elk', + packageName: 'mermaid-flowchart-elk', + file: 'detector.ts', + }, } as const; diff --git a/.build/types.ts b/.build/types.ts new file mode 100644 index 0000000000..d9f10d21ae --- /dev/null +++ b/.build/types.ts @@ -0,0 +1,16 @@ +import { packageOptions } from './common.js'; +import { execSync } from 'child_process'; + +const buildType = (packageName: string) => { + console.log(`Building types for ${packageName}`); + try { + const out = execSync(`tsc -p ./packages/${packageName}/tsconfig.json --emitDeclarationOnly`); + out.length > 0 && console.log(out.toString()); + } catch (e) { + console.error(e); + } +}; + +for (const { packageName } of Object.values(packageOptions)) { + buildType(packageName); +} diff --git a/.esbuild/server.ts b/.esbuild/server.ts index 63d981b99d..9102c7de83 100644 --- a/.esbuild/server.ts +++ b/.esbuild/server.ts @@ -5,38 +5,25 @@ 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 configs = Object.values(packageOptions).map(({ packageName }) => + getBuildConfig({ ...defaultOptions, minify: false, core: false, entryName: packageName }) ); -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 mermaidIIFEConfig = getBuildConfig({ + ...defaultOptions, + minify: false, + core: false, + entryName: 'mermaid', + format: 'iife', +}); +configs.push(mermaidIIFEConfig); + +const contexts = await Promise.all(configs.map((config) => context(config))); const rebuildAll = async () => { console.time('Rebuild time'); - await Promise.all(contexts.map((ctx) => ctx.rebuild())); + await Promise.all(contexts.map((ctx) => ctx.rebuild())).catch((e) => console.error(e)); console.timeEnd('Rebuild time'); }; @@ -101,10 +88,9 @@ async function createServer() { app.use(cors()); app.get('/events', eventsHandler); - 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')); + 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')); diff --git a/.github/codecov.yaml b/.github/codecov.yaml index 950edb6a9a..9450430859 100644 --- a/.github/codecov.yaml +++ b/.github/codecov.yaml @@ -15,3 +15,4 @@ coverage: # Turing off for now as code coverage isn't stable and causes unnecessary build failures. # default: # threshold: 2% + patch: off diff --git a/.vite/server.ts b/.vite/server.ts index 838d711910..99d16f6f24 100644 --- a/.vite/server.ts +++ b/.vite/server.ts @@ -1,6 +1,7 @@ import express from 'express'; import cors from 'cors'; import { createServer as createViteServer } from 'vite'; +import { packageOptions } from '../.build/common.js'; async function createServer() { const app = express(); @@ -14,10 +15,9 @@ 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')); + for (const { packageName } of Object.values(packageOptions)) { + app.use(express.static(`./packages/${packageName}/dist`)); + } app.use(vite.middlewares); app.use(express.static('demos')); app.use(express.static('cypress/platform')); diff --git a/cypress/integration/other/flowchart-elk.spec.js b/cypress/integration/other/flowchart-elk.spec.js new file mode 100644 index 0000000000..22a6efc0f5 --- /dev/null +++ b/cypress/integration/other/flowchart-elk.spec.js @@ -0,0 +1,14 @@ +import { urlSnapshotTest, openURLAndVerifyRendering } from '../../helpers/util.ts'; + +describe('Flowchart elk', () => { + it('should use dagre as fallback', () => { + urlSnapshotTest('http://localhost:9000/flow-elk.html', { + name: 'flow-elk fallback to dagre', + }); + }); + it('should allow overriding with external package', () => { + urlSnapshotTest('http://localhost:9000/flow-elk.html?elk=true', { + name: 'flow-elk overriding dagre with elk', + }); + }); +}); diff --git a/cypress/platform/flow-elk.html b/cypress/platform/flow-elk.html new file mode 100644 index 0000000000..f319f62e28 --- /dev/null +++ b/cypress/platform/flow-elk.html @@ -0,0 +1,28 @@ + + +
+      flowchart-elk
+      a[hello] --> b[world]
+      b --> c{test}
+      c --> one
+      c --> two
+      c --> three
+    
+ + + + diff --git a/demos/flowchart-elk.html b/demos/flowchart-elk.html new file mode 100644 index 0000000000..69ac2d2bc6 --- /dev/null +++ b/demos/flowchart-elk.html @@ -0,0 +1,35 @@ + + + + + + Mermaid Flowchart ELK Test Page + + + +

Flowchart ELK

+
+		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))
+      
+    
+ + + + diff --git a/package.json b/package.json index c899c7dfae..2ca8d8d9a1 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "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", + "build:types": "ts-node-esm --transpileOnly .build/types.ts", "build:types:watch": "tsc -p ./packages/mermaid/tsconfig.json --emitDeclarationOnly --watch", "dev": "ts-node-esm --transpileOnly .esbuild/server.ts", "dev:vite": "ts-node-esm --transpileOnly .vite/server.ts", diff --git a/packages/mermaid-flowchart-elk/package.json b/packages/mermaid-flowchart-elk/package.json new file mode 100644 index 0000000000..e02dba8970 --- /dev/null +++ b/packages/mermaid-flowchart-elk/package.json @@ -0,0 +1,45 @@ +{ + "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", + "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" + ] +} diff --git a/packages/mermaid/src/diagrams/flowchart/elk/detector.spec.ts b/packages/mermaid-flowchart-elk/src/detector.spec.ts similarity index 100% rename from packages/mermaid/src/diagrams/flowchart/elk/detector.spec.ts rename to packages/mermaid-flowchart-elk/src/detector.spec.ts diff --git a/packages/mermaid-flowchart-elk/src/detector.ts b/packages/mermaid-flowchart-elk/src/detector.ts new file mode 100644 index 0000000000..52fb355a55 --- /dev/null +++ b/packages/mermaid-flowchart-elk/src/detector.ts @@ -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; diff --git a/packages/mermaid-flowchart-elk/src/diagram-definition.ts b/packages/mermaid-flowchart-elk/src/diagram-definition.ts new file mode 100644 index 0000000000..a4e678dcc3 --- /dev/null +++ b/packages/mermaid-flowchart-elk/src/diagram-definition.ts @@ -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, +}; diff --git a/packages/mermaid/src/diagrams/flowchart/elk/flowRenderer-elk.js b/packages/mermaid-flowchart-elk/src/flowRenderer-elk.js similarity index 97% rename from packages/mermaid/src/diagrams/flowchart/elk/flowRenderer-elk.js rename to packages/mermaid-flowchart-elk/src/flowRenderer-elk.js index e45739524e..da4f339d5c 100644 --- a/packages/mermaid/src/diagrams/flowchart/elk/flowRenderer-elk.js +++ b/packages/mermaid-flowchart-elk/src/flowRenderer-elk.js @@ -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} ClassDef styles + * @returns {Record} ClassDef styles */ export const getClasses = function (text, diagObj) { log.info('Extracting classes'); diff --git a/packages/mermaid/src/diagrams/flowchart/elk/render-utils.spec.ts b/packages/mermaid-flowchart-elk/src/render-utils.spec.ts similarity index 100% rename from packages/mermaid/src/diagrams/flowchart/elk/render-utils.spec.ts rename to packages/mermaid-flowchart-elk/src/render-utils.spec.ts diff --git a/packages/mermaid/src/diagrams/flowchart/elk/render-utils.ts b/packages/mermaid-flowchart-elk/src/render-utils.ts similarity index 100% rename from packages/mermaid/src/diagrams/flowchart/elk/render-utils.ts rename to packages/mermaid-flowchart-elk/src/render-utils.ts diff --git a/packages/mermaid/src/diagrams/flowchart/elk/styles.ts b/packages/mermaid-flowchart-elk/src/styles.ts similarity index 100% rename from packages/mermaid/src/diagrams/flowchart/elk/styles.ts rename to packages/mermaid-flowchart-elk/src/styles.ts diff --git a/packages/mermaid-flowchart-elk/tsconfig.json b/packages/mermaid-flowchart-elk/tsconfig.json new file mode 100644 index 0000000000..e7ca78fe48 --- /dev/null +++ b/packages/mermaid-flowchart-elk/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "../..", + "outDir": "./dist" + }, + "include": ["./src/**/*.ts"], + "typeRoots": ["./src/types"] +} diff --git a/packages/mermaid/package.json b/packages/mermaid/package.json index 4ac0b70464..eaf2f0c70b 100644 --- a/packages/mermaid/package.json +++ b/packages/mermaid/package.json @@ -68,7 +68,6 @@ "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", diff --git a/packages/mermaid/src/diagram-api/detectType.ts b/packages/mermaid/src/diagram-api/detectType.ts index ba78dbe55e..aed8ca964e 100644 --- a/packages/mermaid/src/diagram-api/detectType.ts +++ b/packages/mermaid/src/diagram-api/detectType.ts @@ -71,10 +71,9 @@ export const registerLazyLoadedDiagrams = (...diagrams: ExternalDiagramDefinitio 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 }; + log.warn(`Detector with key ${key} already exists. Overwriting.`); } + detectors[key] = { detector, loader }; log.debug(`Detector with key ${key} added${loader ? ' with loader' : ''}`); }; diff --git a/packages/mermaid/src/diagram-api/diagramAPI.ts b/packages/mermaid/src/diagram-api/diagramAPI.ts index 7ca9d58043..5ea3825ef5 100644 --- a/packages/mermaid/src/diagram-api/diagramAPI.ts +++ b/packages/mermaid/src/diagram-api/diagramAPI.ts @@ -49,7 +49,7 @@ export const registerDiagram = ( detector?: DiagramDetector ) => { if (diagrams[id]) { - throw new Error(`Diagram ${id} already registered.`); + log.warn(`Diagram with id ${id} already registered. Overwriting.`); } diagrams[id] = diagram; if (detector) { diff --git a/packages/mermaid/src/diagram.spec.ts b/packages/mermaid/src/diagram.spec.ts index d116399ac1..c73fb0a3b0 100644 --- a/packages/mermaid/src/diagram.spec.ts +++ b/packages/mermaid/src/diagram.spec.ts @@ -2,9 +2,32 @@ import { describe, test, expect } from 'vitest'; import { Diagram, getDiagramFromText } from './Diagram.js'; import { addDetector } from './diagram-api/detectType.js'; import { addDiagrams } from './diagram-api/diagram-orchestration.js'; +import type { DiagramLoader } from './diagram-api/types.js'; addDiagrams(); +const getDummyDiagram = (id: string, title?: string): Awaited> => { + return { + id, + diagram: { + db: { + getDiagramTitle: () => title ?? id, + }, + parser: { + parse: () => { + // no-op + }, + }, + renderer: { + draw: () => { + // no-op + }, + }, + styles: {}, + }, + }; +}; + describe('diagram detection', () => { test('should detect inbuilt diagrams', async () => { const graph = (await getDiagramFromText('graph TD; A-->B')) as Diagram; @@ -21,30 +44,25 @@ describe('diagram detection', () => { addDetector( 'loki', (str) => str.startsWith('loki'), - () => - Promise.resolve({ - id: 'loki', - diagram: { - db: {}, - parser: { - parse: () => { - // no-op - }, - }, - renderer: { - draw: () => { - // no-op - }, - }, - styles: {}, - }, - }) + () => Promise.resolve(getDummyDiagram('loki')) ); - const diagram = (await getDiagramFromText('loki TD; A-->B')) as Diagram; + const diagram = await getDiagramFromText('loki TD; A-->B'); expect(diagram).toBeInstanceOf(Diagram); expect(diagram.type).toBe('loki'); }); + test('should allow external diagrams to override internal ones with same ID', async () => { + const title = 'overridden'; + addDetector( + 'flowchart-elk', + (str) => str.startsWith('flowchart-elk'), + () => Promise.resolve(getDummyDiagram('flowchart-elk', title)) + ); + const diagram = await getDiagramFromText('flowchart-elk TD; A-->B'); + expect(diagram).toBeInstanceOf(Diagram); + expect(diagram.db.getDiagramTitle?.()).toBe(title); + }); + test('should throw the right error for incorrect diagram', async () => { await expect(getDiagramFromText('graph TD; A-->')).rejects.toThrowErrorMatchingInlineSnapshot(` "Parse error on line 2: diff --git a/packages/mermaid/src/diagrams/flowchart/elk/detector.ts b/packages/mermaid/src/diagrams/flowchart/elk/detector.ts index 6cfcf26194..b476ff11ba 100644 --- a/packages/mermaid/src/diagrams/flowchart/elk/detector.ts +++ b/packages/mermaid/src/diagrams/flowchart/elk/detector.ts @@ -3,6 +3,7 @@ import type { DiagramDetector, DiagramLoader, } from '../../../diagram-api/types.js'; +import { log } from '../../../logger.js'; const id = 'flowchart-elk'; @@ -13,13 +14,21 @@ const detector: DiagramDetector = (txt, config): boolean => { // If a flowchart/graph diagram has their default renderer set to elk (/^\s*flowchart|graph/.test(txt) && config?.flowchart?.defaultRenderer === 'elk') ) { + // This will log at the end, hopefully. + setTimeout( + () => + log.warn( + 'flowchart-elk was moved to an external package in Mermaid v11. Please refer [release notes](link) for more details. This diagram will be rendered using `dagre` layout as a fallback.' + ), + 500 + ); return true; } return false; }; const loader: DiagramLoader = async () => { - const { diagram } = await import('./flowchart-elk-definition.js'); + const { diagram } = await import('../flowDiagram-v2.js'); return { id, diagram }; }; diff --git a/packages/mermaid/src/diagrams/flowchart/elk/flowchart-elk-definition.ts b/packages/mermaid/src/diagrams/flowchart/elk/flowchart-elk-definition.ts deleted file mode 100644 index 9855c73899..0000000000 --- a/packages/mermaid/src/diagrams/flowchart/elk/flowchart-elk-definition.ts +++ /dev/null @@ -1,13 +0,0 @@ -// @ts-ignore: JISON typing missing -import parser from '../parser/flow.jison'; - -import * as db from '../flowDb.js'; -import renderer from './flowRenderer-elk.js'; -import styles from './styles.js'; - -export const diagram = { - db, - renderer, - parser, - styles, -}; diff --git a/packages/mermaid/src/mermaid.ts b/packages/mermaid/src/mermaid.ts index a6d4954714..99c3b7491b 100644 --- a/packages/mermaid/src/mermaid.ts +++ b/packages/mermaid/src/mermaid.ts @@ -15,6 +15,7 @@ import { isDetailedError } from './utils.js'; import type { DetailedError } from './utils.js'; import type { ExternalDiagramDefinition } from './diagram-api/types.js'; import type { UnknownDiagramError } from './errors.js'; +import { addDiagrams } from './diagram-api/diagram-orchestration.js'; export type { MermaidConfig, @@ -243,6 +244,7 @@ const registerExternalDiagrams = async ( lazyLoad?: boolean; } = {} ) => { + addDiagrams(); registerLazyLoadedDiagrams(...diagrams); if (lazyLoad === false) { await loadRegisteredDiagrams(); diff --git a/packages/mermaid/src/styles.spec.ts b/packages/mermaid/src/styles.spec.ts index 420ee9757b..d22b0f2ee3 100644 --- a/packages/mermaid/src/styles.spec.ts +++ b/packages/mermaid/src/styles.spec.ts @@ -17,7 +17,6 @@ import theme from './themes/index.js'; import c4 from './diagrams/c4/styles.js'; import classDiagram from './diagrams/class/styles.js'; import flowchart from './diagrams/flowchart/styles.js'; -import flowchartElk from './diagrams/flowchart/elk/styles.js'; import er from './diagrams/er/styles.js'; import git from './diagrams/git/styles.js'; import gantt from './diagrams/gantt/styles.js'; @@ -86,7 +85,6 @@ describe('styles', () => { classDiagram, er, flowchart, - flowchartElk, gantt, git, journey, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d9bc33f3a0..8320ab06b1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -224,9 +224,6 @@ importers: dompurify: specifier: ^3.0.5 version: 3.0.5 - elkjs: - specifier: ^0.8.2 - version: 0.8.2 khroma: specifier: ^2.0.0 version: 2.0.0 @@ -416,6 +413,31 @@ importers: specifier: ^5.0.0 version: 5.0.0 + packages/mermaid-flowchart-elk: + dependencies: + d3: + specifier: ^7.4.0 + version: 7.8.5 + dagre-d3-es: + specifier: 7.0.10 + version: 7.0.10 + elkjs: + specifier: ^0.8.2 + version: 0.8.2 + khroma: + specifier: ^2.0.0 + version: 2.0.0 + devDependencies: + concurrently: + specifier: ^8.0.0 + version: 8.0.1 + mermaid: + specifier: workspace:^ + version: link:../mermaid + rimraf: + specifier: ^5.0.0 + version: 5.0.0 + packages/mermaid-zenuml: dependencies: '@zenuml/core':