mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-01 06:36:40 +02:00
feat: Break render and parse types
Both render and parse are async now. Return type of render contains svg and bindFunctions. Parse will not throw error if parseOptions.silent is passed.
This commit is contained in:
@@ -1,5 +1,25 @@
|
||||
# A collection of updates that change the behaviour
|
||||
# A collection of updates that change the behavior
|
||||
|
||||
## Async
|
||||
|
||||
`init`, `parse`, `render` are now async.
|
||||
|
||||
## Lazy loading and asynchronisity
|
||||
|
||||
- Invalid dates are rendered as syntax error instead of returning best guess or the current date
|
||||
|
||||
## ParseError is removed
|
||||
|
||||
```js
|
||||
//< v10.0.0
|
||||
mermaid.parse(text, parseError);
|
||||
|
||||
//>= v10.0.0
|
||||
await mermaid.parse(text).catch(parseError);
|
||||
// or
|
||||
try {
|
||||
await mermaid.parse(text);
|
||||
} catch (err) {
|
||||
parseError(err);
|
||||
}
|
||||
```
|
||||
|
78
docs/config/setup/interfaces/mermaidAPI.RenderResult.md
Normal file
78
docs/config/setup/interfaces/mermaidAPI.RenderResult.md
Normal file
@@ -0,0 +1,78 @@
|
||||
> **Warning**
|
||||
>
|
||||
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
|
||||
>
|
||||
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/config/setup/interfaces/mermaidAPI.RenderResult.md](../../../../packages/mermaid/src/docs/config/setup/interfaces/mermaidAPI.RenderResult.md).
|
||||
|
||||
# Interface: RenderResult
|
||||
|
||||
[mermaidAPI](../modules/mermaidAPI.md).RenderResult
|
||||
|
||||
Function that renders an svg with a graph from a chart definition. Usage example below.
|
||||
|
||||
```javascript
|
||||
mermaidAPI.initialize({
|
||||
startOnLoad: true,
|
||||
});
|
||||
$(function () {
|
||||
const graphDefinition = 'graph TB\na-->b';
|
||||
const cb = function (svgGraph) {
|
||||
console.log(svgGraph);
|
||||
};
|
||||
mermaidAPI.render('id1', graphDefinition, cb);
|
||||
});
|
||||
```
|
||||
|
||||
**`Param`**
|
||||
|
||||
The id for the SVG element (the element to be rendered)
|
||||
|
||||
**`Param`**
|
||||
|
||||
The text for the graph definition
|
||||
|
||||
**`Param`**
|
||||
|
||||
Callback which is called after rendering is finished with the svg code as in param.
|
||||
|
||||
**`Param`**
|
||||
|
||||
HTML element where the svg will be inserted. (Is usually element with the .mermaid class)
|
||||
If no svgContainingElement is provided then the SVG element will be appended to the body.
|
||||
Selector to element in which a div with the graph temporarily will be
|
||||
inserted. If one is provided a hidden div will be inserted in the body of the page instead. The
|
||||
element will be removed when rendering is completed.
|
||||
|
||||
## Properties
|
||||
|
||||
### bindFunctions
|
||||
|
||||
• `Optional` **bindFunctions**: (`element`: `Element`) => `void`
|
||||
|
||||
#### Type declaration
|
||||
|
||||
▸ (`element`): `void`
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| :-------- | :-------- |
|
||||
| `element` | `Element` |
|
||||
|
||||
##### Returns
|
||||
|
||||
`void`
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:382](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L382)
|
||||
|
||||
---
|
||||
|
||||
### svg
|
||||
|
||||
• **svg**: `string`
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:381](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L381)
|
@@ -6,6 +6,10 @@
|
||||
|
||||
# Module: mermaidAPI
|
||||
|
||||
## Interfaces
|
||||
|
||||
- [RenderResult](../interfaces/mermaidAPI.RenderResult.md)
|
||||
|
||||
## References
|
||||
|
||||
### default
|
||||
@@ -20,13 +24,13 @@ Renames and re-exports [mermaidAPI](mermaidAPI.md#mermaidapi)
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:75](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L75)
|
||||
[mermaidAPI.ts:71](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L71)
|
||||
|
||||
## Variables
|
||||
|
||||
### mermaidAPI
|
||||
|
||||
• `Const` **mermaidAPI**: `Readonly`<{ `defaultConfig`: `MermaidConfig` = configApi.defaultConfig; `getConfig`: () => `MermaidConfig` = configApi.getConfig; `getSiteConfig`: () => `MermaidConfig` = configApi.getSiteConfig; `globalReset`: () => `void` ; `initialize`: (`options`: `MermaidConfig`) => `void` ; `parse`: (`text`: `string`, `parseError?`: `ParseErrorFunction`) => `Promise`<`boolean`> ; `parseDirective`: (`p`: `any`, `statement`: `string`, `context`: `string`, `type`: `string`) => `void` ; `render`: (`id`: `string`, `text`: `string`, `cb?`: (`svgCode`: `string`, `bindFunctions?`: (`element`: `Element`) => `void`) => `void`, `svgContainingElement?`: `Element`) => `Promise`<`string`> ; `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; `getSiteConfig`: () => `MermaidConfig` = configApi.getSiteConfig; `globalReset`: () => `void` ; `initialize`: (`options`: `MermaidConfig`) => `void` ; `parse`: (`text`: `string`, `parseOptions?`: { `silent?`: `boolean` }) => `Promise`<`boolean` | `void`> ; `parseDirective`: (`p`: `any`, `statement`: `string`, `context`: `string`, `type`: `string`) => `void` ; `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
|
||||
|
||||
@@ -90,7 +94,7 @@ mermaid.initialize(config);
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:671](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L671)
|
||||
[mermaidAPI.ts:666](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L666)
|
||||
|
||||
## Functions
|
||||
|
||||
@@ -121,7 +125,7 @@ Return the last node appended
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:278](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L278)
|
||||
[mermaidAPI.ts:289](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L289)
|
||||
|
||||
---
|
||||
|
||||
@@ -147,7 +151,7 @@ the cleaned up svgCode
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:229](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L229)
|
||||
[mermaidAPI.ts:240](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L240)
|
||||
|
||||
---
|
||||
|
||||
@@ -173,7 +177,7 @@ the string with all the user styles
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:158](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L158)
|
||||
[mermaidAPI.ts:169](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L169)
|
||||
|
||||
---
|
||||
|
||||
@@ -196,7 +200,7 @@ the string with all the user styles
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:206](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L206)
|
||||
[mermaidAPI.ts:217](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L217)
|
||||
|
||||
---
|
||||
|
||||
@@ -223,7 +227,7 @@ with an enclosing block that has each of the cssClasses followed by !important;
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:142](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L142)
|
||||
[mermaidAPI.ts:153](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L153)
|
||||
|
||||
---
|
||||
|
||||
@@ -243,7 +247,7 @@ with an enclosing block that has each of the cssClasses followed by !important;
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:122](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L122)
|
||||
[mermaidAPI.ts:133](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L133)
|
||||
|
||||
---
|
||||
|
||||
@@ -263,7 +267,7 @@ with an enclosing block that has each of the cssClasses followed by !important;
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:93](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L93)
|
||||
[mermaidAPI.ts:104](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L104)
|
||||
|
||||
---
|
||||
|
||||
@@ -289,7 +293,7 @@ Put the svgCode into an iFrame. Return the iFrame code
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:257](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L257)
|
||||
[mermaidAPI.ts:268](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L268)
|
||||
|
||||
---
|
||||
|
||||
@@ -314,4 +318,4 @@ Remove any existing elements from the given document
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:328](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L328)
|
||||
[mermaidAPI.ts:339](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L339)
|
||||
|
@@ -3,26 +3,24 @@ import { log } from './logger';
|
||||
import { getDiagram, registerDiagram } from './diagram-api/diagramAPI';
|
||||
import { detectType, getDiagramLoader } from './diagram-api/detectType';
|
||||
import { extractFrontMatter } from './diagram-api/frontmatter';
|
||||
import { isDetailedError } from './utils';
|
||||
import type { DetailedError } from './utils';
|
||||
import { UnknownDiagramError } from './errors';
|
||||
import { DetailedError } from './utils';
|
||||
|
||||
export type ParseErrorFunction = (err: string | DetailedError | unknown, hash?: any) => void;
|
||||
|
||||
export class Diagram {
|
||||
type = 'graph';
|
||||
parser;
|
||||
renderer;
|
||||
db;
|
||||
private detectTypeFailed = false;
|
||||
constructor(public txt: string, parseError?: ParseErrorFunction) {
|
||||
private detectError?: UnknownDiagramError;
|
||||
constructor(public text: string) {
|
||||
this.text += '\n';
|
||||
const cnf = configApi.getConfig();
|
||||
this.txt = txt;
|
||||
try {
|
||||
this.type = detectType(txt, cnf);
|
||||
this.type = detectType(text, cnf);
|
||||
} catch (e) {
|
||||
this.handleError(e, parseError);
|
||||
this.type = 'error';
|
||||
this.detectTypeFailed = true;
|
||||
this.detectError = e as UnknownDiagramError;
|
||||
}
|
||||
const diagram = getDiagram(this.type);
|
||||
log.debug('Type ' + this.type);
|
||||
@@ -46,44 +44,19 @@ export class Diagram {
|
||||
diagram.init(cnf);
|
||||
log.info('Initialized diagram ' + this.type, cnf);
|
||||
}
|
||||
this.txt += '\n';
|
||||
|
||||
this.parse(this.txt, parseError);
|
||||
this.parse();
|
||||
}
|
||||
|
||||
parse(text: string, parseError?: ParseErrorFunction): boolean {
|
||||
if (this.detectTypeFailed) {
|
||||
return false;
|
||||
parse() {
|
||||
if (this.detectError) {
|
||||
throw this.detectError;
|
||||
}
|
||||
try {
|
||||
text = text + '\n';
|
||||
this.db.clear?.();
|
||||
this.parser.parse(text);
|
||||
return true;
|
||||
} catch (error) {
|
||||
this.handleError(error, parseError);
|
||||
}
|
||||
return false;
|
||||
this.parser.parse(this.text);
|
||||
}
|
||||
|
||||
handleError(error: unknown, parseError?: ParseErrorFunction) {
|
||||
// Is this the correct way to access mermaid's parseError()
|
||||
// method ? (or global.mermaid.parseError()) ?
|
||||
|
||||
if (parseError === undefined) {
|
||||
// No mermaid.parseError() handler defined, so re-throw it
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (isDetailedError(error)) {
|
||||
// Handle case where error string and hash were
|
||||
// wrapped in object like`const error = { str, hash };`
|
||||
parseError(error.str, error.hash);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, assume it is just an error string and pass it on
|
||||
parseError(error as string);
|
||||
async render(id: string, version: string) {
|
||||
await this.renderer.draw(this.text, id, version, this);
|
||||
}
|
||||
|
||||
getParser() {
|
||||
@@ -95,10 +68,7 @@ export class Diagram {
|
||||
}
|
||||
}
|
||||
|
||||
export const getDiagramFromText = (
|
||||
txt: string,
|
||||
parseError?: ParseErrorFunction
|
||||
): Diagram | Promise<Diagram> => {
|
||||
export const getDiagramFromText = async (txt: string): Promise<Diagram> => {
|
||||
const type = detectType(txt, configApi.getConfig());
|
||||
try {
|
||||
// Trying to find the diagram
|
||||
@@ -106,19 +76,12 @@ export const getDiagramFromText = (
|
||||
} catch (error) {
|
||||
const loader = getDiagramLoader(type);
|
||||
if (!loader) {
|
||||
throw new Error(`Diagram ${type} not found.`);
|
||||
throw new UnknownDiagramError(`Diagram ${type} not found.`);
|
||||
}
|
||||
// TODO: Uncomment for v10
|
||||
// // Diagram not available, loading it
|
||||
// const { diagram } = await loader();
|
||||
// registerDiagram(type, diagram, undefined, diagram.injectUtils);
|
||||
// // new diagram will try getDiagram again and if fails then it is a valid throw
|
||||
return loader().then(({ diagram }) => {
|
||||
registerDiagram(type, diagram, undefined);
|
||||
return new Diagram(txt, parseError);
|
||||
});
|
||||
// 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);
|
||||
}
|
||||
return new Diagram(txt, parseError);
|
||||
return new Diagram(txt);
|
||||
};
|
||||
|
||||
export default Diagram;
|
||||
|
@@ -7,6 +7,7 @@ import type {
|
||||
ExternalDiagramDefinition,
|
||||
} from './types';
|
||||
import { frontMatterRegex } from './frontmatter';
|
||||
import { UnknownDiagramError } from '../errors';
|
||||
|
||||
const directive = /%{2}{\s*(?:(\w+)\s*:|(\w+))\s*(?:(\w+)|((?:(?!}%{2}).|\r?\n)*))?\s*(?:}%{2})?/gi;
|
||||
const anyComment = /\s*%%.*\n/gm;
|
||||
@@ -44,7 +45,7 @@ export const detectType = function (text: string, config?: MermaidConfig): strin
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`No diagram type detected for text: ${text}`);
|
||||
throw new UnknownDiagramError(`No diagram type detected for text: ${text}`);
|
||||
};
|
||||
|
||||
export const registerLazyLoadedDiagrams = (...diagrams: ExternalDiagramDefinition[]) => {
|
||||
|
@@ -18,6 +18,7 @@ export interface DiagramDb {
|
||||
setDiagramTitle?: (title: string) => void;
|
||||
getAccTitle?: () => string;
|
||||
getAccDescription?: () => string;
|
||||
bindFunctions?: (element: Element) => void;
|
||||
}
|
||||
|
||||
export interface DiagramDefinition {
|
||||
|
@@ -348,19 +348,6 @@ export const setConf = function (cnf) {
|
||||
*/
|
||||
export const draw = function (text, id, _version, diagObj) {
|
||||
log.info('Drawing class - ', id);
|
||||
// diagObj.db.clear();
|
||||
// const parser = diagObj.db.parser;
|
||||
// parser.yy = classDb;
|
||||
|
||||
// Parse the graph definition
|
||||
// try {
|
||||
// parser.parse(text);
|
||||
// } catch (err) {
|
||||
// log.debug('Parsing failed');
|
||||
// }
|
||||
|
||||
// Fetch the default direction, use TD if none was found
|
||||
//let dir = 'TD';
|
||||
|
||||
const conf = getConfig().flowchart;
|
||||
const securityLevel = getConfig().securityLevel;
|
||||
@@ -384,15 +371,6 @@ export const draw = function (text, id, _version, diagObj) {
|
||||
return {};
|
||||
});
|
||||
|
||||
// let subG;
|
||||
// const subGraphs = flowDb.getSubGraphs();
|
||||
// log.info('Subgraphs - ', subGraphs);
|
||||
// for (let i = subGraphs.length - 1; i >= 0; i--) {
|
||||
// subG = subGraphs[i];
|
||||
// log.info('Subgraph - ', subG);
|
||||
// flowDb.addVertex(subG.id, subG.title, 'group', undefined, subG.classes);
|
||||
// }
|
||||
|
||||
// Fetch the vertices/nodes and edges/links from the parsed graph definition
|
||||
const classes = diagObj.db.getClasses();
|
||||
const relations = diagObj.db.getRelations();
|
||||
|
@@ -2,15 +2,12 @@
|
||||
import { select, selectAll } from 'd3';
|
||||
import svgDraw, { drawText, fixLifeLineHeights } from './svgDraw';
|
||||
import { log } from '../../logger';
|
||||
// import { parser } from './parser/sequenceDiagram';
|
||||
import common from '../common/common';
|
||||
// import sequenceDb from './sequenceDb';
|
||||
import * as configApi from '../../config';
|
||||
import assignWithDepth from '../../assignWithDepth';
|
||||
import utils from '../../utils';
|
||||
import { configureSvgSize } from '../../setupGraphViewbox';
|
||||
import Diagram from '../../Diagram';
|
||||
import { convert } from '../../tests/util';
|
||||
import { Diagram } from '../../Diagram';
|
||||
|
||||
let conf = {};
|
||||
|
||||
|
6
packages/mermaid/src/errors.ts
Normal file
6
packages/mermaid/src/errors.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export class UnknownDiagramError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = 'UnknownDiagramError';
|
||||
}
|
||||
}
|
@@ -7,7 +7,7 @@ import dedent from 'ts-dedent';
|
||||
import { MermaidConfig } from './config.type';
|
||||
import { log } from './logger';
|
||||
import utils from './utils';
|
||||
import { mermaidAPI } from './mermaidAPI';
|
||||
import { mermaidAPI, RenderResult } from './mermaidAPI';
|
||||
import { registerLazyLoadedDiagrams } from './diagram-api/detectType';
|
||||
import type { ParseErrorFunction } from './Diagram';
|
||||
import { isDetailedError } from './utils';
|
||||
@@ -44,10 +44,8 @@ export type { MermaidConfig, DetailedError, ExternalDiagramDefinition, ParseErro
|
||||
*/
|
||||
const init = async function (
|
||||
config?: MermaidConfig,
|
||||
// eslint-disable-next-line no-undef
|
||||
nodes?: string | HTMLElement | NodeListOf<HTMLElement>,
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
callback?: Function
|
||||
callback?: (id: string) => unknown
|
||||
) {
|
||||
try {
|
||||
await initThrowsErrors(config, nodes, callback);
|
||||
@@ -125,8 +123,7 @@ const loadExternalDiagrams = async (...diagrams: ExternalDiagramDefinition[]) =>
|
||||
const initThrowsErrors = async function (
|
||||
config?: MermaidConfig,
|
||||
nodes?: string | HTMLElement | NodeListOf<HTMLElement>,
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
callback?: Function
|
||||
callback?: (id: string) => unknown
|
||||
) {
|
||||
const conf = mermaidAPI.getConfig();
|
||||
|
||||
@@ -188,20 +185,14 @@ const initThrowsErrors = async function (
|
||||
log.debug('Detected early reinit: ', init);
|
||||
}
|
||||
try {
|
||||
await mermaidAPI.render(
|
||||
id,
|
||||
txt,
|
||||
(svgCode: string, bindFunctions?: (el: Element) => void) => {
|
||||
element.innerHTML = svgCode;
|
||||
if (callback !== undefined) {
|
||||
const { svg, bindFunctions } = await mermaidAPI.render(id, txt, element);
|
||||
element.innerHTML = svg;
|
||||
if (callback) {
|
||||
callback(id);
|
||||
}
|
||||
if (bindFunctions) {
|
||||
bindFunctions(element);
|
||||
}
|
||||
},
|
||||
element
|
||||
);
|
||||
} catch (error) {
|
||||
handleError(error, errors, mermaid.parseError);
|
||||
}
|
||||
@@ -296,15 +287,24 @@ const executeQueue = async () => {
|
||||
};
|
||||
|
||||
/**
|
||||
* @param txt - The mermaid code to be parsed.
|
||||
* 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.silent is true.
|
||||
* @throws Error if the diagram is invalid and parseOptions.silent is false.
|
||||
*/
|
||||
const parse = (txt: string): Promise<boolean> => {
|
||||
const parse = async (
|
||||
text: string,
|
||||
parseOptions?: {
|
||||
silent?: boolean;
|
||||
}
|
||||
): Promise<boolean | void> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
// This promise will resolve when the mermaidAPI.render call is done.
|
||||
// It will be queued first and will be executed when it is first in line
|
||||
const performCall = () =>
|
||||
new Promise((res, rej) => {
|
||||
mermaidAPI.parse(txt, mermaid.parseError).then(
|
||||
mermaidAPI.parse(text, parseOptions).then(
|
||||
(r) => {
|
||||
// This resolves for the promise for the queue handling
|
||||
res(r);
|
||||
@@ -313,6 +313,7 @@ const parse = (txt: string): Promise<boolean> => {
|
||||
},
|
||||
(e) => {
|
||||
log.error('Error parsing', e);
|
||||
mermaid.parseError?.(e);
|
||||
rej(e);
|
||||
reject(e);
|
||||
}
|
||||
@@ -323,18 +324,13 @@ const parse = (txt: string): Promise<boolean> => {
|
||||
});
|
||||
};
|
||||
|
||||
const render = (
|
||||
id: string,
|
||||
text: string,
|
||||
cb?: (svgCode: string, bindFunctions?: (element: Element) => void) => void,
|
||||
container?: Element
|
||||
): Promise<string> => {
|
||||
const render = (id: string, text: string, container?: Element): Promise<RenderResult> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
// This promise will resolve when the mermaidAPI.render call is done.
|
||||
// It will be queued first and will be executed when it is first in line
|
||||
const performCall = () =>
|
||||
new Promise((res, rej) => {
|
||||
mermaidAPI.render(id, text, cb, container).then(
|
||||
mermaidAPI.render(id, text, container).then(
|
||||
(r) => {
|
||||
// This resolves for the promise for the queue handling
|
||||
res(r);
|
||||
@@ -343,6 +339,7 @@ const render = (
|
||||
},
|
||||
(e) => {
|
||||
log.error('Error parsing', e);
|
||||
mermaid.parseError?.(e);
|
||||
rej(e);
|
||||
reject(e);
|
||||
}
|
||||
@@ -355,7 +352,6 @@ const render = (
|
||||
|
||||
const mermaid: {
|
||||
startOnLoad: boolean;
|
||||
diagrams: any;
|
||||
parseError?: ParseErrorFunction;
|
||||
mermaidAPI: typeof mermaidAPI;
|
||||
parse: typeof parse;
|
||||
@@ -368,7 +364,6 @@ const mermaid: {
|
||||
setParseErrorHandler: typeof setParseErrorHandler;
|
||||
} = {
|
||||
startOnLoad: true,
|
||||
diagrams: {},
|
||||
mermaidAPI,
|
||||
parse,
|
||||
render,
|
||||
|
@@ -17,11 +17,7 @@ import { compile, serialize, stringify } from 'stylis';
|
||||
import { version } from '../package.json';
|
||||
import * as configApi from './config';
|
||||
import { addDiagrams } from './diagram-api/diagram-orchestration';
|
||||
import classDb from './diagrams/class/classDb';
|
||||
import flowDb from './diagrams/flowchart/flowDb';
|
||||
import ganttDb from './diagrams/gantt/ganttDb';
|
||||
import Diagram, { getDiagramFromText } from './Diagram';
|
||||
import type { ParseErrorFunction } from './Diagram';
|
||||
import { Diagram, getDiagramFromText } from './Diagram';
|
||||
import errorRenderer from './diagrams/error/errorRenderer';
|
||||
import { attachFunctions } from './interactionDb';
|
||||
import { log, setLogLevel } from './logger';
|
||||
@@ -37,7 +33,7 @@ import { parseDirective } from './directiveUtils';
|
||||
|
||||
// diagram names that support classDef statements
|
||||
const CLASSDEF_DIAGRAMS = ['graph', 'flowchart', 'flowchart-v2', 'stateDiagram', 'stateDiagram-v2'];
|
||||
|
||||
const MAX_TEXTLENGTH = 50_000;
|
||||
const MAX_TEXTLENGTH_EXCEEDED_MSG =
|
||||
'graph TB;a[Maximum text size in diagram exceeded];style a fill:#faa';
|
||||
|
||||
@@ -74,16 +70,34 @@ interface DiagramStyleClassDef {
|
||||
// @ts-ignore Could replicate the type definition in d3. This also makes it possible to use the untyped info from the js diagram files.
|
||||
export type D3Element = any;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Parse the text and validate the syntax.
|
||||
* @param text - The mermaid diagram definition.
|
||||
* @param parseError - If set, handles errors.
|
||||
* @param parseOptions - Options for parsing.
|
||||
* @returns true if the diagram is valid, false otherwise if parseOptions.silent is true.
|
||||
* @throws Error if the diagram is invalid and parseOptions.silent is false.
|
||||
*/
|
||||
async function parse(text: string, parseError?: ParseErrorFunction): Promise<boolean> {
|
||||
|
||||
async function parse(
|
||||
text: string,
|
||||
parseOptions?: {
|
||||
silent?: boolean;
|
||||
}
|
||||
): Promise<boolean | void> {
|
||||
addDiagrams();
|
||||
const diagram = await getDiagramFromText(text, parseError);
|
||||
return diagram.parse(text, parseError);
|
||||
let error;
|
||||
try {
|
||||
const diagram = await getDiagramFromText(text);
|
||||
diagram.parse();
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
if (parseOptions?.silent) {
|
||||
return error === undefined;
|
||||
}
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -366,12 +380,16 @@ export const removeExistingElements = (
|
||||
* @returns Returns the rendered element as a string containing the SVG definition.
|
||||
*/
|
||||
|
||||
export interface RenderResult {
|
||||
svg: string;
|
||||
bindFunctions?: (element: Element) => void;
|
||||
}
|
||||
|
||||
const render = async function (
|
||||
id: string,
|
||||
text: string,
|
||||
cb?: (svgCode: string, bindFunctions?: (element: Element) => void) => void,
|
||||
svgContainingElement?: Element
|
||||
): Promise<string> {
|
||||
): Promise<RenderResult> {
|
||||
addDiagrams();
|
||||
|
||||
configApi.reset();
|
||||
@@ -387,8 +405,7 @@ const render = async function (
|
||||
log.debug(config);
|
||||
|
||||
// Check the maximum allowed text size
|
||||
// TODO: Remove magic number
|
||||
if (text.length > (config?.maxTextSize ?? 50000)) {
|
||||
if (text.length > (config?.maxTextSize ?? MAX_TEXTLENGTH)) {
|
||||
text = MAX_TEXTLENGTH_EXCEEDED_MSG;
|
||||
}
|
||||
|
||||
@@ -453,11 +470,10 @@ const render = async function (
|
||||
// Create the diagram
|
||||
|
||||
// Important that we do not create the diagram until after the directives have been included
|
||||
let diag;
|
||||
let diag: Diagram;
|
||||
let parseEncounteredException;
|
||||
|
||||
try {
|
||||
// diag = new Diagram(text);
|
||||
diag = await getDiagramFromText(text);
|
||||
} catch (error) {
|
||||
diag = new Diagram('error');
|
||||
@@ -510,7 +526,7 @@ const render = async function (
|
||||
root.select(`[id="${id}"]`).selectAll('foreignobject > *').attr('xmlns', XMLNS_XHTML_STD);
|
||||
|
||||
// Fix for when the base tag is used
|
||||
let svgCode = root.select(enclosingDivID_selector).node().innerHTML;
|
||||
let svgCode: string = root.select(enclosingDivID_selector).node().innerHTML;
|
||||
|
||||
log.debug('config.arrowMarkerAbsolute', config.arrowMarkerAbsolute);
|
||||
svgCode = cleanUpSvgCode(svgCode, isSandboxed, evaluate(config.arrowMarkerAbsolute));
|
||||
@@ -526,27 +542,6 @@ const render = async function (
|
||||
});
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// Do any callbacks (cb = callback)
|
||||
if (cb !== undefined) {
|
||||
switch (graphType) {
|
||||
case 'flowchart':
|
||||
case 'flowchart-v2':
|
||||
cb(svgCode, flowDb.bindFunctions);
|
||||
break;
|
||||
case 'gantt':
|
||||
cb(svgCode, ganttDb.bindFunctions);
|
||||
break;
|
||||
case 'class':
|
||||
case 'classDiagram':
|
||||
cb(svgCode, classDb.bindFunctions);
|
||||
break;
|
||||
default:
|
||||
cb(svgCode);
|
||||
}
|
||||
} else {
|
||||
log.debug('CB = undefined!');
|
||||
}
|
||||
attachFunctions();
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
@@ -561,7 +556,10 @@ const render = async function (
|
||||
throw parseEncounteredException;
|
||||
}
|
||||
|
||||
return svgCode;
|
||||
return {
|
||||
svg: svgCode,
|
||||
bindFunctions: diag.db.bindFunctions,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user