From c3c7ccd78af1b9aa203cec43b8046e570abd226b Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Wed, 6 Dec 2023 21:11:07 +0530 Subject: [PATCH 1/8] feat: Add diagramType to RenderResult and ParseResult #5117 --- .../interfaces/mermaidAPI.RenderResult.md | 16 +++++++-- docs/config/setup/modules/mermaidAPI.md | 30 +++++++++++------ packages/mermaid/src/mermaid.ts | 7 ++-- packages/mermaid/src/mermaidAPI.spec.ts | 24 ++++++++++---- packages/mermaid/src/mermaidAPI.ts | 33 +++++++++++++------ 5 files changed, 78 insertions(+), 32 deletions(-) diff --git a/docs/config/setup/interfaces/mermaidAPI.RenderResult.md b/docs/config/setup/interfaces/mermaidAPI.RenderResult.md index 6209782f7..61fcc9357 100644 --- a/docs/config/setup/interfaces/mermaidAPI.RenderResult.md +++ b/docs/config/setup/interfaces/mermaidAPI.RenderResult.md @@ -39,7 +39,19 @@ bindFunctions?.(div); // To call bindFunctions only if it's present. #### Defined in -[mermaidAPI.ts:80](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L80) +[mermaidAPI.ts:96](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L96) + +--- + +### diagramType + +• **diagramType**: `string` + +The diagram type, e.g. 'flowchart', 'sequence', etc. + +#### Defined in + +[mermaidAPI.ts:86](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L86) --- @@ -51,4 +63,4 @@ The svg code for the rendered graph. #### Defined in -[mermaidAPI.ts:70](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L70) +[mermaidAPI.ts:82](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L82) diff --git a/docs/config/setup/modules/mermaidAPI.md b/docs/config/setup/modules/mermaidAPI.md index a1992c225..48cd36e10 100644 --- a/docs/config/setup/modules/mermaidAPI.md +++ b/docs/config/setup/modules/mermaidAPI.md @@ -25,13 +25,23 @@ Renames and re-exports [mermaidAPI](mermaidAPI.md#mermaidapi) #### Defined in -[mermaidAPI.ts:64](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L64) +[mermaidAPI.ts:76](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L76) + +--- + +### ParseResult + +Ƭ **ParseResult**: { `diagramType`: `string` ; `isValid`: `true` } | { `isValid`: `false` } + +#### Defined in + +[mermaidAPI.ts:63](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L63) ## Variables ### mermaidAPI -• `Const` **mermaidAPI**: `Readonly`<{ `defaultConfig`: `MermaidConfig` = configApi.defaultConfig; `getConfig`: () => `MermaidConfig` = configApi.getConfig; `getDiagramFromText`: (`text`: `string`, `metadata`: `Pick`<`DiagramMetadata`, `"title"`>) => `Promise`<`Diagram`> ; `getSiteConfig`: () => `MermaidConfig` = configApi.getSiteConfig; `globalReset`: () => `void` ; `initialize`: (`options`: `MermaidConfig`) => `void` ; `parse`: (`text`: `string`, `parseOptions?`: [`ParseOptions`](../interfaces/mermaidAPI.ParseOptions.md)) => `Promise`<`boolean`> ; `render`: (`id`: `string`, `text`: `string`, `svgContainingElement?`: `Element`) => `Promise`<[`RenderResult`](../interfaces/mermaidAPI.RenderResult.md)> ; `reset`: () => `void` ; `setConfig`: (`conf`: `MermaidConfig`) => `MermaidConfig` = configApi.setConfig; `updateSiteConfig`: (`conf`: `MermaidConfig`) => `MermaidConfig` = configApi.updateSiteConfig }> +• `Const` **mermaidAPI**: `Readonly`<{ `defaultConfig`: `MermaidConfig` = configApi.defaultConfig; `getConfig`: () => `MermaidConfig` = configApi.getConfig; `getDiagramFromText`: (`text`: `string`, `metadata`: `Pick`<`DiagramMetadata`, `"title"`>) => `Promise`<`Diagram`> ; `getSiteConfig`: () => `MermaidConfig` = configApi.getSiteConfig; `globalReset`: () => `void` ; `initialize`: (`options`: `MermaidConfig`) => `void` ; `parse`: (`text`: `string`, `parseOptions?`: [`ParseOptions`](../interfaces/mermaidAPI.ParseOptions.md)) => `Promise`<[`ParseResult`](mermaidAPI.md#parseresult)> ; `render`: (`id`: `string`, `text`: `string`, `svgContainingElement?`: `Element`) => `Promise`<[`RenderResult`](../interfaces/mermaidAPI.RenderResult.md)> ; `reset`: () => `void` ; `setConfig`: (`conf`: `MermaidConfig`) => `MermaidConfig` = configApi.setConfig; `updateSiteConfig`: (`conf`: `MermaidConfig`) => `MermaidConfig` = configApi.updateSiteConfig }> ## mermaidAPI configuration defaults @@ -96,7 +106,7 @@ mermaid.initialize(config); #### Defined in -[mermaidAPI.ts:608](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L608) +[mermaidAPI.ts:621](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L621) ## Functions @@ -127,7 +137,7 @@ Return the last node appended #### Defined in -[mermaidAPI.ts:263](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L263) +[mermaidAPI.ts:275](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L275) --- @@ -153,7 +163,7 @@ the cleaned up svgCode #### Defined in -[mermaidAPI.ts:209](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L209) +[mermaidAPI.ts:221](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L221) --- @@ -178,7 +188,7 @@ the string with all the user styles #### Defined in -[mermaidAPI.ts:139](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L139) +[mermaidAPI.ts:151](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L151) --- @@ -201,7 +211,7 @@ the string with all the user styles #### Defined in -[mermaidAPI.ts:186](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L186) +[mermaidAPI.ts:198](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L198) --- @@ -228,7 +238,7 @@ with an enclosing block that has each of the cssClasses followed by !important; #### Defined in -[mermaidAPI.ts:124](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L124) +[mermaidAPI.ts:136](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L136) --- @@ -254,7 +264,7 @@ Put the svgCode into an iFrame. Return the iFrame code #### Defined in -[mermaidAPI.ts:240](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L240) +[mermaidAPI.ts:252](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L252) --- @@ -279,4 +289,4 @@ Remove any existing elements from the given document #### Defined in -[mermaidAPI.ts:313](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L313) +[mermaidAPI.ts:325](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L325) diff --git a/packages/mermaid/src/mermaid.ts b/packages/mermaid/src/mermaid.ts index 99c3b7491..022c0eaba 100644 --- a/packages/mermaid/src/mermaid.ts +++ b/packages/mermaid/src/mermaid.ts @@ -6,7 +6,7 @@ import { dedent } from 'ts-dedent'; import type { MermaidConfig } from './config.type.js'; import { log } from './logger.js'; import utils from './utils.js'; -import type { ParseOptions, RenderResult } from './mermaidAPI.js'; +import type { ParseOptions, ParseResult, RenderResult } from './mermaidAPI.js'; import { mermaidAPI } from './mermaidAPI.js'; import { registerLazyLoadedDiagrams, detectType } from './diagram-api/detectType.js'; import { loadRegisteredDiagrams } from './diagram-api/loadDiagram.js'; @@ -24,6 +24,7 @@ export type { ParseErrorFunction, RenderResult, ParseOptions, + ParseResult, UnknownDiagramError, }; @@ -314,10 +315,10 @@ const executeQueue = async () => { * Parse the text and validate the syntax. * @param text - The mermaid diagram definition. * @param parseOptions - Options for parsing. - * @returns true if the diagram is valid, false otherwise if parseOptions.suppressErrors is true. + * @returns - If the diagram is valid, returns an object with isValid set to true and the diagramType set to type of the diagram. * @throws Error if the diagram is invalid and parseOptions.suppressErrors is false. */ -const parse = async (text: string, parseOptions?: ParseOptions): Promise => { +const parse = async (text: string, parseOptions?: ParseOptions): Promise => { return new Promise((resolve, reject) => { // This promise will resolve when the render call is done. // It will be queued first and will be executed when it is first in line diff --git a/packages/mermaid/src/mermaidAPI.spec.ts b/packages/mermaid/src/mermaidAPI.spec.ts index 576d46f85..2afe20fac 100644 --- a/packages/mermaid/src/mermaidAPI.spec.ts +++ b/packages/mermaid/src/mermaidAPI.spec.ts @@ -1,5 +1,5 @@ 'use strict'; -import { vi } from 'vitest'; +import { vi, it, expect, describe, beforeEach } from 'vitest'; // ------------------------------------- // Mocks and mocking @@ -682,17 +682,26 @@ describe('mermaidAPI', () => { it('returns false for invalid definition with silent option', async () => { await expect( mermaidAPI.parse('this is not a mermaid diagram definition', { suppressErrors: true }) - ).resolves.toBe(false); + ).resolves.toStrictEqual({ isValid: false }); }); it('resolves for valid definition', async () => { - await expect( - mermaidAPI.parse('graph TD;A--x|text including URL space|B;') - ).resolves.toBeTruthy(); + await expect(mermaidAPI.parse('graph TD;A--x|text including URL space|B;')).resolves + .toMatchInlineSnapshot(` + { + "diagramType": "flowchart-v2", + "isValid": true, + } + `); }); it('returns true for valid definition with silent option', async () => { await expect( mermaidAPI.parse('graph TD;A--x|text including URL space|B;', { suppressErrors: true }) - ).resolves.toBe(true); + ).resolves.toMatchInlineSnapshot(` + { + "diagramType": "flowchart-v2", + "isValid": true, + } + `); }); }); @@ -734,7 +743,8 @@ describe('mermaidAPI', () => { it('should set aria-roledscription to the diagram type AND should call addSVGa11yTitleDescription', async () => { const a11yDiagramInfo_spy = vi.spyOn(accessibility, 'setA11yDiagramInfo'); const a11yTitleDesc_spy = vi.spyOn(accessibility, 'addSVGa11yTitleDescription'); - await mermaidAPI.render(id, diagramText); + const result = await mermaidAPI.render(id, diagramText); + expect(result.diagramType).toBe(expectedDiagramType); expect(a11yDiagramInfo_spy).toHaveBeenCalledWith( expect.anything(), expectedDiagramType diff --git a/packages/mermaid/src/mermaidAPI.ts b/packages/mermaid/src/mermaidAPI.ts index 65310d4fa..46f8d898a 100644 --- a/packages/mermaid/src/mermaidAPI.ts +++ b/packages/mermaid/src/mermaidAPI.ts @@ -60,6 +60,18 @@ export interface ParseOptions { suppressErrors?: boolean; } +export type ParseResult = + | { + isValid: true; + /** + * The diagram type, e.g. 'flowchart', 'sequence', etc. + */ + diagramType: string; + } + | { + isValid: false; + }; + // This makes it clear that we're working with a d3 selected element of some kind, even though it's hard to specify the exact type. export type D3Element = any; @@ -68,6 +80,10 @@ export interface RenderResult { * The svg code for the rendered graph. */ svg: string; + /** + * The diagram type, e.g. 'flowchart', 'sequence', etc. + */ + diagramType: string; /** * Bind function to be called after the svg has been inserted into the DOM. * This is necessary for adding event listeners to the elements in the svg. @@ -91,28 +107,24 @@ function processAndSetConfigs(text: string) { * Parse the text and validate the syntax. * @param text - The mermaid diagram definition. * @param parseOptions - Options for parsing. - * @returns true if the diagram is valid, false otherwise if parseOptions.suppressErrors is true. + * @returns - If the diagram is valid, returns an object with isValid set to true and the diagramType set to type of the diagram. * @throws Error if the diagram is invalid and parseOptions.suppressErrors is false. */ -async function parse(text: string, parseOptions?: ParseOptions): Promise { +async function parse(text: string, parseOptions?: ParseOptions): Promise { addDiagrams(); - - text = processAndSetConfigs(text).code; - try { - await getDiagramFromText(text); + const { code } = processAndSetConfigs(text); + const diagram = await getDiagramFromText(code); + return { isValid: true, diagramType: diagram.type }; } catch (error) { if (parseOptions?.suppressErrors) { - return false; + return { isValid: false }; } throw error; } - return true; } -// append !important; to each cssClass followed by a final !important, all enclosed in { } -// /** * Create a CSS style that starts with the given class name, then the element, * with an enclosing block that has each of the cssClasses followed by !important; @@ -483,6 +495,7 @@ const render = async function ( } return { + diagramType, svg: svgCode, bindFunctions: diag.db.bindFunctions, }; From 479188bc40653d7126a75419f0ea078e9300e4a0 Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Wed, 6 Dec 2023 22:23:37 +0530 Subject: [PATCH 2/8] refactor: Change return type to retain partial backwards compatibility. --- .../interfaces/mermaidAPI.RenderResult.md | 6 +- docs/config/setup/modules/mermaidAPI.md | 20 +++--- docs/config/usage.md | 63 +++--------------- packages/mermaid/src/docs/config/usage.md | 65 +++---------------- packages/mermaid/src/mermaid.ts | 4 +- packages/mermaid/src/mermaidAPI.ts | 13 ++-- 6 files changed, 40 insertions(+), 131 deletions(-) diff --git a/docs/config/setup/interfaces/mermaidAPI.RenderResult.md b/docs/config/setup/interfaces/mermaidAPI.RenderResult.md index 61fcc9357..86f0f92ab 100644 --- a/docs/config/setup/interfaces/mermaidAPI.RenderResult.md +++ b/docs/config/setup/interfaces/mermaidAPI.RenderResult.md @@ -39,7 +39,7 @@ bindFunctions?.(div); // To call bindFunctions only if it's present. #### Defined in -[mermaidAPI.ts:96](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L96) +[mermaidAPI.ts:93](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L93) --- @@ -51,7 +51,7 @@ The diagram type, e.g. 'flowchart', 'sequence', etc. #### Defined in -[mermaidAPI.ts:86](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L86) +[mermaidAPI.ts:83](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L83) --- @@ -63,4 +63,4 @@ The svg code for the rendered graph. #### Defined in -[mermaidAPI.ts:82](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L82) +[mermaidAPI.ts:79](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L79) diff --git a/docs/config/setup/modules/mermaidAPI.md b/docs/config/setup/modules/mermaidAPI.md index 48cd36e10..24d8f8dae 100644 --- a/docs/config/setup/modules/mermaidAPI.md +++ b/docs/config/setup/modules/mermaidAPI.md @@ -25,13 +25,13 @@ Renames and re-exports [mermaidAPI](mermaidAPI.md#mermaidapi) #### Defined in -[mermaidAPI.ts:76](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L76) +[mermaidAPI.ts:73](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L73) --- ### ParseResult -Ƭ **ParseResult**: { `diagramType`: `string` ; `isValid`: `true` } | { `isValid`: `false` } +Ƭ **ParseResult**: { `diagramType`: `string` } | `false` #### Defined in @@ -106,7 +106,7 @@ mermaid.initialize(config); #### Defined in -[mermaidAPI.ts:621](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L621) +[mermaidAPI.ts:618](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L618) ## Functions @@ -137,7 +137,7 @@ Return the last node appended #### Defined in -[mermaidAPI.ts:275](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L275) +[mermaidAPI.ts:272](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L272) --- @@ -163,7 +163,7 @@ the cleaned up svgCode #### Defined in -[mermaidAPI.ts:221](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L221) +[mermaidAPI.ts:218](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L218) --- @@ -188,7 +188,7 @@ the string with all the user styles #### Defined in -[mermaidAPI.ts:151](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L151) +[mermaidAPI.ts:148](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L148) --- @@ -211,7 +211,7 @@ the string with all the user styles #### Defined in -[mermaidAPI.ts:198](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L198) +[mermaidAPI.ts:195](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L195) --- @@ -238,7 +238,7 @@ with an enclosing block that has each of the cssClasses followed by !important; #### Defined in -[mermaidAPI.ts:136](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L136) +[mermaidAPI.ts:133](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L133) --- @@ -264,7 +264,7 @@ Put the svgCode into an iFrame. Return the iFrame code #### Defined in -[mermaidAPI.ts:252](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L252) +[mermaidAPI.ts:249](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L249) --- @@ -289,4 +289,4 @@ Remove any existing elements from the given document #### Defined in -[mermaidAPI.ts:325](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L325) +[mermaidAPI.ts:322](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L322) diff --git a/docs/config/usage.md b/docs/config/usage.md index 699171001..afd8e992a 100644 --- a/docs/config/usage.md +++ b/docs/config/usage.md @@ -331,15 +331,17 @@ module.exports = (options) -> ## Advanced usage -**Syntax validation without rendering (Work in Progress)** +### Syntax validation without rendering -The **mermaid.parse(txt)** function validates graph definitions without rendering a graph. **[This function is still a work in progress](https://github.com/mermaid-js/mermaid/issues/1066), find alternatives below.** +The `mermaid.parse(text, parseOptions)` function validates graph definitions without rendering a graph. -The function **mermaid.parse(txt)**, takes a text string as an argument and returns true if the definition follows mermaid's syntax and -false if it does not. The parseError function will be called when the parse function returns false. +The function `mermaid.parse(text, parseOptions)`, takes a text string as an argument and returns `{ diagramType: string }` if the definition follows mermaid's syntax. -When the parser encounters invalid syntax the **mermaid.parseError** function is called. It is possible to override this -function in order to handle the error in an application-specific way. +If the definition is invalid, the function returns `false` if `parseOptions.supressError` is set to `true`. Otherwise, it throws an error. + +The parseError function will be called when the parse function throws an error. It will not be called if `parseOptions.supressError` is set to `true`. + +It is possible to override this function in order to handle the error in an application-specific way. The code-example below in meta code illustrates how this could work: @@ -359,26 +361,10 @@ const textFieldUpdated = async function () { bindEventHandler('change', 'code', textFieldUpdated); ``` -**Alternative to mermaid.parse():** -One effective and more future-proof method of validating your graph definitions, is to paste and render them via the [Mermaid Live Editor](https://mermaid.live/). This will ensure that your code is compliant with the syntax of Mermaid's most recent version. - ## Configuration -Mermaid takes a number of options which lets you tweak the rendering of the diagrams. Currently there are three ways of -setting the options in mermaid. - -1. Instantiation of the configuration using the initialize call -2. _Using the global mermaid object_ - **Deprecated** -3. _using the global mermaid_config object_ - **Deprecated** -4. Instantiation of the configuration using the **mermaid.init** call- **Deprecated** - -The list above has two ways too many of doing this. Three are deprecated and will eventually be removed. The list of -configuration objects are described [in the mermaidAPI documentation](./setup/README.md). - -## Using the `mermaidAPI.initialize`/`mermaid.initialize` call - -The future proof way of setting the configuration is by using the initialization call to mermaid or mermaidAPI depending -on what kind of integration you use. +You can pass the required configuration to the `mermaid.initialize` call. This is the preferred way of configuring mermaid. +The list of configuration objects are described [in the mermaidAPI documentation](./setup/README.md). ```html