From 5b66810646a12ef36452c2323fb92353efa50358 Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Wed, 22 May 2024 17:01:34 +0530 Subject: [PATCH] feat: Remove direct file dependency of mermaid from elk, by using peerDependency. --- .build/common.ts | 7 +--- cypress/platform/knsv2.html | 2 + packages/mermaid-layout-elk/package.json | 2 +- packages/mermaid-layout-elk/src/layouts.ts | 17 ++++++++ .../src/{index.ts => render.ts} | 27 +++++++------ packages/mermaid-layout-elk/tsconfig.json | 2 +- packages/mermaid/src/internals.ts | 31 ++++++++++++++ packages/mermaid/src/mermaid.ts | 12 ++++++ packages/mermaid/src/rendering-util/render.js | 34 ---------------- packages/mermaid/src/rendering-util/render.ts | 40 +++++++++++++++++++ pnpm-lock.yaml | 1 - tsconfig.json | 2 +- 12 files changed, 120 insertions(+), 57 deletions(-) create mode 100644 packages/mermaid-layout-elk/src/layouts.ts rename packages/mermaid-layout-elk/src/{index.ts => render.ts} (96%) create mode 100644 packages/mermaid/src/internals.ts delete mode 100644 packages/mermaid/src/rendering-util/render.js create mode 100644 packages/mermaid/src/rendering-util/render.ts diff --git a/.build/common.ts b/.build/common.ts index f128e5097..e2190974f 100644 --- a/.build/common.ts +++ b/.build/common.ts @@ -22,14 +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', - }, 'mermaid-layout-elk': { name: 'mermaid-layout-elk', packageName: 'mermaid-layout-elk', - file: 'index.ts', + file: 'layouts.ts', }, } as const; diff --git a/cypress/platform/knsv2.html b/cypress/platform/knsv2.html index 185012596..5f1c0fb33 100644 --- a/cypress/platform/knsv2.html +++ b/cypress/platform/knsv2.html @@ -508,6 +508,8 @@ mindmap // import mindmap from '../../packages/mermaid-mindmap/src/detector'; // import example from '../../packages/mermaid-example-diagram/src/mermaid-example-diagram.core.mjs'; import mermaid from './mermaid.esm.mjs'; + import { layouts } from './mermaid-layout-elk.esm.mjs'; + mermaid.registerLayoutLoaders(layouts); // await mermaid.registerExternalDiagrams([example]); mermaid.parseError = function (err, hash) { // console.error('Mermaid error: ', err); diff --git a/packages/mermaid-layout-elk/package.json b/packages/mermaid-layout-elk/package.json index 888cb56d9..4f8054682 100644 --- a/packages/mermaid-layout-elk/package.json +++ b/packages/mermaid-layout-elk/package.json @@ -34,7 +34,7 @@ "elkjs": "^0.9.3", "d3": "^7.9.0" }, - "devDependencies": { + "peerDependencies": { "mermaid": "workspace:^" }, "files": [ diff --git a/packages/mermaid-layout-elk/src/layouts.ts b/packages/mermaid-layout-elk/src/layouts.ts new file mode 100644 index 000000000..a6075386b --- /dev/null +++ b/packages/mermaid-layout-elk/src/layouts.ts @@ -0,0 +1,17 @@ +import type { LayoutLoaderDefinition } from 'mermaid'; + +const loader = async () => await import(`./render.js`); +const algos = ['elk.stress', 'elk.force', 'elk.mrtree', 'elk.sporeOverlap']; + +export const layouts: LayoutLoaderDefinition[] = [ + { + name: 'elk', + loader, + algorithm: 'elk.layered', + }, + ...algos.map((algo) => ({ + name: algo, + loader, + algorithm: algo, + })), +]; diff --git a/packages/mermaid-layout-elk/src/index.ts b/packages/mermaid-layout-elk/src/render.ts similarity index 96% rename from packages/mermaid-layout-elk/src/index.ts rename to packages/mermaid-layout-elk/src/render.ts index fe8733293..12563b23f 100644 --- a/packages/mermaid-layout-elk/src/index.ts +++ b/packages/mermaid-layout-elk/src/render.ts @@ -1,21 +1,22 @@ // @ts-nocheck File not ready to check types - +import { curveLinear } from 'd3'; import ELK from 'elkjs/lib/elk.bundled.js'; -import { getConfig } from '../../mermaid/src/config.js'; -import common from '../../mermaid/src/diagrams/common/common.js'; -import { log } from '../../mermaid/src/logger.js'; -import { insertCluster } from '../../mermaid/src/rendering-util/rendering-elements/clusters.js'; -import { +import mermaid from 'mermaid'; +import { findCommonAncestor } from './find-common-ancestor.js'; + +const { + common, + getConfig, + insertCluster, insertEdge, insertEdgeLabel, + insertMarkers, + insertNode, + interpolateToCurve, + labelHelper, + log, positionEdgeLabel, -} from '../../mermaid/src/rendering-util/rendering-elements/edges.js'; -import { curveLinear } from 'd3'; -import { interpolateToCurve } from '../../mermaid/src/utils.js'; -import insertMarkers from '../../mermaid/src/rendering-util/rendering-elements/markers.js'; -import { insertNode } from '../../mermaid/src/rendering-util/rendering-elements/nodes.js'; -import { labelHelper } from '../../mermaid/src/rendering-util/rendering-elements/shapes/util.js'; -import { findCommonAncestor } from './find-common-ancestor.js'; +} = mermaid.internalHelpers; const nodeDb = {}; const portPos = {}; diff --git a/packages/mermaid-layout-elk/tsconfig.json b/packages/mermaid-layout-elk/tsconfig.json index 5a41d0603..0d701cede 100644 --- a/packages/mermaid-layout-elk/tsconfig.json +++ b/packages/mermaid-layout-elk/tsconfig.json @@ -1,7 +1,7 @@ { "extends": "../../tsconfig.json", "compilerOptions": { - "rootDir": "../..", + "rootDir": "./src", "outDir": "./dist", "types": ["vitest/importMeta", "vitest/globals"] }, diff --git a/packages/mermaid/src/internals.ts b/packages/mermaid/src/internals.ts new file mode 100644 index 000000000..cebcd4ace --- /dev/null +++ b/packages/mermaid/src/internals.ts @@ -0,0 +1,31 @@ +import { getConfig } from './config.js'; +import common from './diagrams/common/common.js'; +import { log } from './logger.js'; +import { insertCluster } from './rendering-util/rendering-elements/clusters.js'; +import { + insertEdge, + insertEdgeLabel, + positionEdgeLabel, +} from './rendering-util/rendering-elements/edges.js'; +import insertMarkers from './rendering-util/rendering-elements/markers.js'; +import { insertNode } from './rendering-util/rendering-elements/nodes.js'; +import { labelHelper } from './rendering-util/rendering-elements/shapes/util.js'; +import { interpolateToCurve } from './utils.js'; + +/** + * Internal helpers for mermaid + * @deprecated - This should not be used by external packages, as the definitions will change without notice. + */ +export const internalHelpers = { + common, + getConfig, + insertCluster, + insertEdge, + insertEdgeLabel, + insertMarkers, + insertNode, + interpolateToCurve, + labelHelper, + log, + positionEdgeLabel, +}; diff --git a/packages/mermaid/src/mermaid.ts b/packages/mermaid/src/mermaid.ts index 8194872d4..dc9b01e25 100644 --- a/packages/mermaid/src/mermaid.ts +++ b/packages/mermaid/src/mermaid.ts @@ -16,6 +16,9 @@ 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'; +import { registerLayoutLoaders } from './rendering-util/render.js'; +import type { LayoutLoaderDefinition } from './rendering-util/render.js'; +import { internalHelpers } from './internals.js'; export type { MermaidConfig, @@ -26,6 +29,7 @@ export type { ParseOptions, ParseResult, UnknownDiagramError, + LayoutLoaderDefinition, }; export interface RunOptions { @@ -413,11 +417,17 @@ export interface Mermaid { render: typeof render; init: typeof init; run: typeof run; + registerLayoutLoaders: typeof registerLayoutLoaders; registerExternalDiagrams: typeof registerExternalDiagrams; initialize: typeof initialize; contentLoaded: typeof contentLoaded; setParseErrorHandler: typeof setParseErrorHandler; detectType: typeof detectType; + /** + * Internal helpers for mermaid + * @deprecated - This should not be used by external packages, as the definitions will change without notice. + */ + internalHelpers: typeof internalHelpers; } const mermaid: Mermaid = { @@ -428,11 +438,13 @@ const mermaid: Mermaid = { init, run, registerExternalDiagrams, + registerLayoutLoaders, initialize, parseError: undefined, contentLoaded, setParseErrorHandler, detectType, + internalHelpers, }; export default mermaid; diff --git a/packages/mermaid/src/rendering-util/render.js b/packages/mermaid/src/rendering-util/render.js deleted file mode 100644 index 8e15f5ccf..000000000 --- a/packages/mermaid/src/rendering-util/render.js +++ /dev/null @@ -1,34 +0,0 @@ -export const render = async (data4Layout, svg, element) => { - switch (data4Layout.layoutAlgorithm) { - case 'dagre': { - const layoutRenderer = await import('./layout-algorithms/dagre/index.js'); - return layoutRenderer.render(data4Layout, svg, element); - } - - case 'elk': { - // TODO: Should fix this import path - const layoutRenderer = await import('../../../mermaid-layout-elk/src/index.js'); - return layoutRenderer.render(data4Layout, svg, element, 'elk.layered'); - } - case 'stress': { - // TODO: Should fix this import path - const layoutRenderer = await import('../../../mermaid-layout-elk/src/index.js'); - return layoutRenderer.render(data4Layout, svg, element, 'elk.stress'); - } - case 'force': { - // TODO: Should fix this import path - const layoutRenderer = await import('../../../mermaid-layout-elk/src/index.js'); - return layoutRenderer.render(data4Layout, svg, element, 'elk.force'); - } - case 'mrtree': { - // TODO: Should fix this import path - const layoutRenderer = await import('../../../mermaid-layout-elk/src/index.js'); - return layoutRenderer.render(data4Layout, svg, element, 'elk.mrtree'); - } - case 'sporeOverlap': { - // TODO: Should fix this import path - const layoutRenderer = await import('../../../mermaid-layout-elk/src/index.js'); - return layoutRenderer.render(data4Layout, svg, element, 'elk.sporeOverlap'); - } - } -}; diff --git a/packages/mermaid/src/rendering-util/render.ts b/packages/mermaid/src/rendering-util/render.ts new file mode 100644 index 000000000..489e6ba58 --- /dev/null +++ b/packages/mermaid/src/rendering-util/render.ts @@ -0,0 +1,40 @@ +export interface LayoutAlgorithm { + render(data4Layout: any, svg: any, element: any, algorithm?: string): any; +} + +export type LayoutLoader = () => Promise; +export interface LayoutLoaderDefinition { + name: string; + loader: LayoutLoader; + algorithm?: string; +} + +const layoutAlgorithms: Record = {}; + +export const registerLayoutLoaders = (loaders: LayoutLoaderDefinition[]) => { + for (const loader of loaders) { + layoutAlgorithms[loader.name] = loader; + } +}; + +// TODO: Should we load dagre without lazy loading? +const registerDefaultLayoutLoaders = () => { + registerLayoutLoaders([ + { + name: 'dagre', + loader: async () => await import('./layout-algorithms/dagre/index.js'), + }, + ]); +}; + +registerDefaultLayoutLoaders(); + +export const render = async (data4Layout: any, svg: any, element: any) => { + if (!(data4Layout.layoutAlgorithm in layoutAlgorithms)) { + throw new Error(`Unknown layout algorithm: ${data4Layout.layoutAlgorithm}`); + } + + const layoutDefinition = layoutAlgorithms[data4Layout.layoutAlgorithm]; + const layoutRenderer = await layoutDefinition.loader(); + return layoutRenderer.render(data4Layout, svg, element, layoutDefinition.algorithm); +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 98b7a0267..be1ef7f2f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -442,7 +442,6 @@ importers: elkjs: specifier: ^0.9.3 version: 0.9.3 - devDependencies: mermaid: specifier: workspace:^ version: link:../mermaid diff --git a/tsconfig.json b/tsconfig.json index 4cbf209a3..ea03c9777 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -66,7 +66,7 @@ // "newLine": "crlf", /* Set the newline character for emitting files. */ // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */ // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */ - // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + "noEmitOnError": false /* Disable emitting files if any type checking errors are reported. */, // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */ // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */