From c3c7ccd78af1b9aa203cec43b8046e570abd226b Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Wed, 6 Dec 2023 21:11:07 +0530 Subject: [PATCH] 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, };