diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 8710d49aa..44b16532c 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,4 +1,4 @@ -blank_issues_enabled: false +blank_issues_enabled: true contact_links: - name: GitHub Discussions url: https://github.com/mermaid-js/mermaid/discussions diff --git a/.percy.yml b/.percy.yml deleted file mode 100644 index f56df3d5e..000000000 --- a/.percy.yml +++ /dev/null @@ -1,6 +0,0 @@ -version: 2 -snapshot: - widths: - - 1280 -discovery: - disable-cache: true diff --git a/.tern-project b/.tern-project deleted file mode 100644 index 1209b33da..000000000 --- a/.tern-project +++ /dev/null @@ -1,15 +0,0 @@ -{ - "ecmaVersion": 6, - "libs": ["browser"], - "loadEagerly": [], - "dontLoad": ["node_modules/**"], - "plugins": { - "modules": {}, - "es_modules": {}, - "node": {}, - "doc_comment": { - "fullDocs": true, - "strong": true - } - } -} diff --git a/.vite/build.ts b/.vite/build.ts index e3c947173..268db3270 100644 --- a/.vite/build.ts +++ b/.vite/build.ts @@ -62,12 +62,6 @@ export const getBuildConfig = ({ minify, core, watch, entryName }: BuildOptions) sourcemap: true, entryFileNames: `${name}.esm${minify ? '.min' : ''}.mjs`, }, - { - name, - format: 'umd', - sourcemap: true, - entryFileNames: `${name}${minify ? '.min' : ''}.js`, - }, ]; if (core) { diff --git a/.vite/server.ts b/.vite/server.ts index 0f1fef91d..82b75232d 100644 --- a/.vite/server.ts +++ b/.vite/server.ts @@ -1,27 +1,20 @@ -import express, { NextFunction, Request, Response } from 'express'; +import express from 'express'; +import cors from 'cors'; import { createServer as createViteServer } from 'vite'; -const cors = (req: Request, res: Response, next: NextFunction) => { - res.header('Access-Control-Allow-Origin', '*'); - res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE'); - res.header('Access-Control-Allow-Headers', 'Content-Type'); - - next(); -}; - async function createServer() { const app = express(); // Create Vite server in middleware mode const vite = await createViteServer({ configFile: './vite.config.ts', + mode: 'production', server: { middlewareMode: true }, appType: 'custom', // don't include Vite's default HTML handling middlewares }); - app.use(cors); + app.use(cors()); app.use(express.static('./packages/mermaid/dist')); - // app.use(express.static('./packages/mermaid-example-diagram/dist')); app.use(express.static('./packages/mermaid-example-diagram/dist')); app.use(vite.middlewares); app.use(express.static('demos')); diff --git a/CHANGELOG.md b/CHANGELOG.md index c5903cd91..7552efa3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,105 @@ -# Change Log +# Changelog -// TODO: Populate changelog +## [10.0.0](https://github.com/mermaid-js/mermaid/releases/tag/v10.0.0) + +### Mermaid is ESM only! + +We've dropped CJS support. So, you will have to update your import scripts as follows. + +```html + +``` + +You can keep using v9 by adding the `@9` in the CDN URL. + +```diff +- ++ +``` + +### mermaid.render is async and doesn't accept callbacks + +```js +// < v10 +mermaid.render('id', 'graph TD;\nA-->B', (svg, bindFunctions) => { + element.innerHTML = svg; + if (bindFunctions) { + bindFunctions(element); + } +}); + +// Shorter syntax +if (bindFunctions) { + bindFunctions(element); +} +// can be replaced with the `?.` shorthand +bindFunctions?.(element); + +// >= v10 with async/await +const { svg, bindFunctions } = await mermaid.render('id', 'graph TD;\nA-->B'); +element.innerHTML = svg; +bindFunctions?.(element); + +// >= v10 with promise.then +mermaid.render('id', 'graph TD;A-->B').then(({ svg, bindFunctions }) => { + element.innerHTML = svg; + bindFunctions?.(element); +}); +``` + +### mermaid.parse is async and ParseError is removed + +```js +// < v10 +mermaid.parse(text, parseError); + +//>= v10 +await mermaid.parse(text).catch(parseError); +// or +try { + await mermaid.parse(text); +} catch (err) { + parseError(err); +} +``` + +### Init deprecated and InitThrowsErrors removed + +The config passed to `init` was not being used eariler. +It will now be used. +The `init` function is deprecated and will be removed in the next major release. +init currently works as a wrapper to `initialize` and `run`. + +```js +// < v10 +mermaid.init(config, selector, cb); + +//>= v10 +mermaid.initialize(config); +mermaid.run({ + querySelector: selector, + postRenderCallback: cb, + suppressErrors: true, +}); +``` + +```js +// < v10 +mermaid.initThrowsErrors(config, selector, cb); + +//>= v10 +mermaid.initialize(config); +mermaid.run({ + querySelector: selector, + postRenderCallback: cb, + suppressErrors: false, +}); +``` + +// TODO: Populate changelog pre v10 - Config has a lot of changes - globalReset resets to `defaultConfig` instead of current config. Use `reset` instead. diff --git a/README.md b/README.md index f4cf8e105..d42e2f7e1 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Mermaid Generate diagrams from markdown-like text.

- +

diff --git a/README.zh-CN.md b/README.zh-CN.md index 65cf38645..2653ac72b 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -8,7 +8,7 @@ Mermaid 通过解析类 Markdown 的文本语法来实现图表的创建和动态修改。

- +

diff --git a/V10-BreakingChanges.md b/V10-BreakingChanges.md deleted file mode 100644 index bd9110d1a..000000000 --- a/V10-BreakingChanges.md +++ /dev/null @@ -1,5 +0,0 @@ -# A collection of updates that change the behaviour - -## Lazy loading and asynchronisity - -- Invalid dates are rendered as syntax error instead of returning best guess or the current date diff --git a/cSpell.json b/cSpell.json index 340954ba0..d860c5e33 100644 --- a/cSpell.json +++ b/cSpell.json @@ -28,6 +28,7 @@ "cuzon", "cytoscape", "dagre", + "deepdwn", "descr", "docsify", "docsy", diff --git a/cypress/integration/rendering/erDiagram.spec.js b/cypress/integration/rendering/erDiagram.spec.js index c72df49b6..df1fac0cd 100644 --- a/cypress/integration/rendering/erDiagram.spec.js +++ b/cypress/integration/rendering/erDiagram.spec.js @@ -188,7 +188,7 @@ describe('Entity Relationship Diagram', () => { erDiagram CLUSTER { varchar(99) name - string(255) description + string(255) description } `, { logLevel: 1 } diff --git a/cypress/integration/rendering/flowchart-elk.spec.js b/cypress/integration/rendering/flowchart-elk.spec.js index 0d4ec4211..414037651 100644 --- a/cypress/integration/rendering/flowchart-elk.spec.js +++ b/cypress/integration/rendering/flowchart-elk.spec.js @@ -1,6 +1,6 @@ import { imgSnapshotTest, renderGraph } from '../../helpers/util'; -describe('Flowchart ELK', () => { +describe.skip('Flowchart ELK', () => { it('1-elk: should render a simple flowchart', () => { imgSnapshotTest( `flowchart-elk TD diff --git a/cypress/integration/rendering/flowchart-v2.spec.js b/cypress/integration/rendering/flowchart-v2.spec.js index 30ae4f0d2..abdb22265 100644 --- a/cypress/integration/rendering/flowchart-v2.spec.js +++ b/cypress/integration/rendering/flowchart-v2.spec.js @@ -670,6 +670,17 @@ title: Simple flowchart --- flowchart TD A --> B +`, + { titleTopMargin: 0 } + ); + }); + it('3192: It should be possieble to render flowcharts with invisible edges', () => { + imgSnapshotTest( + `--- +title: Simple flowchart with invisible edges +--- +flowchart TD +A ~~~ B `, { titleTopMargin: 0 } ); diff --git a/cypress/integration/rendering/sequencediagram.spec.js b/cypress/integration/rendering/sequencediagram.spec.js index 1f063c13e..f8948240a 100644 --- a/cypress/integration/rendering/sequencediagram.spec.js +++ b/cypress/integration/rendering/sequencediagram.spec.js @@ -116,7 +116,11 @@ context('Sequence diagram', () => { loop Loopy Bob->>Alice: Pasten end `, - { wrap: true } + { + sequence: { + wrap: true, + }, + } ); }); context('font settings', () => { diff --git a/cypress/platform/bundle-test.js b/cypress/platform/bundle-test.js index a991918c4..edd3dfbc4 100644 --- a/cypress/platform/bundle-test.js +++ b/cypress/platform/bundle-test.js @@ -49,13 +49,9 @@ mermaid.initialize({ ], }, }); -mermaid.render( - 'the-id-of-the-svg', - code, - (svg) => { - console.log(svg); - const elem = document.querySelector('#graph-to-be'); - elem.innerHTML = svg; - } - // ,document.querySelector('#tmp') -); +void (async () => { + const { svg } = await mermaid.render('the-id-of-the-svg', code); + console.log(svg); + const elem = document.querySelector('#graph-to-be'); + elem.innerHTML = svg; +})(); diff --git a/cypress/platform/class.html b/cypress/platform/class.html index ea0914c6d..2f853bbc1 100644 --- a/cypress/platform/class.html +++ b/cypress/platform/class.html @@ -112,8 +112,8 @@ classE o-- classF : aggregation callback Shape "callbackFunction" "This is a tooltip for a callback" - - + diff --git a/cypress/platform/click_security_other.html b/cypress/platform/click_security_other.html index 5338cac06..7dc75ea88 100644 --- a/cypress/platform/click_security_other.html +++ b/cypress/platform/click_security_other.html @@ -59,8 +59,8 @@ Add another diagram to demo page : 48h - - - - - - - - - - - + diff --git a/cypress/platform/external-diagrams-example-diagram.html b/cypress/platform/external-diagrams-example-diagram.html index 9d2cad778..b5b716ff8 100644 --- a/cypress/platform/external-diagrams-example-diagram.html +++ b/cypress/platform/external-diagrams-example-diagram.html @@ -17,7 +17,7 @@ example-diagram await mermaid.registerExternalDiagrams([exampleDiagram]); await mermaid.initialize({ logLevel: 0 }); - await mermaid.initThrowsErrorsAsync(); + await mermaid.run(); if (window.Cypress) { window.rendered = true; } diff --git a/cypress/platform/flow.html b/cypress/platform/flow.html index ed70f80d0..0060ac3cb 100644 --- a/cypress/platform/flow.html +++ b/cypress/platform/flow.html @@ -29,8 +29,8 @@ click a_a "http://www.aftonbladet.se" "apa" - - + + diff --git a/cypress/platform/ghsa1.html b/cypress/platform/ghsa1.html index 59c316eb3..39e0ce848 100644 --- a/cypress/platform/ghsa1.html +++ b/cypress/platform/ghsa1.html @@ -8,18 +8,18 @@ - - - - diff --git a/cypress/platform/git-graph.html b/cypress/platform/git-graph.html index da6025f4b..4cb2656f1 100644 --- a/cypress/platform/git-graph.html +++ b/cypress/platform/git-graph.html @@ -43,8 +43,8 @@ cssClass "BankAccount" customCss - - - - - - - - + - -

Example

@@ -26,4 +16,12 @@ sequenceDiagram
     Note left of Ernie: Cookies are good
     
+ diff --git a/cypress/platform/render-after-error.html b/cypress/platform/render-after-error.html index f5165e0ee..2334158c2 100644 --- a/cypress/platform/render-after-error.html +++ b/cypress/platform/render-after-error.html @@ -9,19 +9,19 @@
- - diff --git a/cypress/platform/rerender.html b/cypress/platform/rerender.html index ab1b8e009..d9dbc4a5e 100644 --- a/cypress/platform/rerender.html +++ b/cypress/platform/rerender.html @@ -9,20 +9,20 @@
- - diff --git a/cypress/platform/showcase_base.html b/cypress/platform/showcase_base.html index 227d79cf7..32a2ae72a 100644 --- a/cypress/platform/showcase_base.html +++ b/cypress/platform/showcase_base.html @@ -313,8 +313,8 @@ requirementDiagram merge release - - - - - - - - - - - - - - diff --git a/cypress/platform/xss11.html b/cypress/platform/xss11.html index ca97aeaab..302f39ee9 100644 --- a/cypress/platform/xss11.html +++ b/cypress/platform/xss11.html @@ -49,8 +49,8 @@
- - diff --git a/cypress/platform/xss12.html b/cypress/platform/xss12.html index eb1bce327..b1e2c1d0a 100644 --- a/cypress/platform/xss12.html +++ b/cypress/platform/xss12.html @@ -49,8 +49,8 @@
- - diff --git a/cypress/platform/xss13.html b/cypress/platform/xss13.html index f2d90cddb..9f505ea7b 100644 --- a/cypress/platform/xss13.html +++ b/cypress/platform/xss13.html @@ -49,8 +49,8 @@
- - diff --git a/cypress/platform/xss14.html b/cypress/platform/xss14.html index f429b355a..e68b87b78 100644 --- a/cypress/platform/xss14.html +++ b/cypress/platform/xss14.html @@ -49,8 +49,8 @@
- - diff --git a/cypress/platform/xss15.html b/cypress/platform/xss15.html index 70ebe9f86..3fa6b7151 100644 --- a/cypress/platform/xss15.html +++ b/cypress/platform/xss15.html @@ -49,8 +49,8 @@
- - diff --git a/cypress/platform/xss16.html b/cypress/platform/xss16.html index 9325a70aa..6f8a734eb 100644 --- a/cypress/platform/xss16.html +++ b/cypress/platform/xss16.html @@ -49,8 +49,8 @@
- - diff --git a/cypress/platform/xss17.html b/cypress/platform/xss17.html index c498f3f3e..bd7e1c57e 100644 --- a/cypress/platform/xss17.html +++ b/cypress/platform/xss17.html @@ -49,8 +49,8 @@
- - diff --git a/cypress/platform/xss18.html b/cypress/platform/xss18.html index 3e9cfd35c..ccacfadbb 100644 --- a/cypress/platform/xss18.html +++ b/cypress/platform/xss18.html @@ -49,8 +49,8 @@
- - diff --git a/cypress/platform/xss19.html b/cypress/platform/xss19.html index ca747b39e..7966abb8c 100644 --- a/cypress/platform/xss19.html +++ b/cypress/platform/xss19.html @@ -49,8 +49,8 @@
- - diff --git a/cypress/platform/xss2.html b/cypress/platform/xss2.html index 18b4be6fc..da95e3797 100644 --- a/cypress/platform/xss2.html +++ b/cypress/platform/xss2.html @@ -48,8 +48,8 @@ Alice->>Bob: Hi Bob Bob->>Alice: Hi Alice - - - diff --git a/cypress/platform/xss21.html b/cypress/platform/xss21.html index b2f67cd93..7cfa17c9e 100644 --- a/cypress/platform/xss21.html +++ b/cypress/platform/xss21.html @@ -49,8 +49,8 @@
- - diff --git a/cypress/platform/xss22.html b/cypress/platform/xss22.html index d7e47cd02..50ff3b732 100644 --- a/cypress/platform/xss22.html +++ b/cypress/platform/xss22.html @@ -8,8 +8,8 @@ graph TD A --> B["<a href='javascript#9;t#colon;alert(document.location)'>AAA</a>"] - - diff --git a/cypress/platform/xss3.html b/cypress/platform/xss3.html index 78fabc4aa..f01aab37e 100644 --- a/cypress/platform/xss3.html +++ b/cypress/platform/xss3.html @@ -36,8 +36,8 @@ graph LR A --> B - - - diff --git a/cypress/platform/xss5.html b/cypress/platform/xss5.html index f87e65505..f7abf7a45 100644 --- a/cypress/platform/xss5.html +++ b/cypress/platform/xss5.html @@ -49,8 +49,8 @@
- - diff --git a/cypress/platform/xss6.html b/cypress/platform/xss6.html index bc0f78561..7d7ae18d1 100644 --- a/cypress/platform/xss6.html +++ b/cypress/platform/xss6.html @@ -49,8 +49,8 @@
- - diff --git a/cypress/platform/xss7.html b/cypress/platform/xss7.html index d8b2a7620..177b4342c 100644 --- a/cypress/platform/xss7.html +++ b/cypress/platform/xss7.html @@ -49,8 +49,8 @@
- - diff --git a/cypress/platform/xss8.html b/cypress/platform/xss8.html index cf2969f39..5852c2693 100644 --- a/cypress/platform/xss8.html +++ b/cypress/platform/xss8.html @@ -49,8 +49,8 @@
- - diff --git a/cypress/platform/xss9.html b/cypress/platform/xss9.html index 916f1506d..cf2ad1359 100644 --- a/cypress/platform/xss9.html +++ b/cypress/platform/xss9.html @@ -49,8 +49,8 @@
- - diff --git a/demos/c4context.html b/demos/c4context.html index e085e611c..cf358b550 100644 --- a/demos/c4context.html +++ b/demos/c4context.html @@ -217,8 +217,8 @@
- - - - diff --git a/demos/classchart.html b/demos/classchart.html index e8e48e482..b20dda2a3 100644 --- a/demos/classchart.html +++ b/demos/classchart.html @@ -154,8 +154,8 @@
- - - - - - - - - - - - ``` @@ -71,9 +75,6 @@ Example: ```html - - -
   graph LR
@@ -82,8 +83,7 @@ Example:
       B-->D(fa:fa-spinner);
     
@@ -95,11 +95,12 @@ An id attribute is also added to mermaid tags without one. Mermaid can load multiple diagrams, in the same page. -> Try it out, save this code as HTML and load it using any browser.(Except Internet Explorer, please don't use Internet Explorer.) +> Try it out, save this code as HTML and load it using any browser. +> (Except Internet Explorer, please don't use Internet Explorer.) ## Enabling Click Event and Tags in Nodes -A `securityLevel` configuration has to first be cleared, `securityLevel` sets the level of trust for the parsed diagrams and limits click functionality. This was introduce in version 8.2 as a security improvement, aimed at preventing malicious use. +A `securityLevel` configuration has to first be cleared. `securityLevel` sets the level of trust for the parsed diagrams and limits click functionality. This was introduce in version 8.2 as a security improvement, aimed at preventing malicious use. **It is the site owner's responsibility to discriminate between trustworthy and untrustworthy user-bases and we encourage the use of discretion.** @@ -107,7 +108,7 @@ A `securityLevel` configuration has to first be cleared, `securityLevel` sets th | Parameter | Description | Type | Required | Values | | ------------- | --------------------------------- | ------ | -------- | ------------------------------------------ | -| securityLevel | Level of trust for parsed diagram | String | Required | 'sandbox', 'strict', 'loose', 'antiscript' | +| securityLevel | Level of trust for parsed diagram | String | Optional | 'sandbox', 'strict', 'loose', 'antiscript' | Values: @@ -122,26 +123,17 @@ Values: **If you are taking responsibility for the diagram source security you can set the `securityLevel` to a value of your choosing . This allows clicks and tags are allowed.** -**To change `securityLevel`, you have to call `mermaidAPI.initialize`:** +**To change `securityLevel`, you have to call `mermaid.initialize`:** ```javascript -mermaidAPI.initialize({ +mermaid.initialize({ securityLevel: 'loose', }); ``` ### Labels out of bounds -If you use dynamically loaded fonts that are loaded through CSS, such as Google fonts, mermaid should wait for the -whole page to load (dom + assets, particularly the fonts file). - -```javascript -$(document).load(function () { - mermaid.initialize(); -}); -``` - -or +If you use dynamically loaded fonts that are loaded through CSS, such as fonts, mermaid should wait for the whole page to load (dom + assets, particularly the fonts file). ```javascript $(document).ready(function () { @@ -154,12 +146,54 @@ Not doing so will most likely result in mermaid rendering graphs that have label If your page has other fonts in its body those might be used instead of the mermaid font. Specifying the font in your styling is a workaround for this. ```css -div.mermaid { +pre.mermaid { font-family: 'trebuchet ms', verdana, arial; } ``` -### Calling `mermaid.init` +### Using `mermaid.run` + +mermaid.run was added in v10 and is the preferred way of handling more complex integration. +By default, `mermaid.run` will be called when the document is ready, rendering all elements with `class="mermaid"`. + +You can customize that behavior by calling `await mermaid.run()`. + +`mermaid.initialize({startOnLoad: false})` will prevent `mermaid.run` from being called automatically after load. + +Render all elements with querySelector ".someOtherClass" + +```js +mermaid.initialize({ startOnLoad: false }); +await mermaid.run({ + querySelector: '.someOtherClass', +}); +``` + +Render all elements passed as an array + +```js +mermaid.initialize({ startOnLoad: false }); +await mermaid.run({ + nodes: [document.getElementById('someId'), document.getElementById('anotherId')], +}); +await mermaid.run({ + nodes: document.querySelectorAll('.yetAnotherClass'), +}); +``` + +Render all `.mermaid` elements while suppressing any error + +```js +mermaid.initialize({ startOnLoad: false }); +await mermaid.run({ + suppressErrors: true, +}); +``` + +### Calling `mermaid.init` - Deprecated + +> **Warning** +> mermaid.init is deprecated in v10 and will be removed in v11. Please use mermaid.run instead. By default, `mermaid.init` will be called when the document is ready, finding all elements with `class="mermaid"`. If you are adding content after mermaid is loaded, or otherwise need @@ -192,25 +226,24 @@ mermaid fully supports webpack. Here is a [working demo](https://github.com/merm ## API usage -The main idea of the API is to be able to call a render function with the graph definition as a string. The render function -will render the graph and call a callback with the resulting SVG code. With this approach it is up to the site creator to -fetch the graph definition from the site (perhaps from a textarea), render it and place the graph somewhere in the site. +The main idea of the API is to be able to call a render function with the graph definition as a string. The render function will render the graph and call a callback with the resulting SVG code. With this approach it is up to the site creator to fetch the graph definition from the site (perhaps from a textarea), render it and place the graph somewhere in the site. The example below show an outline of how this could be used. The example just logs the resulting SVG to the JavaScript console. ```html ``` @@ -223,17 +256,17 @@ The example code below is an extract of what mermaid does when using the API. Th bind events to an SVG when using the API for rendering. ```javascript -const insertSvg = function (svgCode, bindFunctions) { - element.innerHTML = svgCode; - if (typeof callback !== 'undefined') { - callback(id); +// Example of using the bindFunctions +const drawDiagram = async function () { + element = document.querySelector('#graphDiv'); + const graphDefinition = 'graph TB\na-->b'; + const { svg, bindFunctions } = await mermaid.render('graphDiv', graphDefinition); + element.innerHTML = svg; + // This can also be written as `bindFunctions?.(element);` using the `?` shorthand. + if (bindFunctions) { + bindFunctions(element); } - bindFunctions(element); }; - -const id = 'theGraph'; - -mermaidAPI.render(id, txt, insertSvg, element); ``` 1. The graph is generated using the render call. @@ -331,8 +364,8 @@ The future proof way of setting the configuration is by using the initialization on what kind of integration you use. ```html - - diff --git a/docs/ecosystem/integrations.md b/docs/ecosystem/integrations.md index 33b6b966e..3db4a17bc 100644 --- a/docs/ecosystem/integrations.md +++ b/docs/ecosystem/integrations.md @@ -20,6 +20,7 @@ They also serve as proof of concept, for the variety of things that can be built - [Gitea](https://gitea.io) (**Native support**) - [Azure Devops](https://docs.microsoft.com/en-us/azure/devops/project/wiki/wiki-markdown-guidance?view=azure-devops#add-mermaid-diagrams-to-a-wiki-page) (**Native support**) - [Tuleap](https://docs.tuleap.org/user-guide/writing-in-tuleap.html#graphs) (**Native support**) +- [Deepdwn](https://billiam.itch.io/deepdwn) (**Native support**) - [Joplin](https://joplinapp.org) (**Native support**) - [Swimm](https://swimm.io) (**Native support**) - [Notion](https://notion.so) (**Native support**) @@ -188,3 +189,6 @@ They also serve as proof of concept, for the variety of things that can be built - [mermaid-server: Generate diagrams using a HTTP request](https://github.com/TomWright/mermaid-server) - [ExDoc](https://github.com/elixir-lang/ex_doc) - [Rendering Mermaid graphs](https://github.com/elixir-lang/ex_doc#rendering-mermaid-graphs) +- [NiceGUI: Let any browser be the frontend of your Python code](https://nicegui.io) + - [ui.mermaid(...)](https://nicegui.io/reference#mermaid_diagrams) + - [ui.markdown(..., extras=\['mermaid'\])](https://nicegui.io/reference#markdown_element) diff --git a/docs/intro/index.md b/docs/intro/index.md index e846e0a35..848df4301 100644 --- a/docs/intro/index.md +++ b/docs/intro/index.md @@ -249,7 +249,7 @@ To select a version: Replace `` with the desired version number. -Latest Version: +Latest Version: ## Deploying Mermaid @@ -267,7 +267,7 @@ To Deploy Mermaid: ```html ``` diff --git a/docs/intro/n00b-gettingStarted.md b/docs/intro/n00b-gettingStarted.md index 0826c32c0..f4fb69b90 100644 --- a/docs/intro/n00b-gettingStarted.md +++ b/docs/intro/n00b-gettingStarted.md @@ -103,7 +103,7 @@ When writing the .html file, we give two instructions inside the html code to th a. The mermaid code for the diagram we want to create. -b. The importing of mermaid library through the `mermaid.esm.js` or `mermaid.esm.min.mjs` and the `mermaid.initialize()` call, which dictates the appearance of diagrams and also starts the rendering process . +b. The importing of mermaid library through the `mermaid.esm.mjs` or `mermaid.esm.min.mjs` and the `mermaid.initialize()` call, which dictates the appearance of diagrams and also starts the rendering process . **a. The embedded mermaid diagram definition inside a `
`:**
 
@@ -128,14 +128,14 @@ b. The importing of mermaid library through the `mermaid.esm.js` or `mermaid.esm
 ```html
 
   
 
 ```
 
 **Notes**:
-Rendering in Mermaid is initialized by `mermaid.initialize()` call. You can place `mermaid.initialize()` inside `mermaid.min.js` for brevity. However, doing the opposite lets you control when it starts looking for `
`tags inside the web page with `mermaid.initialize()`. This is useful when you think that not all `
` tags may have loaded on the execution of `mermaid.min.js` file. +Rendering in Mermaid is initialized by `mermaid.initialize()` call. However, doing the opposite lets you control when it starts looking for `
` tags inside the web page with `mermaid.initialize()`. This is useful when you think that not all `
` tags may have loaded on the execution of `mermaid.esm.min.mjs` file.
 
 `startOnLoad` is one of the parameters that can be defined by `mermaid.initialize()`
 
@@ -143,10 +143,6 @@ Rendering in Mermaid is initialized by `mermaid.initialize()` call. You can plac
 | ----------- | --------------------------------- | ------- | ----------- |
 | startOnLoad | Toggle for Rendering upon loading | Boolean | true, false |
 
-### Adding external diagrams to mermaid
-
-Please refer to the [Mindmap](../syntax/mindmap.md?id=integrating-with-your-librarywebsite) section for more information.
-
 ### Working Examples
 
 **Here is a full working example of the mermaidAPI being called through the CDN:**
@@ -172,7 +168,7 @@ Please refer to the [Mindmap](../syntax/mindmap.md?id=integrating-with-your-libr
     
diff --git a/docs/syntax/flowchart.md b/docs/syntax/flowchart.md index fd0408c45..547847f54 100644 --- a/docs/syntax/flowchart.md +++ b/docs/syntax/flowchart.md @@ -391,6 +391,20 @@ flowchart LR A == text ==> B ``` +### An invisible link + +This can be a useful tool in some instances where you want to alter the default positioning of a node. + +```mermaid-example +flowchart LR + A ~~~ B +``` + +```mermaid +flowchart LR + A ~~~ B +``` + ### Chaining of links It is possible declare many links in the same line as per below: diff --git a/docs/syntax/mindmap.md b/docs/syntax/mindmap.md index 81649351a..ad8aab77f 100644 --- a/docs/syntax/mindmap.md +++ b/docs/syntax/mindmap.md @@ -262,7 +262,7 @@ You can still use the pre 9.4.0 method to add mermaid with mindmaps to a web pag ```html @@ -272,16 +272,8 @@ From version 9.4.0 you can simplify this code to: ```html ``` -or if you prefer not using the ESM package: - -```html - -``` - -Note that more complex integrations that use the **render** function directly need to use the **renderAsync** method instead in order to render mind maps. - You can also refer the implementation in the live editor [here](https://github.com/mermaid-js/mermaid-live-editor/blob/develop/src/lib/util/mermaid.ts) to see how the async loading is done. diff --git a/docs/syntax/timeline.md b/docs/syntax/timeline.md index 943f247a0..58b12313d 100644 --- a/docs/syntax/timeline.md +++ b/docs/syntax/timeline.md @@ -466,9 +466,9 @@ Timeline uses experimental lazy loading & async rendering features which could c You can use this method to add mermaid including the timeline diagram to a web page: ```html - + ``` -Note that more complex integrations that the **render** function directly need to use the **renderAsync** method instead in order to render timeline. - You can also refer the implementation in the live editor [here](https://github.com/mermaid-js/mermaid-live-editor/blob/develop/src/lib/util/mermaid.ts) to see how the async loading is done. diff --git a/package.json b/package.json index e05563f39..8e4c50118 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "test:watch": "vitest --watch", "test:coverage": "vitest --coverage", "prepublishOnly": "pnpm build && pnpm test", - "prepare": "concurrently \"husky install\" \"pnpm build\"", + "prepare": "husky install && pnpm build", "pre-commit": "lint-staged" }, "repository": { @@ -58,8 +58,9 @@ "@commitlint/cli": "^17.2.0", "@commitlint/config-conventional": "^17.2.0", "@cspell/eslint-plugin": "^6.14.2", + "@types/cors": "^2.8.13", "@types/eslint": "^8.4.10", - "@types/express": "^4.17.14", + "@types/express": "^4.17.17", "@types/js-yaml": "^4.0.5", "@types/jsdom": "^21.0.0", "@types/lodash": "^4.14.188", @@ -73,6 +74,7 @@ "@vitest/spy": "^0.28.4", "@vitest/ui": "^0.28.4", "concurrently": "^7.5.0", + "cors": "^2.8.5", "coveralls": "^3.1.1", "cypress": "^12.0.0", "cypress-image-snapshot": "^4.0.1", @@ -103,11 +105,11 @@ "prettier-plugin-jsdoc": "^0.4.2", "rimraf": "^4.0.0", "rollup-plugin-visualizer": "^5.8.3", - "start-server-and-test": "^1.14.0", + "start-server-and-test": "^1.15.4", "ts-node": "^10.9.1", "typescript": "^4.8.4", - "vite": "^4.0.0", - "vitest": "^0.28.4" + "vite": "^4.1.1", + "vitest": "^0.28.5" }, "volta": { "node": "18.14.0" diff --git a/packages/mermaid/README.md b/packages/mermaid/README.md deleted file mode 100644 index d453d2ec0..000000000 --- a/packages/mermaid/README.md +++ /dev/null @@ -1,346 +0,0 @@ -# mermaid - -[![Build CI Status](https://github.com/mermaid-js/mermaid/actions/workflows/build.yml/badge.svg)](https://github.com/mermaid-js/mermaid/actions/workflows/build.yml) [![NPM](https://img.shields.io/npm/v/mermaid)](https://www.npmjs.com/package/mermaid) [![npm minified gzipped bundle size](https://img.shields.io/bundlephobia/minzip/mermaid)](https://bundlephobia.com/package/mermaid) [![Coverage Status](https://coveralls.io/repos/github/mermaid-js/mermaid/badge.svg?branch=master)](https://coveralls.io/github/mermaid-js/mermaid?branch=master) [![CDN Status](https://img.shields.io/jsdelivr/npm/hm/mermaid)](https://www.jsdelivr.com/package/npm/mermaid) [![NPM](https://img.shields.io/npm/dm/mermaid)](https://www.npmjs.com/package/mermaid) [![Join our Slack!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=slack&label=slack)](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE) [![Twitter Follow](https://img.shields.io/twitter/follow/mermaidjs_?style=social)](https://twitter.com/mermaidjs_) - -English | [简体中文](./README.zh-CN.md) - - - -:trophy: **Mermaid was nominated and won the [JS Open Source Awards (2019)](https://osawards.com/javascript/2019) in the category "The most exciting use of technology"!!!** - -**Thanks to all involved, people committing pull requests, people answering questions! 🙏** - -Explore Mermaid.js in depth, with real-world examples, tips & tricks from the creator... The first official book on Mermaid is available for purchase. Check it out! - -## About - - - -Mermaid is a JavaScript-based diagramming and charting tool that uses Markdown-inspired text definitions and a renderer to create and modify complex diagrams. The main purpose of Mermaid is to help documentation catch up with development. - -> Doc-Rot is a Catch-22 that Mermaid helps to solve. - -Diagramming and documentation costs precious developer time and gets outdated quickly. -But not having diagrams or docs ruins productivity and hurts organizational learning.
-Mermaid addresses this problem by enabling users to create easily modifiable diagrams. It can also be made part of production scripts (and other pieces of code).
-
- -Mermaid allows even non-programmers to easily create detailed diagrams through the [Mermaid Live Editor](https://mermaid.live/).
-[Tutorials](./docs/Tutorials.md) has video tutorials. -Use Mermaid with your favorite applications, check out the list of [Integrations and Usages of Mermaid](./docs/integrations.md). - -You can also use Mermaid within [GitHub](https://github.blog/2022-02-14-include-diagrams-markdown-files-mermaid/) as well many of your other favorite applications—check out the list of [Integrations and Usages of Mermaid](./docs/integrations.md). - -For a more detailed introduction to Mermaid and some of its more basic uses, look to the [Beginner's Guide](./docs/n00b-overview.md), [Usage](./docs/usage.md) and [Tutorials](./docs/Tutorials.md). - -🌐 [CDN](https://www.jsdelivr.com/package/npm/mermaid) | 📖 [Documentation](https://mermaidjs.github.io) | 🙌 [Contribution](https://github.com/mermaid-js/mermaid/blob/develop/CONTRIBUTING.md) | 📜 [Changelog](./docs/CHANGELOG.md) - -In our release process we rely heavily on visual regression tests using [applitools](https://applitools.com/). Applitools is a great service which has been easy to use and integrate with our tests. - - - - - - - -## Examples - -**The following are some examples of the diagrams, charts and graphs that can be made using Mermaid. Click here to jump into the [text syntax](https://mermaid-js.github.io/mermaid/#/n00b-syntaxReference).** - - - -### Flowchart [docs - live editor] - -``` -flowchart LR - -A[Hard] -->|Text| B(Round) -B --> C{Decision} -C -->|One| D[Result 1] -C -->|Two| E[Result 2] -``` - -```mermaid -flowchart LR - -A[Hard] -->|Text| B(Round) -B --> C{Decision} -C -->|One| D[Result 1] -C -->|Two| E[Result 2] -``` - -### Sequence diagram [docs - live editor] - -``` -sequenceDiagram -Alice->>John: Hello John, how are you? -loop Healthcheck - John->>John: Fight against hypochondria -end -Note right of John: Rational thoughts! -John-->>Alice: Great! -John->>Bob: How about you? -Bob-->>John: Jolly good! -``` - -```mermaid -sequenceDiagram -Alice->>John: Hello John, how are you? -loop Healthcheck - John->>John: Fight against hypochondria -end -Note right of John: Rational thoughts! -John-->>Alice: Great! -John->>Bob: How about you? -Bob-->>John: Jolly good! -``` - -### Gantt chart [docs - live editor] - -``` -gantt - section Section - Completed :done, des1, 2014-01-06,2014-01-08 - Active :active, des2, 2014-01-07, 3d - Parallel 1 : des3, after des1, 1d - Parallel 2 : des4, after des1, 1d - Parallel 3 : des5, after des3, 1d - Parallel 4 : des6, after des4, 1d -``` - -```mermaid -gantt - section Section - Completed :done, des1, 2014-01-06,2014-01-08 - Active :active, des2, 2014-01-07, 3d - Parallel 1 : des3, after des1, 1d - Parallel 2 : des4, after des1, 1d - Parallel 3 : des5, after des3, 1d - Parallel 4 : des6, after des4, 1d -``` - -### Class diagram [docs - live editor] - -``` -classDiagram -Class01 <|-- AveryLongClass : Cool -<> Class01 -Class09 --> C2 : Where am I? -Class09 --* C3 -Class09 --|> Class07 -Class07 : equals() -Class07 : Object[] elementData -Class01 : size() -Class01 : int chimp -Class01 : int gorilla -class Class10 { - <> - int id - size() -} -``` - -```mermaid -classDiagram -Class01 <|-- AveryLongClass : Cool -<> Class01 -Class09 --> C2 : Where am I? -Class09 --* C3 -Class09 --|> Class07 -Class07 : equals() -Class07 : Object[] elementData -Class01 : size() -Class01 : int chimp -Class01 : int gorilla -class Class10 { - <> - int id - size() -} -``` - -### State diagram [docs - live editor] - -``` -stateDiagram-v2 -[*] --> Still -Still --> [*] -Still --> Moving -Moving --> Still -Moving --> Crash -Crash --> [*] -``` - -```mermaid -stateDiagram-v2 -[*] --> Still -Still --> [*] -Still --> Moving -Moving --> Still -Moving --> Crash -Crash --> [*] -``` - -### Pie chart [docs - live editor] - -``` -pie -"Dogs" : 386 -"Cats" : 85.9 -"Rats" : 15 -``` - -```mermaid -pie -"Dogs" : 386 -"Cats" : 85.9 -"Rats" : 15 -``` - -### Git graph [experimental - live editor] - -### User Journey diagram [docs - live editor] - -``` - journey - title My working day - section Go to work - Make tea: 5: Me - Go upstairs: 3: Me - Do work: 1: Me, Cat - section Go home - Go downstairs: 5: Me - Sit down: 3: Me -``` - -```mermaid - journey - title My working day - section Go to work - Make tea: 5: Me - Go upstairs: 3: Me - Do work: 1: Me, Cat - section Go home - Go downstairs: 5: Me - Sit down: 3: Me -``` - -### C4 diagram [docs] - -``` -C4Context -title System Context diagram for Internet Banking System - -Person(customerA, "Banking Customer A", "A customer of the bank, with personal bank accounts.") -Person(customerB, "Banking Customer B") -Person_Ext(customerC, "Banking Customer C") -System(SystemAA, "Internet Banking System", "Allows customers to view information about their bank accounts, and make payments.") - -Person(customerD, "Banking Customer D", "A customer of the bank,
with personal bank accounts.") - -Enterprise_Boundary(b1, "BankBoundary") { - - SystemDb_Ext(SystemE, "Mainframe Banking System", "Stores all of the core banking information about customers, accounts, transactions, etc.") - - System_Boundary(b2, "BankBoundary2") { - System(SystemA, "Banking System A") - System(SystemB, "Banking System B", "A system of the bank, with personal bank accounts.") - } - - System_Ext(SystemC, "E-mail system", "The internal Microsoft Exchange e-mail system.") - SystemDb(SystemD, "Banking System D Database", "A system of the bank, with personal bank accounts.") - - Boundary(b3, "BankBoundary3", "boundary") { - SystemQueue(SystemF, "Banking System F Queue", "A system of the bank, with personal bank accounts.") - SystemQueue_Ext(SystemG, "Banking System G Queue", "A system of the bank, with personal bank accounts.") - } -} - -BiRel(customerA, SystemAA, "Uses") -BiRel(SystemAA, SystemE, "Uses") -Rel(SystemAA, SystemC, "Sends e-mails", "SMTP") -Rel(SystemC, customerA, "Sends e-mails to") -``` - -```mermaid -C4Context -title System Context diagram for Internet Banking System - -Person(customerA, "Banking Customer A", "A customer of the bank, with personal bank accounts.") -Person(customerB, "Banking Customer B") -Person_Ext(customerC, "Banking Customer C") -System(SystemAA, "Internet Banking System", "Allows customers to view information about their bank accounts, and make payments.") - -Person(customerD, "Banking Customer D", "A customer of the bank,
with personal bank accounts.") - -Enterprise_Boundary(b1, "BankBoundary") { - - SystemDb_Ext(SystemE, "Mainframe Banking System", "Stores all of the core banking information about customers, accounts, transactions, etc.") - - System_Boundary(b2, "BankBoundary2") { - System(SystemA, "Banking System A") - System(SystemB, "Banking System B", "A system of the bank, with personal bank accounts.") - } - - System_Ext(SystemC, "E-mail system", "The internal Microsoft Exchange e-mail system.") - SystemDb(SystemD, "Banking System D Database", "A system of the bank, with personal bank accounts.") - - Boundary(b3, "BankBoundary3", "boundary") { - SystemQueue(SystemF, "Banking System F Queue", "A system of the bank, with personal bank accounts.") - SystemQueue_Ext(SystemG, "Banking System G Queue", "A system of the bank, with personal bank accounts.") - } -} - -BiRel(customerA, SystemAA, "Uses") -BiRel(SystemAA, SystemE, "Uses") -Rel(SystemAA, SystemC, "Sends e-mails", "SMTP") -Rel(SystemC, customerA, "Sends e-mails to") -``` - -## Release - -For those who have the permission to do so: - -Update version number in `package.json`. - -```sh -npm publish -``` - -The above command generates files into the `dist` folder and publishes them to npmjs.org. - -## Related projects - -- [Command Line Interface](https://github.com/mermaid-js/mermaid-cli) -- [Live Editor](https://github.com/mermaid-js/mermaid-live-editor) -- [HTTP Server](https://github.com/TomWright/mermaid-server) - -## Contributors [![Good first issue](https://img.shields.io/github/labels/mermaid-js/mermaid/Good%20first%20issue%21)](https://github.com/mermaid-js/mermaid/issues?q=is%3Aissue+is%3Aopen+label%3A%22Good+first+issue%21%22) [![Contributors](https://img.shields.io/github/contributors/mermaid-js/mermaid)](https://github.com/mermaid-js/mermaid/graphs/contributors) [![Commits](https://img.shields.io/github/commit-activity/m/mermaid-js/mermaid)](https://github.com/mermaid-js/mermaid/graphs/contributors) - -Mermaid is a growing community and is always accepting new contributors. There's a lot of different ways to help out and we're always looking for extra hands! Look at [this issue](https://github.com/mermaid-js/mermaid/issues/866) if you want to know where to start helping out. - -Detailed information about how to contribute can be found in the [contribution guide](CONTRIBUTING.md) - -## Security and safe diagrams - -For public sites, it can be precarious to retrieve text from users on the internet, storing that content for presentation in a browser at a later stage. The reason is that the user content can contain embedded malicious scripts that will run when the data is presented. For Mermaid this is a risk, specially as mermaid diagrams contain many characters that are used in html which makes the standard sanitation unusable as it also breaks the diagrams. We still make an effort to sanitise the incoming code and keep refining the process but it is hard to guarantee that there are no loop holes. - -As an extra level of security for sites with external users we are happy to introduce a new security level in which the diagram is rendered in a sandboxed iframe preventing javascript in the code from being executed. This is a great step forward for better security. - -_Unfortunately you can not have a cake and eat it at the same time which in this case means that some of the interactive functionality gets blocked along with the possible malicious code._ - -## Reporting vulnerabilities - -To report a vulnerability, please e-mail security@mermaid.live with a description of the issue, the steps you took to create the issue, affected versions, and if known, mitigations for the issue. - -## Appreciation - -A quick note from Knut Sveidqvist: - -> _Many thanks to the [d3](https://d3js.org/) and [dagre-d3](https://github.com/cpettitt/dagre-d3) projects for providing the graphical layout and drawing libraries!_ >_Thanks also to the [js-sequence-diagram](https://bramp.github.io/js-sequence-diagrams) project for usage of the grammar for the sequence diagrams. Thanks to Jessica Peter for inspiration and starting point for gantt rendering._ >_Thank you to [Tyler Long](https://github.com/tylerlong) who has been a collaborator since April 2017._ -> -> _Thank you to the ever-growing list of [contributors](https://github.com/knsv/mermaid/graphs/contributors) that brought the project this far!_ - ---- - -_Mermaid was created by Knut Sveidqvist for easier documentation._ diff --git a/packages/mermaid/README.zh-CN.md b/packages/mermaid/README.zh-CN.md deleted file mode 100644 index 3612ba0a9..000000000 --- a/packages/mermaid/README.zh-CN.md +++ /dev/null @@ -1,334 +0,0 @@ -# mermaid - -[![Build CI Status](https://github.com/mermaid-js/mermaid/actions/workflows/build.yml/badge.svg)](https://github.com/mermaid-js/mermaid/actions/workflows/build.yml) [![NPM](https://img.shields.io/npm/v/mermaid)](https://www.npmjs.com/package/mermaid) [![npm minified gzipped bundle size](https://img.shields.io/bundlephobia/minzip/mermaid)](https://bundlephobia.com/package/mermaid) [![Coverage Status](https://coveralls.io/repos/github/mermaid-js/mermaid/badge.svg?branch=master)](https://coveralls.io/github/mermaid-js/mermaid?branch=master) [![CDN Status](https://img.shields.io/jsdelivr/npm/hm/mermaid)](https://www.jsdelivr.com/package/npm/mermaid) [![NPM](https://img.shields.io/npm/dm/mermaid)](https://www.npmjs.com/package/mermaid) [![Join our Slack!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=slack&label=slack)](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE) [![Twitter Follow](https://img.shields.io/twitter/follow/mermaidjs_?style=social)](https://twitter.com/mermaidjs_) - -[English](./README.md) | 简体中文 - - - -:trophy: **Mermaid 被提名并获得了 [JS Open Source Awards (2019)](https://osawards.com/javascript/2019) 的 "The most exciting use of technology" 奖项!!!** - -**感谢所有参与进来提交 PR,解答疑问的人们! 🙏** - -Explore Mermaid.js in depth, with real-world examples, tips & tricks from the creator... The first official book on Mermaid is available for purchase. Check it out! - -## 关于 Mermaid - - - -Mermaid 是一个基于 Javascript 的图表绘制工具,通过解析类 Markdown 的文本语法来实现图表的创建和动态修改。Mermaid 诞生的主要目的是让文档的更新能够及时跟上开发进度。 - -> Doc-Rot 是 Mermaid 致力于解决的一个难题。 - -绘图和编写文档花费了开发者宝贵的开发时间,而且随着业务的变更,它很快就会过期。 但是如果缺少了图表或文档,对于生产力和团队新人的业务学习都会产生巨大的阻碍。
-Mermaid 通过允许用户创建便于修改的图表来解决这一难题,它也可以作为生产脚本(或其他代码)的一部分。
-
-Mermaid 甚至能让非程序员也能通过 [Mermaid Live Editor](https://mermaid.live/) 轻松创建详细的图表。
-你可以访问 [教程](./docs/Tutorials.md) 来查看 Live Editor 的视频教程,也可以查看 [Mermaid 的集成和使用](./docs/integrations.md) 这个清单来检查你的文档工具是否已经集成了 Mermaid 支持。 - -如果想要查看关于 Mermaid 更详细的介绍及基础使用方式,可以查看 [入门指引](./docs/n00b-overview.md), [用法](./docs/usage.md) 和 [教程](./docs/Tutorials.md). - -🌐 [CDN](https://www.jsdelivr.com/package/npm/mermaid) | 📖 [文档](https://mermaidjs.github.io) | 🙌 [贡献](https://github.com/mermaid-js/mermaid/blob/develop/CONTRIBUTING.md) | 📜 [更新日志](./docs/CHANGELOG.md) - - - -## 示例 - -**下面是一些可以使用 Mermaid 创建的图表示例。点击 [语法](https://mermaid-js.github.io/mermaid/#/n00b-syntaxReference) 查看详情。** - - - - -### 流程图 [文档 - live editor] - -``` -flowchart LR -A[Hard] -->|Text| B(Round) -B --> C{Decision} -C -->|One| D[Result 1] -C -->|Two| E[Result 2] -``` - -```mermaid -flowchart LR -A[Hard] -->|Text| B(Round) -B --> C{Decision} -C -->|One| D[Result 1] -C -->|Two| E[Result 2] -``` - -### 时序图 [文档 - live editor] - -``` -sequenceDiagram -Alice->>John: Hello John, how are you? -loop Healthcheck - John->>John: Fight against hypochondria -end -Note right of John: Rational thoughts! -John-->>Alice: Great! -John->>Bob: How about you? -Bob-->>John: Jolly good! -``` - -```mermaid -sequenceDiagram -Alice->>John: Hello John, how are you? -loop Healthcheck - John->>John: Fight against hypochondria -end -Note right of John: Rational thoughts! -John-->>Alice: Great! -John->>Bob: How about you? -Bob-->>John: Jolly good! -``` - -### 甘特图 [文档 - live editor] - -``` -gantt - section Section - Completed :done, des1, 2014-01-06,2014-01-08 - Active :active, des2, 2014-01-07, 3d - Parallel 1 : des3, after des1, 1d - Parallel 2 : des4, after des1, 1d - Parallel 3 : des5, after des3, 1d - Parallel 4 : des6, after des4, 1d -``` - -```mermaid -gantt - section Section - Completed :done, des1, 2014-01-06,2014-01-08 - Active :active, des2, 2014-01-07, 3d - Parallel 1 : des3, after des1, 1d - Parallel 2 : des4, after des1, 1d - Parallel 3 : des5, after des3, 1d - Parallel 4 : des6, after des4, 1d -``` - -### 类图 [文档 - live editor] - -``` -classDiagram -Class01 <|-- AveryLongClass : Cool -<> Class01 -Class09 --> C2 : Where am I? -Class09 --* C3 -Class09 --|> Class07 -Class07 : equals() -Class07 : Object[] elementData -Class01 : size() -Class01 : int chimp -Class01 : int gorilla -class Class10 { - <> - int id - size() -} -``` - -```mermaid -classDiagram -Class01 <|-- AveryLongClass : Cool -<> Class01 -Class09 --> C2 : Where am I? -Class09 --* C3 -Class09 --|> Class07 -Class07 : equals() -Class07 : Object[] elementData -Class01 : size() -Class01 : int chimp -Class01 : int gorilla -class Class10 { - <> - int id - size() -} -``` - -### 状态图 [[docs - live editor] - -``` -stateDiagram-v2 -[*] --> Still -Still --> [*] -Still --> Moving -Moving --> Still -Moving --> Crash -Crash --> [*] -``` - -```mermaid -stateDiagram-v2 -[*] --> Still -Still --> [*] -Still --> Moving -Moving --> Still -Moving --> Crash -Crash --> [*] -``` - -### 饼图 [文档 - live editor] - -``` -pie -"Dogs" : 386 -"Cats" : 85 -"Rats" : 15 -``` - -```mermaid -pie -"Dogs" : 386 -"Cats" : 85 -"Rats" : 15 -``` - -### Git 图 [实验特性 - live editor] - -### 用户体验旅程图 [文档 - live editor] - -``` - journey - title My working day - section Go to work - Make tea: 5: Me - Go upstairs: 3: Me - Do work: 1: Me, Cat - section Go home - Go downstairs: 5: Me - Sit down: 3: Me -``` - -```mermaid - journey - title My working day - section Go to work - Make tea: 5: Me - Go upstairs: 3: Me - Do work: 1: Me, Cat - section Go home - Go downstairs: 5: Me - Sit down: 3: Me -``` - -### C4 图 [文档] - -``` -C4Context -title System Context diagram for Internet Banking System - -Person(customerA, "Banking Customer A", "A customer of the bank, with personal bank accounts.") -Person(customerB, "Banking Customer B") -Person_Ext(customerC, "Banking Customer C") -System(SystemAA, "Internet Banking System", "Allows customers to view information about their bank accounts, and make payments.") - -Person(customerD, "Banking Customer D", "A customer of the bank,
with personal bank accounts.") - -Enterprise_Boundary(b1, "BankBoundary") { - - SystemDb_Ext(SystemE, "Mainframe Banking System", "Stores all of the core banking information about customers, accounts, transactions, etc.") - - System_Boundary(b2, "BankBoundary2") { - System(SystemA, "Banking System A") - System(SystemB, "Banking System B", "A system of the bank, with personal bank accounts.") - } - - System_Ext(SystemC, "E-mail system", "The internal Microsoft Exchange e-mail system.") - SystemDb(SystemD, "Banking System D Database", "A system of the bank, with personal bank accounts.") - - Boundary(b3, "BankBoundary3", "boundary") { - SystemQueue(SystemF, "Banking System F Queue", "A system of the bank, with personal bank accounts.") - SystemQueue_Ext(SystemG, "Banking System G Queue", "A system of the bank, with personal bank accounts.") - } -} - -BiRel(customerA, SystemAA, "Uses") -BiRel(SystemAA, SystemE, "Uses") -Rel(SystemAA, SystemC, "Sends e-mails", "SMTP") -Rel(SystemC, customerA, "Sends e-mails to") -``` - -```mermaid -C4Context -title System Context diagram for Internet Banking System - -Person(customerA, "Banking Customer A", "A customer of the bank, with personal bank accounts.") -Person(customerB, "Banking Customer B") -Person_Ext(customerC, "Banking Customer C") -System(SystemAA, "Internet Banking System", "Allows customers to view information about their bank accounts, and make payments.") - -Person(customerD, "Banking Customer D", "A customer of the bank,
with personal bank accounts.") - -Enterprise_Boundary(b1, "BankBoundary") { - - SystemDb_Ext(SystemE, "Mainframe Banking System", "Stores all of the core banking information about customers, accounts, transactions, etc.") - - System_Boundary(b2, "BankBoundary2") { - System(SystemA, "Banking System A") - System(SystemB, "Banking System B", "A system of the bank, with personal bank accounts.") - } - - System_Ext(SystemC, "E-mail system", "The internal Microsoft Exchange e-mail system.") - SystemDb(SystemD, "Banking System D Database", "A system of the bank, with personal bank accounts.") - - Boundary(b3, "BankBoundary3", "boundary") { - SystemQueue(SystemF, "Banking System F Queue", "A system of the bank, with personal bank accounts.") - SystemQueue_Ext(SystemG, "Banking System G Queue", "A system of the bank, with personal bank accounts.") - } -} - -BiRel(customerA, SystemAA, "Uses") -BiRel(SystemAA, SystemE, "Uses") -Rel(SystemAA, SystemC, "Sends e-mails", "SMTP") -Rel(SystemC, customerA, "Sends e-mails to") -``` - -## 发布 - -对于有权限的同学来说,你可以通过以下步骤来完成发布操作: - -更新 `package.json` 中的版本号,然后执行如下命令: - -```sh -npm publish -``` - -以上的命令会将文件打包到 `dist` 目录并发布至 npmjs.org. - -## 相关项目 - -- [Command Line Interface](https://github.com/mermaid-js/mermaid-cli) -- [Live Editor](https://github.com/mermaid-js/mermaid-live-editor) -- [HTTP Server](https://github.com/TomWright/mermaid-server) - -## 贡献者 [![Good first issue](https://img.shields.io/github/labels/mermaid-js/mermaid/Good%20first%20issue%21)](https://github.com/mermaid-js/mermaid/issues?q=is%3Aissue+is%3Aopen+label%3A%22Good+first+issue%21%22) [![Contributors](https://img.shields.io/github/contributors/mermaid-js/mermaid)](https://github.com/mermaid-js/mermaid/graphs/contributors) [![Commits](https://img.shields.io/github/commit-activity/m/mermaid-js/mermaid)](https://github.com/mermaid-js/mermaid/graphs/contributors) - -Mermaid 是一个不断发展中的社区,并且还在接收新的贡献者。有很多不同的方式可以参与进来,而且我们还在寻找额外的帮助。如果你想知道如何开始贡献,请查看 [这个 issue](https://github.com/mermaid-js/mermaid/issues/866)。 - -关于如何贡献的详细信息可以在 [贡献指南](CONTRIBUTING.md) 中找到。 - -## 安全 - -对于公开网站来说,从互联网上的用户处检索文本、存储供后续在浏览器中展示的内容可能是不安全的,理由是用户的内容可能嵌入一些数据加载完成之后就会运行的恶意脚本,这些对于 Mermaid 来说毫无疑问是一个风险,尤其是 mermaid 图表还包含了许多在 html 中使用的字符,这意味着我们难以使用常规的手段来过滤不安全代码,因为这些常规手段会造成图表损坏。我们仍然在努力对获取到的代码进行安全过滤并不断完善我们的程序,但很难保证没有漏洞。 - -作为拥有外部用户的网站的额外安全级别,我们很高兴推出一个新的安全级别,其中的图表在沙盒 iframe 中渲染,防止代码中的 javascript 被执行,这是在安全性方面迈出的一大步。 - -_很不幸的是,鱼与熊掌不可兼得,在这个场景下它意味着在可能的恶意代码被阻止时,也会损失部分交互能力_。 - -## 报告漏洞 - -如果想要报告漏洞,请发送邮件到 security@mermaid.live, 并附上问题的描述、复现问题的步骤、受影响的版本,以及解决问题的方案(如果有的话)。 - -## 鸣谢 - -来自 Knut Sveidqvist: - -> _特别感谢 [d3](https://d3js.org/) 和 [dagre-d3](https://github.com/cpettitt/dagre-d3) 这两个优秀的项目,它们提供了图形布局和绘图工具库! _ >_同样感谢 [js-sequence-diagram](https://bramp.github.io/js-sequence-diagrams) 提供了时序图语法的使用。 感谢 Jessica Peter 提供了甘特图渲染的灵感。_ >_感谢 [Tyler Long](https://github.com/tylerlong) 从 2017 年四月开始成为了项目的合作者。_ -> -> _感谢越来越多的 [贡献者们](https://github.com/knsv/mermaid/graphs/contributors),没有你们,就没有这个项目的今天!_ - ---- - -_Mermaid 是由 Knut Sveidqvist 创建,它为了更简单的文档编写而生。_ diff --git a/packages/mermaid/package.json b/packages/mermaid/package.json index e4480286f..9fdef30b4 100644 --- a/packages/mermaid/package.json +++ b/packages/mermaid/package.json @@ -1,15 +1,14 @@ { "name": "mermaid", - "version": "9.4.0", + "version": "10.0.0", "description": "Markdown-ish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.", - "main": "./dist/mermaid.min.js", + "type": "module", "module": "./dist/mermaid.core.mjs", "types": "./dist/mermaid.d.ts", "exports": { ".": { - "require": "./dist/mermaid.min.js", - "import": "./dist/mermaid.core.mjs", - "types": "./dist/mermaid.d.ts" + "types": "./dist/mermaid.d.ts", + "import": "./dist/mermaid.core.mjs" }, "./*": "./*" }, @@ -56,13 +55,13 @@ "cytoscape": "^3.23.0", "cytoscape-cose-bilkent": "^4.1.0", "cytoscape-fcose": "^2.1.0", - "d3": "^7.0.0", + "d3": "^7.4.0", "dagre-d3-es": "7.0.8", "dompurify": "2.4.3", "elkjs": "^0.8.2", "khroma": "^2.0.0", "lodash-es": "^4.17.21", - "moment": "^2.29.4", + "moment-mini": "^2.29.4", "non-layered-tidy-tree-layout": "^2.0.2", "stylis": "^4.1.2", "ts-dedent": "^2.2.0", @@ -109,8 +108,5 @@ "dist", "README.md" ], - "sideEffects": [ - "**/*.css", - "**/*.scss" - ] + "sideEffects": false } diff --git a/packages/mermaid/src/Diagram.ts b/packages/mermaid/src/Diagram.ts index 1f68e52ba..1e7539aeb 100644 --- a/packages/mermaid/src/Diagram.ts +++ b/packages/mermaid/src/Diagram.ts @@ -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.db.clear?.(); + 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,30 +68,20 @@ export class Diagram { } } -export const getDiagramFromText = ( - txt: string, - parseError?: ParseErrorFunction -): Diagram | Promise => { - const type = detectType(txt, configApi.getConfig()); +export const getDiagramFromText = async (text: string): Promise => { + const type = detectType(text, configApi.getConfig()); try { // Trying to find the diagram getDiagram(type); } 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(text); }; - -export default Diagram; diff --git a/packages/mermaid/src/__mocks__/mermaidAPI.ts b/packages/mermaid/src/__mocks__/mermaidAPI.ts index 12c1652bc..95b87d990 100644 --- a/packages/mermaid/src/__mocks__/mermaidAPI.ts +++ b/packages/mermaid/src/__mocks__/mermaidAPI.ts @@ -5,24 +5,14 @@ */ import * as configApi from '../config'; import { vi } from 'vitest'; -import { addDiagrams } from '../diagram-api/diagram-orchestration'; -import Diagram, { type ParseErrorFunction } from '../Diagram'; - -// Normally, we could just do the following to get the original `parse()` -// implementation, however, requireActual returns a promise and it's not documented how to use withing mock file. - -/** {@inheritDoc mermaidAPI.parse} */ -function parse(text: string, parseError?: ParseErrorFunction): boolean { - addDiagrams(); - const diagram = new Diagram(text, parseError); - return diagram.parse(text, parseError); -} +import { mermaidAPI as mAPI } from '../mermaidAPI'; // original version cannot be modified since it was frozen with `Object.freeze()` export const mermaidAPI = { - render: vi.fn(), - renderAsync: vi.fn(), - parse, + render: vi.fn().mockResolvedValue({ + svg: '', + }), + parse: mAPI.parse, parseDirective: vi.fn(), initialize: vi.fn(), getConfig: configApi.getConfig, diff --git a/packages/mermaid/src/config.ts b/packages/mermaid/src/config.ts index 8750c8fa5..bc0066cec 100644 --- a/packages/mermaid/src/config.ts +++ b/packages/mermaid/src/config.ts @@ -243,6 +243,7 @@ const checkConfig = (config: MermaidConfig) => { if (!config) { return; } + // @ts-expect-error Properties were removed in v10. Warning should exist. if (config.lazyLoadedDiagrams || config.loadExternalDiagramsAtStartup) { issueWarning('LAZY_LOAD_DEPRECATED'); } diff --git a/packages/mermaid/src/config.type.ts b/packages/mermaid/src/config.type.ts index 75d1138aa..b0f60c5a9 100644 --- a/packages/mermaid/src/config.type.ts +++ b/packages/mermaid/src/config.type.ts @@ -3,10 +3,6 @@ import DOMPurify from 'dompurify'; export interface MermaidConfig { - /** @deprecated use mermaid.registerLazyDiagrams instead */ - lazyLoadedDiagrams?: string[]; - /** @deprecated use mermaid.registerLazyDiagrams instead */ - loadExternalDiagramsAtStartup?: boolean; theme?: string; themeVariables?: any; themeCSS?: string; diff --git a/packages/mermaid/src/dagre-wrapper/edges.js b/packages/mermaid/src/dagre-wrapper/edges.js index 71183eab5..f8c113694 100644 --- a/packages/mermaid/src/dagre-wrapper/edges.js +++ b/packages/mermaid/src/dagre-wrapper/edges.js @@ -453,6 +453,9 @@ export const insertEdge = function (elem, e, edge, clusterDb, diagramType, graph case 'thick': strokeClasses = 'edge-thickness-thick'; break; + case 'invisible': + strokeClasses = 'edge-thickness-thick'; + break; default: strokeClasses = ''; } diff --git a/packages/mermaid/src/diagram-api/detectType.ts b/packages/mermaid/src/diagram-api/detectType.ts index b75e914fb..6ffe5df85 100644 --- a/packages/mermaid/src/diagram-api/detectType.ts +++ b/packages/mermaid/src/diagram-api/detectType.ts @@ -7,6 +7,8 @@ import type { ExternalDiagramDefinition, } from './types'; import { frontMatterRegex } from './frontmatter'; +import { getDiagram, registerDiagram } from './diagramAPI'; +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 +46,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[]) => { @@ -53,6 +55,39 @@ export const registerLazyLoadedDiagrams = (...diagrams: ExternalDiagramDefinitio } }; +export const loadRegisteredDiagrams = async () => { + log.debug(`Loading registered diagrams`); + // Load all lazy loaded diagrams in parallel + const results = await Promise.allSettled( + Object.entries(detectors).map(async ([key, { detector, loader }]) => { + if (loader) { + try { + getDiagram(key); + } catch (error) { + try { + // Register diagram if it is not already registered + const { diagram, id } = await loader(); + registerDiagram(id, diagram, detector); + } catch (err) { + // Remove failed diagram from detectors + log.error(`Failed to load external diagram with key ${key}. Removing from detectors.`); + delete detectors[key]; + throw err; + } + } + } + }) + ); + const failed = results.filter((result) => result.status === 'rejected'); + if (failed.length > 0) { + log.error(`Failed to load ${failed.length} external diagrams`); + for (const res of failed) { + log.error(res); + } + throw new Error(`Failed to load ${failed.length} external diagrams`); + } +}; + export const addDetector = (key: string, detector: DiagramDetector, loader?: DiagramLoader) => { if (detectors[key]) { log.error(`Detector with key ${key} already exists`); diff --git a/packages/mermaid/src/diagram-api/diagram-orchestration.ts b/packages/mermaid/src/diagram-api/diagram-orchestration.ts index a68e99dd0..d06ce846a 100644 --- a/packages/mermaid/src/diagram-api/diagram-orchestration.ts +++ b/packages/mermaid/src/diagram-api/diagram-orchestration.ts @@ -1,104 +1,24 @@ -import { registerDiagram } from './diagramAPI'; -// @ts-ignore: TODO Fix ts errors -import gitGraphParser from '../diagrams/git/parser/gitGraph'; -import { gitGraphDetector } from '../diagrams/git/gitGraphDetector'; -import gitGraphDb from '../diagrams/git/gitGraphAst'; -import gitGraphRenderer from '../diagrams/git/gitGraphRenderer'; -import gitGraphStyles from '../diagrams/git/styles'; - -// @ts-ignore: TODO Fix ts errors -import c4Parser from '../diagrams/c4/parser/c4Diagram'; -import { c4Detector } from '../diagrams/c4/c4Detector'; -import c4Db from '../diagrams/c4/c4Db'; -import c4Renderer from '../diagrams/c4/c4Renderer'; -import c4Styles from '../diagrams/c4/styles'; - -// @ts-ignore: TODO Fix ts errors -import classParser from '../diagrams/class/parser/classDiagram'; -import { classDetector } from '../diagrams/class/classDetector'; -import { classDetectorV2 } from '../diagrams/class/classDetector-V2'; -import classDb from '../diagrams/class/classDb'; -import classRenderer from '../diagrams/class/classRenderer'; -import classRendererV2 from '../diagrams/class/classRenderer-v2'; -import classStyles from '../diagrams/class/styles'; - -// @ts-ignore: TODO Fix ts errors -import erParser from '../diagrams/er/parser/erDiagram'; -import { erDetector } from '../diagrams/er/erDetector'; -import erDb from '../diagrams/er/erDb'; -import erRenderer from '../diagrams/er/erRenderer'; -import erStyles from '../diagrams/er/styles'; - -// @ts-ignore: TODO Fix ts errors -import flowParser from '../diagrams/flowchart/parser/flow'; -import { flowDetector } from '../diagrams/flowchart/flowDetector'; -import { flowDetectorV2 } from '../diagrams/flowchart/flowDetector-v2'; -import flowDb from '../diagrams/flowchart/flowDb'; -import flowRenderer from '../diagrams/flowchart/flowRenderer'; -import flowRendererV2 from '../diagrams/flowchart/flowRenderer-v2'; -import flowStyles from '../diagrams/flowchart/styles'; - -// @ts-ignore: TODO Fix ts errors -import ganttParser from '../diagrams/gantt/parser/gantt'; -import { ganttDetector } from '../diagrams/gantt/ganttDetector'; -import ganttDb from '../diagrams/gantt/ganttDb'; -import ganttRenderer from '../diagrams/gantt/ganttRenderer'; -import ganttStyles from '../diagrams/gantt/styles'; - -// @ts-ignore: TODO Fix ts errors -import infoParser from '../diagrams/info/parser/info'; -import infoDb from '../diagrams/info/infoDb'; -import infoRenderer from '../diagrams/info/infoRenderer'; -import { infoDetector } from '../diagrams/info/infoDetector'; -import infoStyles from '../diagrams/info/styles'; - -// @ts-ignore: TODO Fix ts errors -import pieParser from '../diagrams/pie/parser/pie'; -import { pieDetector } from '../diagrams/pie/pieDetector'; -import pieDb from '../diagrams/pie/pieDb'; -import pieRenderer from '../diagrams/pie/pieRenderer'; -import pieStyles from '../diagrams/pie/styles'; - -// @ts-ignore: TODO Fix ts errors -import requirementParser from '../diagrams/requirement/parser/requirementDiagram'; -import { requirementDetector } from '../diagrams/requirement/requirementDetector'; -import requirementDb from '../diagrams/requirement/requirementDb'; -import requirementRenderer from '../diagrams/requirement/requirementRenderer'; -import requirementStyles from '../diagrams/requirement/styles'; - -// @ts-ignore: TODO Fix ts errors -import sequenceParser from '../diagrams/sequence/parser/sequenceDiagram'; -import { sequenceDetector } from '../diagrams/sequence/sequenceDetector'; -import sequenceDb from '../diagrams/sequence/sequenceDb'; -import sequenceRenderer from '../diagrams/sequence/sequenceRenderer'; -import sequenceStyles from '../diagrams/sequence/styles'; - -// @ts-ignore: TODO Fix ts errors -import stateParser from '../diagrams/state/parser/stateDiagram'; -import { stateDetector } from '../diagrams/state/stateDetector'; -import { stateDetectorV2 } from '../diagrams/state/stateDetector-V2'; -import stateDb from '../diagrams/state/stateDb'; -import stateRenderer from '../diagrams/state/stateRenderer'; -import stateRendererV2 from '../diagrams/state/stateRenderer-v2'; -import stateStyles from '../diagrams/state/styles'; - -// @ts-ignore: TODO Fix ts errors -import journeyParser from '../diagrams/user-journey/parser/journey'; -import { journeyDetector } from '../diagrams/user-journey/journeyDetector'; -import journeyDb from '../diagrams/user-journey/journeyDb'; -import journeyRenderer from '../diagrams/user-journey/journeyRenderer'; -import journeyStyles from '../diagrams/user-journey/styles'; -import { setConfig } from '../config'; - -import errorRenderer from '../diagrams/error/errorRenderer'; -import errorStyles from '../diagrams/error/styles'; - +import c4 from '../diagrams/c4/c4Detector'; +import flowchart from '../diagrams/flowchart/flowDetector'; +import flowchartV2 from '../diagrams/flowchart/flowDetector-v2'; +import er from '../diagrams/er/erDetector'; +import git from '../diagrams/git/gitGraphDetector'; +import gantt from '../diagrams/gantt/ganttDetector'; +import info from '../diagrams/info/infoDetector'; +import pie from '../diagrams/pie/pieDetector'; +import requirement from '../diagrams/requirement/requirementDetector'; +import sequence from '../diagrams/sequence/sequenceDetector'; +import classDiagram from '../diagrams/class/classDetector'; +import classDiagramV2 from '../diagrams/class/classDetector-V2'; +import state from '../diagrams/state/stateDetector'; +import stateV2 from '../diagrams/state/stateDetector-V2'; +import journey from '../diagrams/user-journey/journeyDetector'; +import error from '../diagrams/error/errorDetector'; import flowchartElk from '../diagrams/flowchart/elk/detector'; +import timeline from '../diagrams/timeline/detector'; +import mindmap from '../diagrams/mindmap/detector'; import { registerLazyLoadedDiagrams } from './detectType'; - -// Lazy loaded diagrams -import timelineDetector from '../diagrams/timeline/detector'; -import mindmapDetector from '../diagrams/mindmap/detector'; +import { registerDiagram } from './diagramAPI'; let hasLoadedDiagrams = false; export const addDiagrams = () => { @@ -108,31 +28,6 @@ export const addDiagrams = () => { // This is added here to avoid race-conditions. // We could optimize the loading logic somehow. hasLoadedDiagrams = true; - registerLazyLoadedDiagrams(flowchartElk, timelineDetector, mindmapDetector); - - registerDiagram( - 'error', - // Special diagram with error messages but setup as a regular diagram - { - db: { - clear: () => { - // Quite ok, clear needs to be there for error to work as a regular diagram - }, - }, - styles: errorStyles, - renderer: errorRenderer, - parser: { - parser: { yy: {} }, - parse: () => { - // no op - }, - }, - init: () => { - // no op - }, - }, - (text) => text.toLowerCase().trim() === 'error' - ); registerDiagram( '---', // --- diagram type may appear if YAML front-matter is not parsed correctly @@ -142,8 +37,8 @@ export const addDiagrams = () => { // Quite ok, clear needs to be there for --- to work as a regular diagram }, }, - styles: errorStyles, // should never be used - renderer: errorRenderer, // should never be used + styles: {}, // should never be used + renderer: {}, // should never be used parser: { parser: { yy: {} }, parse: () => { @@ -160,220 +55,25 @@ export const addDiagrams = () => { return text.toLowerCase().trimStart().startsWith('---'); } ); - - registerDiagram( - 'c4', - { - parser: c4Parser, - db: c4Db, - renderer: c4Renderer, - styles: c4Styles, - init: (cnf) => { - c4Renderer.setConf(cnf.c4); - }, - }, - c4Detector - ); - registerDiagram( - 'class', - { - parser: classParser, - db: classDb, - renderer: classRenderer, - styles: classStyles, - init: (cnf) => { - if (!cnf.class) { - cnf.class = {}; - } - cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute; - classDb.clear(); - }, - }, - classDetector - ); - registerDiagram( - 'classDiagram', - { - parser: classParser, - db: classDb, - renderer: classRendererV2, - styles: classStyles, - init: (cnf) => { - if (!cnf.class) { - cnf.class = {}; - } - cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute; - classDb.clear(); - }, - }, - classDetectorV2 - ); - registerDiagram( - 'er', - { - parser: erParser, - db: erDb, - renderer: erRenderer, - styles: erStyles, - }, - erDetector - ); - registerDiagram( - 'gantt', - { - parser: ganttParser, - db: ganttDb, - renderer: ganttRenderer, - styles: ganttStyles, - }, - ganttDetector - ); - registerDiagram( - 'info', - { - parser: infoParser, - db: infoDb, - renderer: infoRenderer, - styles: infoStyles, - }, - infoDetector - ); - registerDiagram( - 'pie', - { - parser: pieParser, - db: pieDb, - renderer: pieRenderer, - styles: pieStyles, - }, - pieDetector - ); - registerDiagram( - 'requirement', - { - parser: requirementParser, - db: requirementDb, - renderer: requirementRenderer, - styles: requirementStyles, - }, - requirementDetector - ); - registerDiagram( - 'sequence', - { - parser: sequenceParser, - db: sequenceDb, - renderer: sequenceRenderer, - styles: sequenceStyles, - init: (cnf) => { - if (!cnf.sequence) { - cnf.sequence = {}; - } - cnf.sequence.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute; - if ('sequenceDiagram' in cnf) { - throw new Error( - '`mermaid config.sequenceDiagram` has been renamed to `config.sequence`. Please update your mermaid config.' - ); - } - sequenceDb.setWrap(cnf.wrap); - sequenceRenderer.setConf(cnf.sequence); - }, - }, - sequenceDetector - ); - registerDiagram( - 'state', - { - parser: stateParser, - db: stateDb, - renderer: stateRenderer, - styles: stateStyles, - init: (cnf) => { - if (!cnf.state) { - cnf.state = {}; - } - cnf.state.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute; - stateDb.clear(); - }, - }, - stateDetector - ); - registerDiagram( - 'stateDiagram', - { - parser: stateParser, - db: stateDb, - renderer: stateRendererV2, - styles: stateStyles, - init: (cnf) => { - if (!cnf.state) { - cnf.state = {}; - } - cnf.state.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute; - stateDb.clear(); - }, - }, - stateDetectorV2 - ); - registerDiagram( - 'journey', - { - parser: journeyParser, - db: journeyDb, - renderer: journeyRenderer, - styles: journeyStyles, - init: (cnf) => { - journeyRenderer.setConf(cnf.journey); - journeyDb.clear(); - }, - }, - journeyDetector - ); - - registerDiagram( - 'flowchart', - { - parser: flowParser, - db: flowDb, - renderer: flowRendererV2, - styles: flowStyles, - init: (cnf) => { - if (!cnf.flowchart) { - cnf.flowchart = {}; - } - // TODO, broken as of 2022-09-14 (13809b50251845475e6dca65cc395761be38fbd2) - cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute; - flowRenderer.setConf(cnf.flowchart); - flowDb.clear(); - flowDb.setGen('gen-1'); - }, - }, - flowDetector - ); - registerDiagram( - 'flowchart-v2', - { - parser: flowParser, - db: flowDb, - renderer: flowRendererV2, - styles: flowStyles, - init: (cnf) => { - if (!cnf.flowchart) { - cnf.flowchart = {}; - } - cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute; - // flowchart-v2 uses dagre-wrapper, which doesn't have access to flowchart cnf - setConfig({ flowchart: { arrowMarkerAbsolute: cnf.arrowMarkerAbsolute } }); - flowRendererV2.setConf(cnf.flowchart); - flowDb.clear(); - flowDb.setGen('gen-2'); - }, - }, - flowDetectorV2 - ); - registerDiagram( - 'gitGraph', - { parser: gitGraphParser, db: gitGraphDb, renderer: gitGraphRenderer, styles: gitGraphStyles }, - gitGraphDetector + registerLazyLoadedDiagrams( + error, + c4, + classDiagram, + classDiagramV2, + er, + gantt, + info, + pie, + requirement, + sequence, + flowchart, + flowchartV2, + flowchartElk, + mindmap, + timeline, + git, + state, + stateV2, + journey ); }; diff --git a/packages/mermaid/src/diagram-api/diagramAPI.spec.ts b/packages/mermaid/src/diagram-api/diagramAPI.spec.ts index ea546fbb6..9e04c861f 100644 --- a/packages/mermaid/src/diagram-api/diagramAPI.spec.ts +++ b/packages/mermaid/src/diagram-api/diagramAPI.spec.ts @@ -2,8 +2,12 @@ import { detectType } from './detectType'; import { getDiagram, registerDiagram } from './diagramAPI'; import { addDiagrams } from './diagram-orchestration'; import { DiagramDetector } from './types'; +import { getDiagramFromText } from '../Diagram'; addDiagrams(); +beforeAll(async () => { + await getDiagramFromText('sequenceDiagram'); +}); describe('DiagramAPI', () => { it('should return default diagrams', () => { diff --git a/packages/mermaid/src/diagram-api/diagramAPI.ts b/packages/mermaid/src/diagram-api/diagramAPI.ts index 936e43efd..c5841b96b 100644 --- a/packages/mermaid/src/diagram-api/diagramAPI.ts +++ b/packages/mermaid/src/diagram-api/diagramAPI.ts @@ -71,3 +71,9 @@ export const getDiagram = (name: string): DiagramDefinition => { } throw new Error(`Diagram ${name} not found.`); }; + +export class DiagramNotFoundError extends Error { + constructor(message: string) { + super(`Diagram ${message} not found.`); + } +} diff --git a/packages/mermaid/src/diagram-api/types.ts b/packages/mermaid/src/diagram-api/types.ts index d60019577..081136563 100644 --- a/packages/mermaid/src/diagram-api/types.ts +++ b/packages/mermaid/src/diagram-api/types.ts @@ -18,6 +18,7 @@ export interface DiagramDb { setDiagramTitle?: (title: string) => void; getAccTitle?: () => string; getAccDescription?: () => string; + bindFunctions?: (element: Element) => void; } export interface DiagramDefinition { diff --git a/packages/mermaid/src/diagram.spec.ts b/packages/mermaid/src/diagram.spec.ts index ebe088a86..a862c7936 100644 --- a/packages/mermaid/src/diagram.spec.ts +++ b/packages/mermaid/src/diagram.spec.ts @@ -1,18 +1,18 @@ import { describe, test, expect } from 'vitest'; -import Diagram, { getDiagramFromText } from './Diagram'; +import { Diagram, getDiagramFromText } from './Diagram'; import { addDetector } from './diagram-api/detectType'; import { addDiagrams } from './diagram-api/diagram-orchestration'; addDiagrams(); describe('diagram detection', () => { - test('should detect inbuilt diagrams', () => { - const graph = getDiagramFromText('graph TD; A-->B') as Diagram; + test('should detect inbuilt diagrams', async () => { + const graph = (await getDiagramFromText('graph TD; A-->B')) as Diagram; expect(graph).toBeInstanceOf(Diagram); expect(graph.type).toBe('flowchart-v2'); - const sequence = getDiagramFromText( + const sequence = (await getDiagramFromText( 'sequenceDiagram; Alice->>+John: Hello John, how are you?' - ) as Diagram; + )) as Diagram; expect(sequence).toBeInstanceOf(Diagram); expect(sequence.type).toBe('sequence'); }); @@ -44,14 +44,15 @@ describe('diagram detection', () => { expect(diagram.type).toBe('loki'); }); - test('should throw the right error for incorrect diagram', () => { - expect(() => getDiagramFromText('graph TD; A-->')).toThrowErrorMatchingInlineSnapshot(` -"Parse error on line 3: -graph TD; A--> ---------------^ -Expecting 'AMP', 'ALPHA', 'COLON', 'PIPE', 'TESTSTR', 'DOWN', 'DEFAULT', 'NUM', 'COMMA', 'MINUS', 'BRKT', 'DOT', 'PUNCTUATION', 'UNICODE_TEXT', 'PLUS', 'EQUALS', 'MULT', 'UNDERSCORE', got 'EOF'" - `); - expect(() => getDiagramFromText('sequenceDiagram; A-->B')).toThrowErrorMatchingInlineSnapshot(` + test('should throw the right error for incorrect diagram', async () => { + await expect(getDiagramFromText('graph TD; A-->')).rejects.toThrowErrorMatchingInlineSnapshot(` + "Parse error on line 2: + graph TD; A--> + --------------^ + Expecting 'AMP', 'ALPHA', 'COLON', 'PIPE', 'TESTSTR', 'DOWN', 'DEFAULT', 'NUM', 'COMMA', 'MINUS', 'BRKT', 'DOT', 'PUNCTUATION', 'UNICODE_TEXT', 'PLUS', 'EQUALS', 'MULT', 'UNDERSCORE', got 'EOF'" + `); + await expect(getDiagramFromText('sequenceDiagram; A-->B')).rejects + .toThrowErrorMatchingInlineSnapshot(` "Parse error on line 1: ...quenceDiagram; A-->B -----------------------^ @@ -59,8 +60,8 @@ Expecting 'TXT', got 'NEWLINE'" `); }); - test('should throw the right error for unregistered diagrams', () => { - expect(() => getDiagramFromText('thor TD; A-->B')).toThrowError( + test('should throw the right error for unregistered diagrams', async () => { + await expect(getDiagramFromText('thor TD; A-->B')).rejects.toThrowError( 'No diagram type detected for text: thor TD; A-->B' ); }); diff --git a/packages/mermaid/src/diagrams/c4/c4Detector.ts b/packages/mermaid/src/diagrams/c4/c4Detector.ts index 49ba95b8e..08b8bbf55 100644 --- a/packages/mermaid/src/diagrams/c4/c4Detector.ts +++ b/packages/mermaid/src/diagrams/c4/c4Detector.ts @@ -1,5 +1,20 @@ -import type { DiagramDetector } from '../../diagram-api/types'; +import type { ExternalDiagramDefinition } from '../../diagram-api/types'; -export const c4Detector: DiagramDetector = (txt) => { +const id = 'c4'; + +const detector = (txt: string) => { return txt.match(/^\s*C4Context|C4Container|C4Component|C4Dynamic|C4Deployment/) !== null; }; + +const loader = async () => { + const { diagram } = await import('./c4Diagram'); + return { id, diagram }; +}; + +const plugin: ExternalDiagramDefinition = { + id, + detector, + loader, +}; + +export default plugin; diff --git a/packages/mermaid/src/diagrams/c4/c4Diagram.ts b/packages/mermaid/src/diagrams/c4/c4Diagram.ts new file mode 100644 index 000000000..6f8f25db2 --- /dev/null +++ b/packages/mermaid/src/diagrams/c4/c4Diagram.ts @@ -0,0 +1,17 @@ +// @ts-ignore: TODO Fix ts errors +import c4Parser from './parser/c4Diagram'; +import c4Db from './c4Db'; +import c4Renderer from './c4Renderer'; +import c4Styles from './styles'; +import { MermaidConfig } from '../../config.type'; +import { DiagramDefinition } from '../../diagram-api/types'; + +export const diagram: DiagramDefinition = { + parser: c4Parser, + db: c4Db, + renderer: c4Renderer, + styles: c4Styles, + init: (cnf: MermaidConfig) => { + c4Renderer.setConf(cnf.c4); + }, +}; diff --git a/packages/mermaid/src/diagrams/class/classDetector-V2.ts b/packages/mermaid/src/diagrams/class/classDetector-V2.ts index 7100f6c66..1d4255719 100644 --- a/packages/mermaid/src/diagrams/class/classDetector-V2.ts +++ b/packages/mermaid/src/diagrams/class/classDetector-V2.ts @@ -1,6 +1,8 @@ -import type { DiagramDetector } from '../../diagram-api/types'; +import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types'; -export const classDetectorV2: DiagramDetector = (txt, config) => { +const id = 'classDiagram'; + +const detector: DiagramDetector = (txt, config) => { // If we have configured to use dagre-wrapper then we should return true in this function for classDiagram code thus making it use the new class diagram if ( txt.match(/^\s*classDiagram/) !== null && @@ -11,3 +13,16 @@ export const classDetectorV2: DiagramDetector = (txt, config) => { // We have not opted to use the new renderer so we should return true if we detect a class diagram return txt.match(/^\s*classDiagram-v2/) !== null; }; + +const loader = async () => { + const { diagram } = await import('./classDiagram-v2'); + return { id, diagram }; +}; + +const plugin: ExternalDiagramDefinition = { + id, + detector, + loader, +}; + +export default plugin; diff --git a/packages/mermaid/src/diagrams/class/classDetector.ts b/packages/mermaid/src/diagrams/class/classDetector.ts index c3833ed28..ef8ea61e7 100644 --- a/packages/mermaid/src/diagrams/class/classDetector.ts +++ b/packages/mermaid/src/diagrams/class/classDetector.ts @@ -1,6 +1,8 @@ -import type { DiagramDetector } from '../../diagram-api/types'; +import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types'; -export const classDetector: DiagramDetector = (txt, config) => { +const id = 'class'; + +const detector: DiagramDetector = (txt, config) => { // If we have configured to use dagre-wrapper then we should never return true in this function if (config?.class?.defaultRenderer === 'dagre-wrapper') { return false; @@ -8,3 +10,16 @@ export const classDetector: DiagramDetector = (txt, config) => { // We have not opted to use the new renderer so we should return true if we detect a class diagram return txt.match(/^\s*classDiagram/) !== null; }; + +const loader = async () => { + const { diagram } = await import('./classDiagram'); + return { id, diagram }; +}; + +const plugin: ExternalDiagramDefinition = { + id, + detector, + loader, +}; + +export default plugin; diff --git a/packages/mermaid/src/diagrams/class/classDiagram-v2.ts b/packages/mermaid/src/diagrams/class/classDiagram-v2.ts new file mode 100644 index 000000000..2f0bbf371 --- /dev/null +++ b/packages/mermaid/src/diagrams/class/classDiagram-v2.ts @@ -0,0 +1,20 @@ +import { DiagramDefinition } from '../../diagram-api/types'; +// @ts-ignore: TODO Fix ts errors +import parser from './parser/classDiagram'; +import db from './classDb'; +import styles from './styles'; +import renderer from './classRenderer-v2'; + +export const diagram: DiagramDefinition = { + parser, + db, + renderer, + styles, + init: (cnf) => { + if (!cnf.class) { + cnf.class = {}; + } + cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute; + db.clear(); + }, +}; diff --git a/packages/mermaid/src/diagrams/class/classDiagram.ts b/packages/mermaid/src/diagrams/class/classDiagram.ts new file mode 100644 index 000000000..250d04176 --- /dev/null +++ b/packages/mermaid/src/diagrams/class/classDiagram.ts @@ -0,0 +1,20 @@ +import { DiagramDefinition } from '../../diagram-api/types'; +// @ts-ignore: TODO Fix ts errors +import parser from './parser/classDiagram'; +import db from './classDb'; +import styles from './styles'; +import renderer from './classRenderer'; + +export const diagram: DiagramDefinition = { + parser, + db, + renderer, + styles, + init: (cnf) => { + if (!cnf.class) { + cnf.class = {}; + } + cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute; + db.clear(); + }, +}; diff --git a/packages/mermaid/src/diagrams/er/erDetector.ts b/packages/mermaid/src/diagrams/er/erDetector.ts index 5a87a949e..f73baa434 100644 --- a/packages/mermaid/src/diagrams/er/erDetector.ts +++ b/packages/mermaid/src/diagrams/er/erDetector.ts @@ -1,5 +1,20 @@ -import type { DiagramDetector } from '../../diagram-api/types'; +import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types'; -export const erDetector: DiagramDetector = (txt) => { +const id = 'er'; + +const detector: DiagramDetector = (txt) => { return txt.match(/^\s*erDiagram/) !== null; }; + +const loader = async () => { + const { diagram } = await import('./erDiagram'); + return { id, diagram }; +}; + +const plugin: ExternalDiagramDefinition = { + id, + detector, + loader, +}; + +export default plugin; diff --git a/packages/mermaid/src/diagrams/er/erDiagram.ts b/packages/mermaid/src/diagrams/er/erDiagram.ts new file mode 100644 index 000000000..a5b0da9c1 --- /dev/null +++ b/packages/mermaid/src/diagrams/er/erDiagram.ts @@ -0,0 +1,12 @@ +// @ts-ignore: TODO Fix ts errors +import erParser from './parser/erDiagram'; +import erDb from './erDb'; +import erRenderer from './erRenderer'; +import erStyles from './styles'; + +export const diagram = { + parser: erParser, + db: erDb, + renderer: erRenderer, + styles: erStyles, +}; diff --git a/packages/mermaid/src/diagrams/er/parser/erDiagram.jison b/packages/mermaid/src/diagrams/er/parser/erDiagram.jison index 1e3972a3b..6aaca81d6 100644 --- a/packages/mermaid/src/diagrams/er/parser/erDiagram.jison +++ b/packages/mermaid/src/diagrams/er/parser/erDiagram.jison @@ -81,7 +81,7 @@ start document : /* empty */ { $$ = [] } - | document line {$1.push($2);$$ = $1} + | document line {$1.push($2);$$ = $1} ; line diff --git a/packages/mermaid/src/diagrams/error/errorDetector.ts b/packages/mermaid/src/diagrams/error/errorDetector.ts new file mode 100644 index 000000000..2bdcd7028 --- /dev/null +++ b/packages/mermaid/src/diagrams/error/errorDetector.ts @@ -0,0 +1,20 @@ +import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types'; + +const id = 'error'; + +const detector: DiagramDetector = (text) => { + return text.toLowerCase().trim() === 'error'; +}; + +const loader = async () => { + const { diagram } = await import('./errorDiagram'); + return { id, diagram }; +}; + +const plugin: ExternalDiagramDefinition = { + id, + detector, + loader, +}; + +export default plugin; diff --git a/packages/mermaid/src/diagrams/error/errorDiagram.ts b/packages/mermaid/src/diagrams/error/errorDiagram.ts new file mode 100644 index 000000000..d081e1028 --- /dev/null +++ b/packages/mermaid/src/diagrams/error/errorDiagram.ts @@ -0,0 +1,21 @@ +import { DiagramDefinition } from '../../diagram-api/types'; +import styles from './styles'; +import renderer from './errorRenderer'; +export const diagram: DiagramDefinition = { + db: { + clear: () => { + // Quite ok, clear needs to be there for error to work as a regular diagram + }, + }, + styles, + renderer, + parser: { + parser: { yy: {} }, + parse: () => { + // no op + }, + }, + init: () => { + // no op + }, +}; diff --git a/packages/mermaid/src/diagrams/error/errorRenderer.ts b/packages/mermaid/src/diagrams/error/errorRenderer.ts index b4e267684..60877cb8d 100644 --- a/packages/mermaid/src/diagrams/error/errorRenderer.ts +++ b/packages/mermaid/src/diagrams/error/errorRenderer.ts @@ -1,4 +1,5 @@ /** Created by knut on 14-12-11. */ +// @ts-ignore TODO: Investigate D3 issue import { select } from 'd3'; import { log } from '../../logger'; import { getErrorMessage } from '../../utils'; diff --git a/packages/mermaid/src/diagrams/flowchart/elk/detector.ts b/packages/mermaid/src/diagrams/flowchart/elk/detector.ts index 41760ff4d..c6fa77957 100644 --- a/packages/mermaid/src/diagrams/flowchart/elk/detector.ts +++ b/packages/mermaid/src/diagrams/flowchart/elk/detector.ts @@ -16,7 +16,7 @@ const detector: DiagramDetector = (txt: string, config?: MermaidConfig): boolean }; const loader = async () => { - const { diagram } = await import('./diagram-definition.js'); + const { diagram } = await import('./flowchart-elk-definition.js'); return { id, diagram }; }; diff --git a/packages/mermaid/src/diagrams/flowchart/elk/diagram-definition.ts b/packages/mermaid/src/diagrams/flowchart/elk/flowchart-elk-definition.ts similarity index 100% rename from packages/mermaid/src/diagrams/flowchart/elk/diagram-definition.ts rename to packages/mermaid/src/diagrams/flowchart/elk/flowchart-elk-definition.ts diff --git a/packages/mermaid/src/diagrams/flowchart/flowDb.js b/packages/mermaid/src/diagrams/flowchart/flowDb.js index 2e6b840b5..31196ba96 100644 --- a/packages/mermaid/src/diagrams/flowchart/flowDb.js +++ b/packages/mermaid/src/diagrams/flowchart/flowDb.js @@ -677,6 +677,10 @@ const destructEndLink = (_str) => { stroke = 'thick'; } + if (line[0] === '~') { + stroke = 'invisible'; + } + let dots = countChar('.', line); if (dots) { diff --git a/packages/mermaid/src/diagrams/flowchart/flowDetector-v2.ts b/packages/mermaid/src/diagrams/flowchart/flowDetector-v2.ts index 3916325de..6162cc828 100644 --- a/packages/mermaid/src/diagrams/flowchart/flowDetector-v2.ts +++ b/packages/mermaid/src/diagrams/flowchart/flowDetector-v2.ts @@ -1,6 +1,9 @@ import type { DiagramDetector } from '../../diagram-api/types'; +import type { ExternalDiagramDefinition } from '../../diagram-api/types'; -export const flowDetectorV2: DiagramDetector = (txt, config) => { +const id = 'flowchart-v2'; + +const detector: DiagramDetector = (txt, config) => { if (config?.flowchart?.defaultRenderer === 'dagre-d3') { return false; } @@ -14,3 +17,16 @@ export const flowDetectorV2: DiagramDetector = (txt, config) => { } return txt.match(/^\s*flowchart/) !== null; }; + +const loader = async () => { + const { diagram } = await import('./flowDiagram-v2'); + return { id, diagram }; +}; + +const plugin: ExternalDiagramDefinition = { + id, + detector, + loader, +}; + +export default plugin; diff --git a/packages/mermaid/src/diagrams/flowchart/flowDetector.ts b/packages/mermaid/src/diagrams/flowchart/flowDetector.ts index d46b7d8f5..9457ff469 100644 --- a/packages/mermaid/src/diagrams/flowchart/flowDetector.ts +++ b/packages/mermaid/src/diagrams/flowchart/flowDetector.ts @@ -1,6 +1,8 @@ -import type { DiagramDetector } from '../../diagram-api/types'; +import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types'; -export const flowDetector: DiagramDetector = (txt, config) => { +const id = 'flowchart'; + +const detector: DiagramDetector = (txt, config) => { // If we have conferred to only use new flow charts this function should always return false // as in not signalling true for a legacy flowchart if (config?.flowchart?.defaultRenderer === 'dagre-wrapper') { @@ -11,3 +13,16 @@ export const flowDetector: DiagramDetector = (txt, config) => { } return txt.match(/^\s*graph/) !== null; }; + +const loader = async () => { + const { diagram } = await import('./flowDiagram'); + return { id, diagram }; +}; + +const plugin: ExternalDiagramDefinition = { + id, + detector, + loader, +}; + +export default plugin; diff --git a/packages/mermaid/src/diagrams/flowchart/flowDiagram-v2.ts b/packages/mermaid/src/diagrams/flowchart/flowDiagram-v2.ts new file mode 100644 index 000000000..8cd49de65 --- /dev/null +++ b/packages/mermaid/src/diagrams/flowchart/flowDiagram-v2.ts @@ -0,0 +1,25 @@ +// @ts-ignore: TODO Fix ts errors +import flowParser from './parser/flow'; +import flowDb from './flowDb'; +import flowRendererV2 from './flowRenderer-v2'; +import flowStyles from './styles'; +import { MermaidConfig } from '../../config.type'; +import { setConfig } from '../../config'; + +export const diagram = { + parser: flowParser, + db: flowDb, + renderer: flowRendererV2, + styles: flowStyles, + init: (cnf: MermaidConfig) => { + if (!cnf.flowchart) { + cnf.flowchart = {}; + } + cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute; + // flowchart-v2 uses dagre-wrapper, which doesn't have access to flowchart cnf + setConfig({ flowchart: { arrowMarkerAbsolute: cnf.arrowMarkerAbsolute } }); + flowRendererV2.setConf(cnf.flowchart); + flowDb.clear(); + flowDb.setGen('gen-2'); + }, +}; diff --git a/packages/mermaid/src/diagrams/flowchart/flowDiagram.ts b/packages/mermaid/src/diagrams/flowchart/flowDiagram.ts new file mode 100644 index 000000000..d68a7c01d --- /dev/null +++ b/packages/mermaid/src/diagrams/flowchart/flowDiagram.ts @@ -0,0 +1,24 @@ +// @ts-ignore: TODO Fix ts errors +import flowParser from './parser/flow'; +import flowDb from './flowDb'; +import flowRenderer from './flowRenderer'; +import flowRendererV2 from './flowRenderer-v2'; +import flowStyles from './styles'; +import { MermaidConfig } from '../../config.type'; + +export const diagram = { + parser: flowParser, + db: flowDb, + renderer: flowRendererV2, + styles: flowStyles, + init: (cnf: MermaidConfig) => { + if (!cnf.flowchart) { + cnf.flowchart = {}; + } + // TODO, broken as of 2022-09-14 (13809b50251845475e6dca65cc395761be38fbd2) + cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute; + flowRenderer.setConf(cnf.flowchart); + flowDb.clear(); + flowDb.setGen('gen-1'); + }, +}; diff --git a/packages/mermaid/src/diagrams/flowchart/flowRenderer-v2.js b/packages/mermaid/src/diagrams/flowchart/flowRenderer-v2.js index 03bda7611..2d3e21a44 100644 --- a/packages/mermaid/src/diagrams/flowchart/flowRenderer-v2.js +++ b/packages/mermaid/src/diagrams/flowchart/flowRenderer-v2.js @@ -280,6 +280,11 @@ export const addEdges = function (edges, g, diagObj) { edgeData.pattern = 'solid'; edgeData.style = 'stroke-width: 3.5px;fill:none;'; break; + case 'invisible': + edgeData.thickness = 'invisible'; + edgeData.pattern = 'solid'; + edgeData.style = 'stroke-width: 0;fill:none;'; + break; } if (edge.style !== undefined) { const styles = getStylesFromArray(edge.style); diff --git a/packages/mermaid/src/diagrams/flowchart/flowRenderer.addEdges.spec.js b/packages/mermaid/src/diagrams/flowchart/flowRenderer.addEdges.spec.js index 41868e203..7744053f0 100644 --- a/packages/mermaid/src/diagrams/flowchart/flowRenderer.addEdges.spec.js +++ b/packages/mermaid/src/diagrams/flowchart/flowRenderer.addEdges.spec.js @@ -1,21 +1,24 @@ import flowDb from './flowDb'; -import flowParser from './parser/flow'; +import { parser } from './parser/flow'; import flowRenderer from './flowRenderer'; -import Diagram from '../../Diagram'; import { addDiagrams } from '../../diagram-api/diagram-orchestration'; + +const diag = { + db: flowDb, +}; addDiagrams(); describe('when using mermaid and ', function () { describe('when calling addEdges ', function () { beforeEach(function () { - flowParser.parser.yy = flowDb; + parser.yy = flowDb; flowDb.clear(); flowDb.setGen('gen-2'); }); - it('should handle edges with text', function () { - const diag = new Diagram('graph TD;A-->|text ex|B;'); - diag.db.getVertices(); - const edges = diag.db.getEdges(); + it('should handle edges with text', () => { + parser.parse('graph TD;A-->|text ex|B;'); + flowDb.getVertices(); + const edges = flowDb.getEdges(); const mockG = { setEdge: function (start, end, options) { @@ -29,10 +32,10 @@ describe('when using mermaid and ', function () { flowRenderer.addEdges(edges, mockG, diag); }); - it('should handle edges without text', function () { - const diag = new Diagram('graph TD;A-->B;'); - diag.db.getVertices(); - const edges = diag.db.getEdges(); + it('should handle edges without text', async function () { + parser.parse('graph TD;A-->B;'); + flowDb.getVertices(); + const edges = flowDb.getEdges(); const mockG = { setEdge: function (start, end, options) { @@ -45,10 +48,10 @@ describe('when using mermaid and ', function () { flowRenderer.addEdges(edges, mockG, diag); }); - it('should handle open-ended edges', function () { - const diag = new Diagram('graph TD;A---B;'); - diag.db.getVertices(); - const edges = diag.db.getEdges(); + it('should handle open-ended edges', () => { + parser.parse('graph TD;A---B;'); + flowDb.getVertices(); + const edges = flowDb.getEdges(); const mockG = { setEdge: function (start, end, options) { @@ -61,10 +64,10 @@ describe('when using mermaid and ', function () { flowRenderer.addEdges(edges, mockG, diag); }); - it('should handle edges with styles defined', function () { - const diag = new Diagram('graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2;'); - diag.db.getVertices(); - const edges = diag.db.getEdges(); + it('should handle edges with styles defined', () => { + parser.parse('graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2;'); + flowDb.getVertices(); + const edges = flowDb.getEdges(); const mockG = { setEdge: function (start, end, options) { @@ -77,10 +80,10 @@ describe('when using mermaid and ', function () { flowRenderer.addEdges(edges, mockG, diag); }); - it('should handle edges with interpolation defined', function () { - const diag = new Diagram('graph TD;A---B; linkStyle 0 interpolate basis'); - diag.db.getVertices(); - const edges = diag.db.getEdges(); + it('should handle edges with interpolation defined', () => { + parser.parse('graph TD;A---B; linkStyle 0 interpolate basis'); + flowDb.getVertices(); + const edges = flowDb.getEdges(); const mockG = { setEdge: function (start, end, options) { @@ -93,12 +96,10 @@ describe('when using mermaid and ', function () { flowRenderer.addEdges(edges, mockG, diag); }); - it('should handle edges with text and styles defined', function () { - const diag = new Diagram( - 'graph TD;A---|the text|B; linkStyle 0 stroke:val1,stroke-width:val2;' - ); - diag.db.getVertices(); - const edges = diag.db.getEdges(); + it('should handle edges with text and styles defined', () => { + parser.parse('graph TD;A---|the text|B; linkStyle 0 stroke:val1,stroke-width:val2;'); + flowDb.getVertices(); + const edges = flowDb.getEdges(); const mockG = { setEdge: function (start, end, options) { @@ -113,10 +114,10 @@ describe('when using mermaid and ', function () { flowRenderer.addEdges(edges, mockG, diag); }); - it('should set fill to "none" by default when handling edges', function () { - const diag = new Diagram('graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2;'); - diag.db.getVertices(); - const edges = diag.db.getEdges(); + it('should set fill to "none" by default when handling edges', () => { + parser.parse('graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2;'); + flowDb.getVertices(); + const edges = flowDb.getEdges(); const mockG = { setEdge: function (start, end, options) { @@ -130,12 +131,10 @@ describe('when using mermaid and ', function () { flowRenderer.addEdges(edges, mockG, diag); }); - it('should not set fill to none if fill is set in linkStyle', function () { - const diag = new Diagram( - 'graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2,fill:blue;' - ); - diag.db.getVertices(); - const edges = diag.db.getEdges(); + it('should not set fill to none if fill is set in linkStyle', () => { + parser.parse('graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2,fill:blue;'); + flowDb.getVertices(); + const edges = flowDb.getEdges(); const mockG = { setEdge: function (start, end, options) { expect(start).toContain('flowchart-A-'); diff --git a/packages/mermaid/src/diagrams/flowchart/parser/flow.jison b/packages/mermaid/src/diagrams/flowchart/parser/flow.jison index 05473b4a0..e2dad5881 100644 --- a/packages/mermaid/src/diagrams/flowchart/parser/flow.jison +++ b/packages/mermaid/src/diagrams/flowchart/parser/flow.jison @@ -121,6 +121,7 @@ that id. \s*[xo<]?\-\-+[-xo>]\s* return 'LINK'; \s*[xo<]?\=\=+[=xo>]\s* return 'LINK'; \s*[xo<]?\-?\.+\-[xo>]?\s* return 'LINK'; +\s*\~\~[\~]+\s* return 'LINK'; \s*[xo<]?\-\-\s* return 'START_LINK'; \s*[xo<]?\=\=\s* return 'START_LINK'; \s*[xo<]?\-\.\s* return 'START_LINK'; diff --git a/packages/mermaid/src/diagrams/gantt/ganttDb.js b/packages/mermaid/src/diagrams/gantt/ganttDb.js index 273a02d58..a1c74dd62 100644 --- a/packages/mermaid/src/diagrams/gantt/ganttDb.js +++ b/packages/mermaid/src/diagrams/gantt/ganttDb.js @@ -1,4 +1,4 @@ -import moment from 'moment'; +import moment from 'moment-mini'; import { sanitizeUrl } from '@braintree/sanitize-url'; import { log } from '../../logger'; import * as configApi from '../../config'; diff --git a/packages/mermaid/src/diagrams/gantt/ganttDb.spec.ts b/packages/mermaid/src/diagrams/gantt/ganttDb.spec.ts index 2b0e9f435..09df96f12 100644 --- a/packages/mermaid/src/diagrams/gantt/ganttDb.spec.ts +++ b/packages/mermaid/src/diagrams/gantt/ganttDb.spec.ts @@ -1,5 +1,5 @@ // @ts-nocheck TODO: Fix TS -import moment from 'moment'; +import moment from 'moment-mini'; import ganttDb from './ganttDb'; import { convert } from '../../tests/util'; diff --git a/packages/mermaid/src/diagrams/gantt/ganttDetector.ts b/packages/mermaid/src/diagrams/gantt/ganttDetector.ts index 5de167010..3fe2bbe7e 100644 --- a/packages/mermaid/src/diagrams/gantt/ganttDetector.ts +++ b/packages/mermaid/src/diagrams/gantt/ganttDetector.ts @@ -1,5 +1,20 @@ -import type { DiagramDetector } from '../../diagram-api/types'; +import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types'; -export const ganttDetector: DiagramDetector = (txt) => { +const id = 'gantt'; + +const detector: DiagramDetector = (txt) => { return txt.match(/^\s*gantt/) !== null; }; + +const loader = async () => { + const { diagram } = await import('./ganttDiagram'); + return { id, diagram }; +}; + +const plugin: ExternalDiagramDefinition = { + id, + detector, + loader, +}; + +export default plugin; diff --git a/packages/mermaid/src/diagrams/gantt/ganttDiagram.ts b/packages/mermaid/src/diagrams/gantt/ganttDiagram.ts new file mode 100644 index 000000000..b1341052d --- /dev/null +++ b/packages/mermaid/src/diagrams/gantt/ganttDiagram.ts @@ -0,0 +1,13 @@ +// @ts-ignore: TODO Fix ts errors +import ganttParser from './parser/gantt'; +import ganttDb from './ganttDb'; +import ganttRenderer from './ganttRenderer'; +import ganttStyles from './styles'; +import { DiagramDefinition } from '../../diagram-api/types'; + +export const diagram: DiagramDefinition = { + parser: ganttParser, + db: ganttDb, + renderer: ganttRenderer, + styles: ganttStyles, +}; diff --git a/packages/mermaid/src/diagrams/gantt/ganttRenderer.js b/packages/mermaid/src/diagrams/gantt/ganttRenderer.js index 360322b68..faec35a86 100644 --- a/packages/mermaid/src/diagrams/gantt/ganttRenderer.js +++ b/packages/mermaid/src/diagrams/gantt/ganttRenderer.js @@ -1,4 +1,4 @@ -import moment from 'moment'; +import moment from 'moment-mini'; import { log } from '../../logger'; import { select, diff --git a/packages/mermaid/src/diagrams/git/gitGraphDetector.ts b/packages/mermaid/src/diagrams/git/gitGraphDetector.ts index f890501a5..46d09c6e5 100644 --- a/packages/mermaid/src/diagrams/git/gitGraphDetector.ts +++ b/packages/mermaid/src/diagrams/git/gitGraphDetector.ts @@ -1,5 +1,21 @@ import type { DiagramDetector } from '../../diagram-api/types'; +import type { ExternalDiagramDefinition } from '../../diagram-api/types'; -export const gitGraphDetector: DiagramDetector = (txt) => { +const id = 'gitGraph'; + +const detector: DiagramDetector = (txt) => { return txt.match(/^\s*gitGraph/) !== null; }; + +const loader = async () => { + const { diagram } = await import('./gitGraphDiagram'); + return { id, diagram }; +}; + +const plugin: ExternalDiagramDefinition = { + id, + detector, + loader, +}; + +export default plugin; diff --git a/packages/mermaid/src/diagrams/git/gitGraphDiagram.ts b/packages/mermaid/src/diagrams/git/gitGraphDiagram.ts new file mode 100644 index 000000000..9ef3506a0 --- /dev/null +++ b/packages/mermaid/src/diagrams/git/gitGraphDiagram.ts @@ -0,0 +1,13 @@ +// @ts-ignore: TODO Fix ts errors +import gitGraphParser from './parser/gitGraph'; +import gitGraphDb from './gitGraphAst'; +import gitGraphRenderer from './gitGraphRenderer'; +import gitGraphStyles from './styles'; +import { DiagramDefinition } from '../../diagram-api/types'; + +export const diagram: DiagramDefinition = { + parser: gitGraphParser, + db: gitGraphDb, + renderer: gitGraphRenderer, + styles: gitGraphStyles, +}; diff --git a/packages/mermaid/src/diagrams/info/infoDetector.ts b/packages/mermaid/src/diagrams/info/infoDetector.ts index 8bccb578f..a022e3ccb 100644 --- a/packages/mermaid/src/diagrams/info/infoDetector.ts +++ b/packages/mermaid/src/diagrams/info/infoDetector.ts @@ -1,5 +1,20 @@ -import type { DiagramDetector } from '../../diagram-api/types'; +import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types'; -export const infoDetector: DiagramDetector = (txt) => { +const id = 'info'; + +const detector: DiagramDetector = (txt) => { return txt.match(/^\s*info/) !== null; }; + +const loader = async () => { + const { diagram } = await import('./infoDiagram'); + return { id, diagram }; +}; + +const plugin: ExternalDiagramDefinition = { + id, + detector, + loader, +}; + +export default plugin; diff --git a/packages/mermaid/src/diagrams/info/infoDiagram.ts b/packages/mermaid/src/diagrams/info/infoDiagram.ts new file mode 100644 index 000000000..a8100a79f --- /dev/null +++ b/packages/mermaid/src/diagrams/info/infoDiagram.ts @@ -0,0 +1,13 @@ +import { DiagramDefinition } from '../../diagram-api/types'; +// @ts-ignore: TODO Fix ts errors +import parser from './parser/info'; +import db from './infoDb'; +import styles from './styles'; +import renderer from './infoRenderer'; + +export const diagram: DiagramDefinition = { + parser, + db, + renderer, + styles, +}; diff --git a/packages/mermaid/src/diagrams/mindmap/detector.ts b/packages/mermaid/src/diagrams/mindmap/detector.ts index c96b19097..2e2b1c7d6 100644 --- a/packages/mermaid/src/diagrams/mindmap/detector.ts +++ b/packages/mermaid/src/diagrams/mindmap/detector.ts @@ -6,7 +6,7 @@ const detector = (txt: string) => { }; const loader = async () => { - const { diagram } = await import('./diagram-definition.js'); + const { diagram } = await import('./mindmap-definition.js'); return { id, diagram }; }; diff --git a/packages/mermaid/src/diagrams/mindmap/diagram-definition.ts b/packages/mermaid/src/diagrams/mindmap/mindmap-definition.ts similarity index 100% rename from packages/mermaid/src/diagrams/mindmap/diagram-definition.ts rename to packages/mermaid/src/diagrams/mindmap/mindmap-definition.ts diff --git a/packages/mermaid/src/diagrams/pie/pieDetector.ts b/packages/mermaid/src/diagrams/pie/pieDetector.ts index e267c710a..dd1224db9 100644 --- a/packages/mermaid/src/diagrams/pie/pieDetector.ts +++ b/packages/mermaid/src/diagrams/pie/pieDetector.ts @@ -1,6 +1,20 @@ -import type { DiagramDetector } from '../../diagram-api/types'; +import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types'; -export const pieDetector: DiagramDetector = (txt) => { - const logOutput = txt.match(/^\s*pie/) !== null || txt.match(/^\s*bar/) !== null; - return logOutput; +const id = 'pie'; + +const detector: DiagramDetector = (txt) => { + return txt.match(/^\s*pie/) !== null; }; + +const loader = async () => { + const { diagram } = await import('./pieDiagram'); + return { id, diagram }; +}; + +const plugin: ExternalDiagramDefinition = { + id, + detector, + loader, +}; + +export default plugin; diff --git a/packages/mermaid/src/diagrams/pie/pieDiagram.ts b/packages/mermaid/src/diagrams/pie/pieDiagram.ts new file mode 100644 index 000000000..3a586f668 --- /dev/null +++ b/packages/mermaid/src/diagrams/pie/pieDiagram.ts @@ -0,0 +1,13 @@ +import { DiagramDefinition } from '../../diagram-api/types'; +// @ts-ignore: TODO Fix ts errors +import parser from './parser/pie'; +import db from './pieDb'; +import styles from './styles'; +import renderer from './pieRenderer'; + +export const diagram: DiagramDefinition = { + parser, + db, + renderer, + styles, +}; diff --git a/packages/mermaid/src/diagrams/requirement/requirementDetector.ts b/packages/mermaid/src/diagrams/requirement/requirementDetector.ts index 164da6c1a..1102fde0c 100644 --- a/packages/mermaid/src/diagrams/requirement/requirementDetector.ts +++ b/packages/mermaid/src/diagrams/requirement/requirementDetector.ts @@ -1,5 +1,20 @@ -import type { DiagramDetector } from '../../diagram-api/types'; +import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types'; -export const requirementDetector: DiagramDetector = (txt) => { +const id = 'requirement'; + +const detector: DiagramDetector = (txt) => { return txt.match(/^\s*requirement(Diagram)?/) !== null; }; + +const loader = async () => { + const { diagram } = await import('./requirementDiagram'); + return { id, diagram }; +}; + +const plugin: ExternalDiagramDefinition = { + id, + detector, + loader, +}; + +export default plugin; diff --git a/packages/mermaid/src/diagrams/requirement/requirementDiagram.ts b/packages/mermaid/src/diagrams/requirement/requirementDiagram.ts new file mode 100644 index 000000000..37f6177b6 --- /dev/null +++ b/packages/mermaid/src/diagrams/requirement/requirementDiagram.ts @@ -0,0 +1,13 @@ +import { DiagramDefinition } from '../../diagram-api/types'; +// @ts-ignore: TODO Fix ts errors +import parser from './parser/requirementDiagram'; +import db from './requirementDb'; +import styles from './styles'; +import renderer from './requirementRenderer'; + +export const diagram: DiagramDefinition = { + parser, + db, + renderer, + styles, +}; diff --git a/packages/mermaid/src/diagrams/sequence/sequenceDetector.ts b/packages/mermaid/src/diagrams/sequence/sequenceDetector.ts index 52640b134..c436e65d4 100644 --- a/packages/mermaid/src/diagrams/sequence/sequenceDetector.ts +++ b/packages/mermaid/src/diagrams/sequence/sequenceDetector.ts @@ -1,5 +1,20 @@ -import type { DiagramDetector } from '../../diagram-api/types'; +import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types'; -export const sequenceDetector: DiagramDetector = (txt) => { +const id = 'sequence'; + +const detector: DiagramDetector = (txt) => { return txt.match(/^\s*sequenceDiagram/) !== null; }; + +const loader = async () => { + const { diagram } = await import('./sequenceDiagram'); + return { id, diagram }; +}; + +const plugin: ExternalDiagramDefinition = { + id, + detector, + loader, +}; + +export default plugin; diff --git a/packages/mermaid/src/diagrams/sequence/sequenceDiagram.spec.js b/packages/mermaid/src/diagrams/sequence/sequenceDiagram.spec.js index 80850c2f2..08f6abee1 100644 --- a/packages/mermaid/src/diagrams/sequence/sequenceDiagram.spec.js +++ b/packages/mermaid/src/diagrams/sequence/sequenceDiagram.spec.js @@ -2,9 +2,14 @@ import { vi } from 'vitest'; import * as configApi from '../../config'; import mermaidAPI from '../../mermaidAPI'; -import Diagram from '../../Diagram'; +import { Diagram, getDiagramFromText } from '../../Diagram'; import { addDiagrams } from '../../diagram-api/diagram-orchestration'; +beforeAll(async () => { + // Is required to load the sequence diagram + await getDiagramFromText('sequenceDiagram'); +}); + /** * Sequence diagrams require their own very special version of a mocked d3 module * diagrams/sequence/svgDraw uses statements like this with d3 nodes: (note the [0][0]) @@ -176,14 +181,14 @@ Note right of Bob: Bob thinks Bob-->Alice: I am good thanks!`); diagram.db.clear(); }); - it('should handle a sequenceDiagram definition', function () { + it('should handle a sequenceDiagram definition', async function () { const str = ` sequenceDiagram Alice->Bob:Hello Bob, how are you? Note right of Bob: Bob thinks Bob-->Alice: I am good thanks!`; - mermaidAPI.parse(str, diagram); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(actors.Alice.description).toBe('Alice'); actors.Bob.description = 'Bob'; @@ -194,18 +199,18 @@ Bob-->Alice: I am good thanks!`; expect(messages[0].from).toBe('Alice'); expect(messages[2].from).toBe('Bob'); }); - it('should not show sequence numbers per default', function () { + it('should not show sequence numbers per default', async () => { const str = ` sequenceDiagram Alice->Bob:Hello Bob, how are you? Note right of Bob: Bob thinks Bob-->Alice: I am good thanks!`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); diagram.renderer.draw(str, 'tst', '1.2.3', diagram); // needs to be rendered for the correct value of visibility auto numbers expect(diagram.db.showSequenceNumbers()).toBe(false); }); - it('should show sequence numbers when autonumber is enabled', function () { + it('should show sequence numbers when autonumber is enabled', async () => { const str = ` sequenceDiagram autonumber @@ -213,11 +218,11 @@ Alice->Bob:Hello Bob, how are you? Note right of Bob: Bob thinks Bob-->Alice: I am good thanks!`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); diagram.renderer.draw(str, 'tst', '1.2.3', diagram); // needs to be rendered for the correct value of visibility auto numbers expect(diagram.db.showSequenceNumbers()).toBe(true); }); - it('should handle a sequenceDiagram definition with a title:', function () { + it('should handle a sequenceDiagram definition with a title:', async () => { const str = ` sequenceDiagram title: Diagram Title @@ -225,7 +230,7 @@ Alice->Bob:Hello Bob, how are you? Note right of Bob: Bob thinks Bob-->Alice: I am good thanks!`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(actors.Alice.description).toBe('Alice'); actors.Bob.description = 'Bob'; @@ -240,7 +245,7 @@ Bob-->Alice: I am good thanks!`; expect(title).toBe('Diagram Title'); }); - it('should handle a sequenceDiagram definition with a title without a :', function () { + it('should handle a sequenceDiagram definition with a title without a :', async () => { const str = ` sequenceDiagram title Diagram Title @@ -248,7 +253,7 @@ Alice->Bob:Hello Bob, how are you? Note right of Bob: Bob thinks Bob-->Alice: I am good thanks!`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(actors.Alice.description).toBe('Alice'); actors.Bob.description = 'Bob'; @@ -263,7 +268,7 @@ Bob-->Alice: I am good thanks!`; expect(title).toBe('Diagram Title'); }); - it('should handle a sequenceDiagram definition with a accessibility title and description (accDescr)', function () { + it('should handle a sequenceDiagram definition with a accessibility title and description (accDescr)', async () => { const str = ` sequenceDiagram title: Diagram Title @@ -272,13 +277,13 @@ accDescr: Accessibility Description Alice->Bob:Hello Bob, how are you? `; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); expect(diagram.db.getDiagramTitle()).toBe('Diagram Title'); expect(diagram.db.getAccTitle()).toBe('This is the title'); expect(diagram.db.getAccDescription()).toBe('Accessibility Description'); const messages = diagram.db.getMessages(); }); - it('should handle a sequenceDiagram definition with a accessibility title and multiline description (accDescr)', function () { + it('should handle a sequenceDiagram definition with a accessibility title and multiline description (accDescr)', async () => { const str = ` sequenceDiagram accTitle: This is the title @@ -289,19 +294,19 @@ Description Alice->Bob:Hello Bob, how are you? `; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); expect(diagram.db.getAccTitle()).toBe('This is the title'); expect(diagram.db.getAccDescription()).toBe('Accessibility\nDescription'); const messages = diagram.db.getMessages(); }); - it('should space in actor names', function () { + it('should space in actor names', async () => { const str = ` sequenceDiagram Alice->Bob:Hello Bob, how are - you? Bob-->Alice: I am good thanks!`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(actors.Alice.description).toBe('Alice'); actors.Bob.description = 'Bob'; @@ -312,13 +317,13 @@ Bob-->Alice: I am good thanks!`; expect(messages[0].from).toBe('Alice'); expect(messages[1].from).toBe('Bob'); }); - it('should handle dashes in actor names', function () { + it('should handle dashes in actor names', async () => { const str = ` sequenceDiagram Alice-in-Wonderland->Bob:Hello Bob, how are - you? Bob-->Alice-in-Wonderland:I am good thanks!`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(actors['Alice-in-Wonderland'].description).toBe('Alice-in-Wonderland'); expect(actors.Bob.description).toBe('Bob'); @@ -330,7 +335,7 @@ Bob-->Alice-in-Wonderland:I am good thanks!`; expect(messages[1].from).toBe('Bob'); }); - it('should handle dashes in participant names', function () { + it('should handle dashes in participant names', async () => { const str = ` sequenceDiagram participant Alice-in-Wonderland @@ -338,7 +343,7 @@ participant Bob Alice-in-Wonderland->Bob:Hello Bob, how are - you? Bob-->Alice-in-Wonderland:I am good thanks!`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(Object.keys(actors)).toEqual(['Alice-in-Wonderland', 'Bob']); expect(actors['Alice-in-Wonderland'].description).toBe('Alice-in-Wonderland'); @@ -351,7 +356,7 @@ Bob-->Alice-in-Wonderland:I am good thanks!`; expect(messages[1].from).toBe('Bob'); }); - it('should alias participants', function () { + it('should alias participants', async () => { const str = ` sequenceDiagram participant A as Alice @@ -359,7 +364,7 @@ participant B as Bob A->B:Hello Bob, how are you? B-->A: I am good thanks!`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); @@ -372,7 +377,7 @@ B-->A: I am good thanks!`; expect(messages[0].from).toBe('A'); expect(messages[1].from).toBe('B'); }); - it('should alias a mix of actors and participants apa12', function () { + it('should alias a mix of actors and participants apa12', async () => { const str = ` sequenceDiagram actor Alice as Alice2 @@ -385,7 +390,7 @@ sequenceDiagram John->>Mandy: Hi Mandy Mandy ->>Joan: Hi Joan`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(Object.keys(actors)).toEqual(['Alice', 'Bob', 'John', 'Mandy', 'Joan']); @@ -400,7 +405,7 @@ sequenceDiagram expect(messages[0].from).toBe('Alice'); expect(messages[4].to).toBe('Joan'); }); - it('should alias actors apa13', function () { + it('should alias actors apa13', async () => { const str = ` sequenceDiagram actor A as Alice @@ -408,7 +413,7 @@ actor B as Bob A->B:Hello Bob, how are you? B-->A: I am good thanks!`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(Object.keys(actors)).toEqual(['A', 'B']); @@ -420,12 +425,12 @@ B-->A: I am good thanks!`; expect(messages[0].from).toBe('A'); expect(messages[1].from).toBe('B'); }); - it('should handle in async messages', function () { + it('should handle in async messages', async () => { const str = ` sequenceDiagram Alice-xBob:Hello Bob, how are you?`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(actors.Alice.description).toBe('Alice'); expect(actors.Bob.description).toBe('Bob'); @@ -435,12 +440,12 @@ Alice-xBob:Hello Bob, how are you?`; expect(messages.length).toBe(1); expect(messages[0].type).toBe(diagram.db.LINETYPE.SOLID_CROSS); }); - it('should handle in async dotted messages', function () { + it('should handle in async dotted messages', async () => { const str = ` sequenceDiagram Alice--xBob:Hello Bob, how are you?`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(actors.Alice.description).toBe('Alice'); expect(actors.Bob.description).toBe('Bob'); @@ -450,12 +455,12 @@ Alice--xBob:Hello Bob, how are you?`; expect(messages.length).toBe(1); expect(messages[0].type).toBe(diagram.db.LINETYPE.DOTTED_CROSS); }); - it('should handle in sync messages', function () { + it('should handle in sync messages', async () => { const str = ` sequenceDiagram Alice-)Bob:Hello Bob, how are you?`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(actors.Alice.description).toBe('Alice'); expect(actors.Bob.description).toBe('Bob'); @@ -465,12 +470,12 @@ Alice-)Bob:Hello Bob, how are you?`; expect(messages.length).toBe(1); expect(messages[0].type).toBe(diagram.db.LINETYPE.SOLID_POINT); }); - it('should handle in sync dotted messages', function () { + it('should handle in sync dotted messages', async () => { const str = ` sequenceDiagram Alice--)Bob:Hello Bob, how are you?`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(actors.Alice.description).toBe('Alice'); expect(actors.Bob.description).toBe('Bob'); @@ -480,12 +485,12 @@ Alice--)Bob:Hello Bob, how are you?`; expect(messages.length).toBe(1); expect(messages[0].type).toBe(diagram.db.LINETYPE.DOTTED_POINT); }); - it('should handle in arrow messages', function () { + it('should handle in arrow messages', async () => { const str = ` sequenceDiagram Alice->>Bob:Hello Bob, how are you?`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(actors.Alice.description).toBe('Alice'); expect(actors.Bob.description).toBe('Bob'); @@ -495,10 +500,10 @@ Alice->>Bob:Hello Bob, how are you?`; expect(messages.length).toBe(1); expect(messages[0].type).toBe(diagram.db.LINETYPE.SOLID); }); - it('should handle in arrow messages', function () { + it('should handle in arrow messages', async () => { const str = 'sequenceDiagram\n' + 'Alice-->>Bob:Hello Bob, how are you?'; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(actors.Alice.description).toBe('Alice'); expect(actors.Bob.description).toBe('Bob'); @@ -508,7 +513,7 @@ Alice->>Bob:Hello Bob, how are you?`; expect(messages.length).toBe(1); expect(messages[0].type).toBe(diagram.db.LINETYPE.DOTTED); }); - it('should handle actor activation', function () { + it('should handle actor activation', async () => { const str = ` sequenceDiagram Alice-->>Bob:Hello Bob, how are you? @@ -516,7 +521,7 @@ activate Bob Bob-->>Alice:Hello Alice, I'm fine and you? deactivate Bob`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(actors.Alice.description).toBe('Alice'); expect(actors.Bob.description).toBe('Bob'); @@ -531,13 +536,13 @@ deactivate Bob`; expect(messages[3].type).toBe(diagram.db.LINETYPE.ACTIVE_END); expect(messages[3].from.actor).toBe('Bob'); }); - it('should handle actor one line notation activation', function () { + it('should handle actor one line notation activation', async () => { const str = ` sequenceDiagram Alice-->>+Bob:Hello Bob, how are you? Bob-->>- Alice:Hello Alice, I'm fine and you?`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(actors.Alice.description).toBe('Alice'); expect(actors.Bob.description).toBe('Bob'); @@ -552,7 +557,7 @@ deactivate Bob`; expect(messages[3].type).toBe(diagram.db.LINETYPE.ACTIVE_END); expect(messages[3].from.actor).toBe('Bob'); }); - it('should handle stacked activations', function () { + it('should handle stacked activations', async () => { const str = ` sequenceDiagram Alice-->>+Bob:Hello Bob, how are you? @@ -560,7 +565,7 @@ deactivate Bob`; Bob-->>- Alice:Hello Alice, please meet Carol? Carol->>- Bob:Oh Bob, I'm so happy to be here!`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(actors.Alice.description).toBe('Alice'); expect(actors.Bob.description).toBe('Bob'); @@ -579,7 +584,7 @@ deactivate Bob`; expect(messages[7].type).toBe(diagram.db.LINETYPE.ACTIVE_END); expect(messages[7].from.actor).toBe('Carol'); }); - it('should handle fail parsing when activating an inactive participant', function () { + it('should handle fail parsing when activating an inactive participant', async () => { const str = ` sequenceDiagram participant user as End User @@ -598,14 +603,14 @@ deactivate Bob`; let error = false; try { - mermaidAPI.parse(str); + await mermaidAPI.parse(str); } catch (e) { error = true; } expect(error).toBe(true); }); - it('should handle comments in a sequenceDiagram', function () { + it('should handle comments in a sequenceDiagram', async () => { const str = ` sequenceDiagram Alice->Bob: Hello Bob, how are you? @@ -613,7 +618,7 @@ deactivate Bob`; Note right of Bob: Bob thinks Bob-->Alice: I am good thanks!`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(actors.Alice.description).toBe('Alice'); actors.Bob.description = 'Bob'; @@ -624,7 +629,7 @@ deactivate Bob`; expect(messages[0].from).toBe('Alice'); expect(messages[2].from).toBe('Bob'); }); - it('should handle new lines in a sequenceDiagram', function () { + it('should handle new lines in a sequenceDiagram', async () => { const str = ` sequenceDiagram Alice->Bob: Hello Bob, how are you? @@ -634,7 +639,7 @@ deactivate Bob`; Bob-->Alice: I am good thanks! `; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(actors.Alice.description).toBe('Alice'); actors.Bob.description = 'Bob'; @@ -645,11 +650,11 @@ deactivate Bob`; expect(messages[0].from).toBe('Alice'); expect(messages[2].from).toBe('Bob'); }); - it('should handle semicolons', function () { + it('should handle semicolons', async () => { const str = ` sequenceDiagram;Alice->Bob: Hello Bob, how are you?;Note right of Bob: Bob thinks;Bob-->Alice: I am good thanks!;`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(actors.Alice.description).toBe('Alice'); actors.Bob.description = 'Bob'; @@ -660,7 +665,7 @@ sequenceDiagram;Alice->Bob: Hello Bob, how are you?;Note right of Bob: Bob think expect(messages[0].from).toBe('Alice'); expect(messages[2].from).toBe('Bob'); }); - it('should handle one leading space in lines in a sequenceDiagram', function () { + it('should handle one leading space in lines in a sequenceDiagram', async () => { const str = ` sequenceDiagram Alice->Bob: Hello Bob, how are you? @@ -669,7 +674,7 @@ sequenceDiagram Note right of Bob: Bob thinks Bob-->Alice: I am good thanks!`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(actors.Alice.description).toBe('Alice'); actors.Bob.description = 'Bob'; @@ -680,7 +685,7 @@ Bob-->Alice: I am good thanks!`; expect(messages[0].from).toBe('Alice'); expect(messages[2].from).toBe('Bob'); }); - it('should handle several leading spaces in lines in a sequenceDiagram', function () { + it('should handle several leading spaces in lines in a sequenceDiagram', async () => { const str = ` sequenceDiagram Alice->Bob: Hello Bob, how are you? @@ -689,7 +694,7 @@ sequenceDiagram Note right of Bob: Bob thinks Bob-->Alice: I am good thanks!`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(actors.Alice.description).toBe('Alice'); actors.Bob.description = 'Bob'; @@ -700,7 +705,7 @@ Bob-->Alice: I am good thanks!`; expect(messages[0].from).toBe('Alice'); expect(messages[2].from).toBe('Bob'); }); - it('should handle several leading spaces in lines in a sequenceDiagram', function () { + it('should handle several leading spaces in lines in a sequenceDiagram', async () => { const str = ` sequenceDiagram participant Alice @@ -714,7 +719,7 @@ Note right of John: Rational thoughts
prevail... John->Bob: How about you? Bob-->John: Jolly good!`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(actors.Alice.description).toBe('Alice'); actors.Bob.description = 'Bob'; @@ -725,7 +730,7 @@ Bob-->John: Jolly good!`; expect(messages[0].from).toBe('Alice'); expect(messages[2].from).toBe('John'); }); - it('should handle different line breaks', function () { + it('should handle different line breaks', async () => { const str = ` sequenceDiagram participant 1 as multiline
text @@ -742,7 +747,7 @@ note right of 4: multiline
text note right of 1: multiline
text `; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(actors['1'].description).toBe('multiline
text'); @@ -760,7 +765,7 @@ note right of 1: multiline
text expect(messages[6].message).toBe('multiline
text'); expect(messages[7].message).toBe('multiline
text'); }); - it('should handle notes and messages without wrap specified', function () { + it('should handle notes and messages without wrap specified', async () => { const str = ` sequenceDiagram participant 1 @@ -777,7 +782,7 @@ note right of 4: multiline
text note right of 1:nowrap: multiline
text `; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const messages = diagram.db.getMessages(); expect(messages[0].message).toBe('single-line text'); @@ -799,7 +804,7 @@ note right of 1:nowrap: multiline
text expect(messages[6].wrap).toBe(false); expect(messages[7].wrap).toBe(false); }); - it('should handle notes and messages with wrap specified', function () { + it('should handle notes and messages with wrap specified', async () => { const str = ` sequenceDiagram participant 1 @@ -812,7 +817,7 @@ note right of 2:wrap: single-line text note right of 3:wrap: multiline
text `; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const messages = diagram.db.getMessages(); expect(messages[0].message).toBe('single-line text'); @@ -824,7 +829,7 @@ note right of 3:wrap: multiline
text expect(messages[2].wrap).toBe(true); expect(messages[3].wrap).toBe(true); }); - it('should handle notes and messages with nowrap or line breaks', function () { + it('should handle notes and messages with nowrap or line breaks', async () => { const str = ` sequenceDiagram participant 1 @@ -833,7 +838,7 @@ participant 2 note right of 2: single-line text `; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const messages = diagram.db.getMessages(); expect(messages[0].message).toBe('single-line text'); @@ -841,20 +846,20 @@ note right of 2: single-line text expect(messages[0].wrap).toBe(false); expect(messages[1].wrap).toBe(false); }); - it('should handle notes over a single actor', function () { + it('should handle notes over a single actor', async () => { const str = ` sequenceDiagram Alice->Bob: Hello Bob, how are you? Note over Bob: Bob thinks `; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const messages = diagram.db.getMessages(); expect(messages[1].from).toBe('Bob'); expect(messages[1].to).toBe('Bob'); }); - it('should handle notes over multiple actors', function () { + it('should handle notes over multiple actors', async () => { const str = ` sequenceDiagram Alice->Bob: Hello Bob, how are you? @@ -862,7 +867,7 @@ Note over Alice,Bob: confusion Note over Bob,Alice: resolution `; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const messages = diagram.db.getMessages(); expect(messages[1].from).toBe('Alice'); @@ -870,7 +875,7 @@ Note over Bob,Alice: resolution expect(messages[2].from).toBe('Bob'); expect(messages[2].to).toBe('Alice'); }); - it('should handle loop statements', function () { + it('should handle loop statements', async () => { const str = ` sequenceDiagram Alice->Bob: Hello Bob, how are you? @@ -882,7 +887,7 @@ loop Multiple happy responses Bob-->Alice: I am good thanks! end`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(actors.Alice.description).toBe('Alice'); actors.Bob.description = 'Bob'; @@ -893,7 +898,7 @@ end`; expect(messages[0].from).toBe('Alice'); expect(messages[1].from).toBe('Bob'); }); - it('should add a rect around sequence', function () { + it('should add a rect around sequence', async () => { const str = ` sequenceDiagram Alice->Bob: Hello Bob, how are you? @@ -904,7 +909,7 @@ end`; end `; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(actors.Alice.description).toBe('Alice'); actors.Bob.description = 'Bob'; @@ -917,7 +922,7 @@ end`; expect(messages[4].type).toEqual(diagram.db.LINETYPE.RECT_END); }); - it('should allow for nested rects', function () { + it('should allow for nested rects', async () => { const str = ` sequenceDiagram Alice->Bob: Hello Bob, how are you? @@ -929,7 +934,7 @@ end`; Bob-->Alice: I am good thanks end `; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(actors.Alice.description).toBe('Alice'); actors.Bob.description = 'Bob'; @@ -944,7 +949,7 @@ end`; expect(messages[5].type).toEqual(diagram.db.LINETYPE.DOTTED_OPEN); expect(messages[6].type).toEqual(diagram.db.LINETYPE.RECT_END); }); - it('should handle opt statements', function () { + it('should handle opt statements', async () => { const str = ` sequenceDiagram Alice->Bob: Hello Bob, how are you? @@ -956,7 +961,7 @@ opt Perhaps a happy response Bob-->Alice: I am good thanks! end`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(actors.Alice.description).toBe('Alice'); actors.Bob.description = 'Bob'; @@ -967,7 +972,7 @@ end`; expect(messages[0].from).toBe('Alice'); expect(messages[1].from).toBe('Bob'); }); - it('should handle alt statements', function () { + it('should handle alt statements', async () => { const str = ` sequenceDiagram Alice->Bob: Hello Bob, how are you? @@ -981,7 +986,7 @@ else isSick Bob-->Alice: Feel sick... end`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(actors.Alice.description).toBe('Alice'); @@ -993,7 +998,7 @@ end`; expect(messages[0].from).toBe('Alice'); expect(messages[1].from).toBe('Bob'); }); - it('should handle alt statements with multiple elses', function () { + it('should handle alt statements with multiple elses', async () => { const str = ` sequenceDiagram Alice->Bob: Hello Bob, how are you? @@ -1008,7 +1013,7 @@ Bob-->Alice: Feel sick... else default Bob-->Alice: :-) end`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const messages = diagram.db.getMessages(); expect(messages.length).toBe(9); expect(messages[1].from).toBe('Bob'); @@ -1020,14 +1025,14 @@ end`; expect(messages[7].from).toBe('Bob'); expect(messages[8].type).toBe(diagram.db.LINETYPE.ALT_END); }); - it('should handle critical statements without options', function () { + it('should handle critical statements without options', async () => { const str = ` sequenceDiagram critical Establish a connection to the DB Service-->DB: connect end`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(actors.Service.description).toBe('Service'); @@ -1040,7 +1045,7 @@ sequenceDiagram expect(messages[1].from).toBe('Service'); expect(messages[2].type).toBe(diagram.db.LINETYPE.CRITICAL_END); }); - it('should handle critical statements with options', function () { + it('should handle critical statements with options', async () => { const str = ` sequenceDiagram critical Establish a connection to the DB @@ -1051,7 +1056,7 @@ sequenceDiagram Service-->Service: Log different error end`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(actors.Service.description).toBe('Service'); @@ -1068,7 +1073,7 @@ sequenceDiagram expect(messages[5].from).toBe('Service'); expect(messages[6].type).toBe(diagram.db.LINETYPE.CRITICAL_END); }); - it('should handle break statements', function () { + it('should handle break statements', async () => { const str = ` sequenceDiagram Consumer-->API: Book something @@ -1078,7 +1083,7 @@ sequenceDiagram end API-->BillingService: Start billing process`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(actors.Consumer.description).toBe('Consumer'); @@ -1094,7 +1099,7 @@ sequenceDiagram expect(messages[4].type).toBe(diagram.db.LINETYPE.BREAK_END); expect(messages[5].from).toBe('API'); }); - it('should handle par statements a sequenceDiagram', function () { + it('should handle par statements a sequenceDiagram', async () => { const str = ` sequenceDiagram par Parallel one @@ -1108,7 +1113,7 @@ Alice->>Bob: What do you think about it? Bob-->>Alice: It's good! end`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(actors.Alice.description).toBe('Alice'); @@ -1121,26 +1126,26 @@ end`; expect(messages[1].from).toBe('Alice'); expect(messages[2].from).toBe('Bob'); }); - it('should handle special characters in signals', function () { + it('should handle special characters in signals', async () => { const str = 'sequenceDiagram\n' + 'Alice->Bob: -:<>,;# comment'; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const messages = diagram.db.getMessages(); expect(messages[0].message).toBe('-:<>,'); }); - it('should handle special characters in notes', function () { + it('should handle special characters in notes', async () => { const str = ` sequenceDiagram Alice->Bob: Hello Bob, how are you? Note right of Bob: -:<>,;# comment`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const messages = diagram.db.getMessages(); expect(messages[1].message).toBe('-:<>,'); }); - it('should handle special characters in loop', function () { + it('should handle special characters in loop', async () => { const str = ` sequenceDiagram Alice->Bob: Hello Bob, how are you? @@ -1148,12 +1153,12 @@ loop -:<>,;# comment Bob-->Alice: I am good thanks! end`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const messages = diagram.db.getMessages(); expect(messages[1].message).toBe('-:<>,'); }); - it('should handle special characters in opt', function () { + it('should handle special characters in opt', async () => { const str = ` sequenceDiagram Alice->Bob: Hello Bob, how are you? @@ -1161,12 +1166,12 @@ opt -:<>,;# comment Bob-->Alice: I am good thanks! end`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const messages = diagram.db.getMessages(); expect(messages[1].message).toBe('-:<>,'); }); - it('should handle special characters in alt', function () { + it('should handle special characters in alt', async () => { const str = ` sequenceDiagram Alice->Bob: Hello Bob, how are you? @@ -1176,13 +1181,13 @@ else ,<>:-#; comment Bob-->Alice: I am good thanks! end`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const messages = diagram.db.getMessages(); expect(messages[1].message).toBe('-:<>,'); expect(messages[3].message).toBe(',<>:-'); }); - it('should handle special characters in par', function () { + it('should handle special characters in par', async () => { const str = ` sequenceDiagram Alice->Bob: Hello Bob, how are you? @@ -1192,13 +1197,13 @@ and ,<>:-#; comment Bob-->Alice: I am good thanks! end`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const messages = diagram.db.getMessages(); expect(messages[1].message).toBe('-:<>,'); expect(messages[3].message).toBe(',<>:-'); }); - it('should handle no-label loop', function () { + it('should handle no-label loop', async () => { const str = ` sequenceDiagram Alice->Bob: Hello Bob, how are you? @@ -1206,13 +1211,13 @@ loop Bob-->Alice: I am good thanks! end`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const messages = diagram.db.getMessages(); expect(messages[1].message).toBe(''); expect(messages[2].message).toBe('I am good thanks!'); }); - it('should handle no-label opt', function () { + it('should handle no-label opt', async () => { const str = ` sequenceDiagram Alice->Bob: Hello Bob, how are you? @@ -1220,13 +1225,13 @@ opt # comment Bob-->Alice: I am good thanks! end`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const messages = diagram.db.getMessages(); expect(messages[1].message).toBe(''); expect(messages[2].message).toBe('I am good thanks!'); }); - it('should handle no-label alt', function () { + it('should handle no-label alt', async () => { const str = ` sequenceDiagram Alice->Bob: Hello Bob, how are you? @@ -1235,7 +1240,7 @@ else # comment Bob-->Alice: I am good thanks! end`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const messages = diagram.db.getMessages(); expect(messages[1].message).toBe(''); @@ -1243,7 +1248,7 @@ end`; expect(messages[3].message).toBe(''); expect(messages[4].message).toBe('I am good thanks!'); }); - it('should handle no-label par', function () { + it('should handle no-label par', async () => { const str = ` sequenceDiagram Alice->Bob: Hello Bob, how are you? @@ -1252,7 +1257,7 @@ and # comment Bob-->Alice: I am good thanks! end`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const messages = diagram.db.getMessages(); expect(messages[1].message).toBe(''); @@ -1261,7 +1266,7 @@ end`; expect(messages[4].message).toBe('I am good thanks!'); }); - it('should handle links', function () { + it('should handle links', async () => { const str = ` sequenceDiagram participant a as Alice @@ -1275,7 +1280,7 @@ link a: Swagger @ https://swagger.contoso.com link a: Tests @ https://tests.contoso.com/?svc=alice@contoso.com `; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(actors.a.links['Repo']).toBe('https://repo.contoso.com/'); expect(actors.b.links['Repo']).toBe(undefined); @@ -1288,7 +1293,7 @@ link a: Tests @ https://tests.contoso.com/?svc=alice@contoso.com expect(actors.a.links['Tests']).toBe('https://tests.contoso.com/?svc=alice@contoso.com'); }); - it('should handle properties EXPERIMENTAL: USE WITH CAUTION', function () { + it('should handle properties EXPERIMENTAL: USE WITH CAUTION', async () => { //Be aware that the syntax for "properties" is likely to be changed. const str = ` sequenceDiagram @@ -1299,7 +1304,7 @@ properties a: {"class": "internal-service-actor", "icon": "@clock"} properties b: {"class": "external-service-actor", "icon": "@computer"} `; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(actors.a.properties['class']).toBe('internal-service-actor'); expect(actors.b.properties['class']).toBe('external-service-actor'); @@ -1308,7 +1313,7 @@ properties b: {"class": "external-service-actor", "icon": "@computer"} expect(actors.c.properties['class']).toBe(undefined); }); - it('should handle box', function () { + it('should handle box', async () => { const str = ` sequenceDiagram box green Group 1 @@ -1324,14 +1329,14 @@ link a: Swagger @ https://swagger.contoso.com link a: Tests @ https://tests.contoso.com/?svc=alice@contoso.com `; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const boxes = diagram.db.getBoxes(); expect(boxes[0].name).toEqual('Group 1'); expect(boxes[0].actorKeys).toEqual(['a', 'b']); expect(boxes[0].fill).toEqual('green'); }); - it('should handle box without color', function () { + it('should handle box without color', async () => { const str = ` sequenceDiagram box Group 1 @@ -1347,14 +1352,14 @@ link a: Tests @ https://tests.contoso.com/?svc=alice@contoso.com link a: Tests @ https://tests.contoso.com/?svc=alice@contoso.com `; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const boxes = diagram.db.getBoxes(); expect(boxes[0].name).toEqual('Group 1'); expect(boxes[0].actorKeys).toEqual(['a', 'b']); expect(boxes[0].fill).toEqual('transparent'); }); - it('should handle box without description', function () { + it('should handle box without description', async () => { const str = ` sequenceDiagram box Aqua @@ -1370,7 +1375,7 @@ link a: Tests @ https://tests.contoso.com/?svc=alice@contoso.com link a: Tests @ https://tests.contoso.com/?svc=alice@contoso.com `; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const boxes = diagram.db.getBoxes(); expect(boxes[0].name).toBeFalsy(); expect(boxes[0].actorKeys).toEqual(['a', 'b']); @@ -1403,7 +1408,7 @@ describe('when checking the bounds in a sequenceDiagram', function () { diagram.renderer.bounds.init(); conf = diagram.db.getConfig(); }); - it('should handle a simple bound call', function () { + it('should handle a simple bound call', async () => { diagram.renderer.bounds.insert(100, 100, 200, 200); const { bounds } = diagram.renderer.bounds.getBounds(); @@ -1412,7 +1417,7 @@ describe('when checking the bounds in a sequenceDiagram', function () { expect(bounds.stopx).toBe(200); expect(bounds.stopy).toBe(200); }); - it('should handle an expanding bound', function () { + it('should handle an expanding bound', async () => { diagram.renderer.bounds.insert(100, 100, 200, 200); diagram.renderer.bounds.insert(25, 50, 300, 400); @@ -1422,7 +1427,7 @@ describe('when checking the bounds in a sequenceDiagram', function () { expect(bounds.stopx).toBe(300); expect(bounds.stopy).toBe(400); }); - it('should handle inserts within the bound without changing the outer bounds', function () { + it('should handle inserts within the bound without changing the outer bounds', async () => { diagram.renderer.bounds.insert(100, 100, 200, 200); diagram.renderer.bounds.insert(25, 50, 300, 400); diagram.renderer.bounds.insert(125, 150, 150, 200); @@ -1433,7 +1438,7 @@ describe('when checking the bounds in a sequenceDiagram', function () { expect(bounds.stopx).toBe(300); expect(bounds.stopy).toBe(400); }); - it('should handle a loop without expanding the area', function () { + it('should handle a loop without expanding the area', async () => { diagram.renderer.bounds.insert(25, 50, 300, 400); diagram.renderer.bounds.verticalPos = 150; diagram.renderer.bounds.newLoop(); @@ -1454,7 +1459,7 @@ describe('when checking the bounds in a sequenceDiagram', function () { expect(bounds.stopx).toBe(300); expect(bounds.stopy).toBe(400); }); - it('should handle multiple loops withtout expanding the bounds', function () { + it('should handle multiple loops withtout expanding the bounds', async () => { diagram.renderer.bounds.insert(100, 100, 1000, 1000); diagram.renderer.bounds.verticalPos = 200; diagram.renderer.bounds.newLoop(); @@ -1485,7 +1490,7 @@ describe('when checking the bounds in a sequenceDiagram', function () { expect(bounds.stopx).toBe(1000); expect(bounds.stopy).toBe(1000); }); - it('should handle a loop that expands the area', function () { + it('should handle a loop that expands the area', async () => { diagram.renderer.bounds.insert(100, 100, 200, 200); diagram.renderer.bounds.verticalPos = 200; diagram.renderer.bounds.newLoop(); @@ -1555,13 +1560,13 @@ Bob-->Alice: I am good thanks!`); }); ['tspan', 'fo', 'old', undefined].forEach(function (textPlacement) { it(` -it should handle one actor, when textPlacement is ${textPlacement}`, function () { +it should handle one actor, when textPlacement is ${textPlacement}`, async () => { const str = ` sequenceDiagram participant Alice`; // mermaidAPI.reinitialize({ sequence: { textPlacement: textPlacement } }); - mermaidAPI.parse(str); + await mermaidAPI.parse(str); // diagram.renderer.setConf(mermaidAPI.getConfig().sequence); diagram.renderer.draw(str, 'tst', '1.2.3', diagram); @@ -1572,7 +1577,7 @@ participant Alice`; expect(bounds.stopy).toBe(conf.height); }); }); - it('should handle same actor with different whitespace properly', function () { + it('should handle same actor with different whitespace properly', async () => { const str = ` sequenceDiagram participant Alice @@ -1580,12 +1585,12 @@ participant Alice participant Alice `; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); const actors = diagram.db.getActors(); expect(Object.keys(actors)).toEqual(['Alice']); }); - it('should handle one actor and a centered note', function () { + it('should handle one actor and a centered note', async () => { const str = ` sequenceDiagram participant Alice @@ -1593,7 +1598,7 @@ Note over Alice: Alice thinks `; expect(mermaidAPI.getConfig().sequence.mirrorActors).toBeFalsy(); - mermaidAPI.parse(str); + await mermaidAPI.parse(str); diagram.renderer.draw(str, 'tst', '1.2.3', diagram); const { bounds, models } = diagram.renderer.bounds.getBounds(); @@ -1603,13 +1608,13 @@ Note over Alice: Alice thinks // 10 comes from mock of text height expect(bounds.stopy).toBe(models.lastNote().stopy); }); - it('should handle one actor and a note to the left', function () { + it('should handle one actor and a note to the left', async () => { const str = ` sequenceDiagram participant Alice Note left of Alice: Alice thinks`; - mermaidAPI.parse(str, diagram); + await mermaidAPI.parse(str); diagram.renderer.draw(str, 'tst', '1.2.3', diagram); const { bounds, models } = diagram.renderer.bounds.getBounds(); @@ -1619,13 +1624,13 @@ Note left of Alice: Alice thinks`; // 10 comes from mock of text height expect(bounds.stopy).toBe(models.lastNote().stopy); }); - it('should handle one actor and a note to the right', function () { + it('should handle one actor and a note to the right', async () => { const str = ` sequenceDiagram participant Alice Note right of Alice: Alice thinks`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); diagram.renderer.draw(str, 'tst', '1.2.3', diagram); const { bounds, models } = diagram.renderer.bounds.getBounds(); @@ -1635,12 +1640,12 @@ Note right of Alice: Alice thinks`; // 10 comes from mock of text height expect(bounds.stopy).toBe(models.lastNote().stopy); }); - it('should handle two actors', function () { + it('should handle two actors', async () => { const str = ` sequenceDiagram Alice->Bob: Hello Bob, how are you?`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); diagram.renderer.draw(str, 'tst', '1.2.3', diagram); const { bounds, models } = diagram.renderer.bounds.getBounds(); @@ -1649,7 +1654,7 @@ Alice->Bob: Hello Bob, how are you?`; expect(bounds.stopx).toBe(conf.width * 2 + conf.actorMargin); expect(bounds.stopy).toBe(models.lastMessage().stopy + 10); }); - it('should handle two actors in a box', function () { + it('should handle two actors in a box', async () => { const str = ` sequenceDiagram box rgb(34, 56, 0) Group1 @@ -1658,7 +1663,7 @@ participant Bob end Alice->Bob: Hello Bob, how are you?`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); diagram.renderer.draw(str, 'tst', '1.2.3', diagram); const { bounds, models } = diagram.renderer.bounds.getBounds(); @@ -1667,13 +1672,13 @@ Alice->Bob: Hello Bob, how are you?`; expect(bounds.stopx).toBe(conf.width * 2 + conf.actorMargin + conf.boxTextMargin * 2); expect(bounds.stopy).toBe(models.lastMessage().stopy + 20); }); - it('should handle two actors with init directive', function () { + it('should handle two actors with init directive', async () => { const str = ` %%{init: {'logLevel': 0}}%% sequenceDiagram Alice->Bob: Hello Bob, how are you?`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); diagram.renderer.draw(str, 'tst', '1.2.3', diagram); const { bounds, models } = diagram.renderer.bounds.getBounds(); @@ -1684,7 +1689,7 @@ Alice->Bob: Hello Bob, how are you?`; expect(bounds.stopx).toBe(conf.width * 2 + conf.actorMargin); expect(bounds.stopy).toBe(models.lastMessage().stopy + 10); }); - it('should handle two actors with init directive with multiline directive', function () { + it('should handle two actors with init directive with multiline directive', async () => { const str = ` %%{init: { 'logLevel': 0}}%% sequenceDiagram @@ -1693,7 +1698,7 @@ wrap }%% Alice->Bob: Hello Bob, how are you?`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); diagram.renderer.draw(str, 'tst', '1.2.3', diagram); const msgs = diagram.db.getMessages(); @@ -1706,7 +1711,7 @@ Alice->Bob: Hello Bob, how are you?`; expect(bounds.stopy).toBe(models.lastMessage().stopy + 10); expect(msgs.every((v) => v.wrap)).toBe(true); }); - it('should handle two actors and two centered shared notes', function () { + it('should handle two actors and two centered shared notes', async () => { const str = ` sequenceDiagram Alice->Bob: Hello Bob, how are you? @@ -1714,7 +1719,7 @@ Note over Alice,Bob: Looks Note over Bob,Alice: Looks back `; // mermaidAPI.initialize({logLevel:0}) - mermaidAPI.parse(str); + await mermaidAPI.parse(str); diagram.renderer.draw(str, 'tst', '1.2.3', diagram); const { bounds, models } = diagram.renderer.bounds.getBounds(); @@ -1723,13 +1728,13 @@ Note over Bob,Alice: Looks back expect(bounds.stopx).toBe(conf.width * 2 + conf.actorMargin); expect(bounds.stopy).toBe(models.lastNote().stopy); }); - it('should draw two actors and two messages', function () { + it('should draw two actors and two messages', async () => { const str = ` sequenceDiagram Alice->Bob: Hello Bob, how are you? Bob->Alice: Fine!`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); diagram.renderer.draw(str, 'tst', '1.2.3', diagram); const { bounds, models } = diagram.renderer.bounds.getBounds(); @@ -1738,14 +1743,14 @@ Bob->Alice: Fine!`; expect(bounds.stopx).toBe(conf.width * 2 + conf.actorMargin); expect(bounds.stopy).toBe(models.lastMessage().stopy + 10); }); - it('should draw two actors notes to the right', function () { + it('should draw two actors notes to the right', async () => { const str = ` sequenceDiagram Alice->Bob: Hello Bob, how are you? Note right of Bob: Bob thinks Bob->Alice: Fine!`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); diagram.renderer.draw(str, 'tst', '1.2.3', diagram); const { bounds, models } = diagram.renderer.bounds.getBounds(); @@ -1757,14 +1762,14 @@ Bob->Alice: Fine!`; expect(bounds.stopx).toBe(expStopX); expect(bounds.stopy).toBe(models.lastMessage().stopy + 10); }); - it('should draw two actors notes to the left', function () { + it('should draw two actors notes to the left', async () => { const str = ` sequenceDiagram Alice->Bob: Hello Bob, how are you? Note left of Alice: Bob thinks Bob->Alice: Fine!`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); diagram.renderer.draw(str, 'tst', '1.2.3', diagram); const { bounds, models } = diagram.renderer.bounds.getBounds(); @@ -1774,14 +1779,14 @@ Bob->Alice: Fine!`; expect(bounds.stopx).toBe(conf.width * 2 + conf.actorMargin); expect(bounds.stopy).toBe(models.lastMessage().stopy + 10); }); - it('should draw two actors notes to the left with text wrapped (inline)', function () { + it('should draw two actors notes to the left with text wrapped (inline)', async () => { const str = ` sequenceDiagram Alice->>Bob:wrap: Hello Bob, how are you? If you are not available right now, I can leave you a message. Please get back to me as soon as you can! Note left of Alice: Bob thinks Bob->>Alice: Fine!`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); diagram.renderer.draw(str, 'tst', '1.2.3', diagram); const { bounds, models } = diagram.renderer.bounds.getBounds(); @@ -1793,7 +1798,7 @@ Bob->>Alice: Fine!`; expect(bounds.stopx).toBe(conf.width * 2 + conf.actorMargin); expect(bounds.stopy).toBe(models.lastMessage().stopy + 10); }); - it('should draw two actors notes to the left with text wrapped (directive)', function () { + it('should draw two actors notes to the left with text wrapped (directive)', async () => { const str = ` %%{init: { 'theme': 'dark' } }%% sequenceDiagram @@ -1802,7 +1807,7 @@ Alice->>Bob: Hello Bob, how are you? If you are not available right now, I can l Note left of Alice: Bob thinks Bob->>Alice: Fine!`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); diagram.renderer.draw(str, 'tst', '1.2.3', diagram); const { bounds, models } = diagram.renderer.bounds.getBounds(); @@ -1816,7 +1821,7 @@ Bob->>Alice: Fine!`; expect(bounds.stopx).toBe(conf.width * 2 + conf.actorMargin); expect(bounds.stopy).toBe(models.lastMessage().stopy + 10); }); - it('should draw two actors notes to the left with text wrapped and the init directive sets the theme to dark', function () { + it('should draw two actors notes to the left with text wrapped and the init directive sets the theme to dark', async () => { const str = ` %%{init:{'theme':'dark'}}%% sequenceDiagram @@ -1825,7 +1830,7 @@ Alice->>Bob: Hello Bob, how are you? If you are not available right now, I can l Note left of Alice: Bob thinks Bob->>Alice: Fine!`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); diagram.renderer.draw(str, 'tst', '1.2.3', diagram); const { bounds, models } = diagram.renderer.bounds.getBounds(); @@ -1839,7 +1844,7 @@ Bob->>Alice: Fine!`; expect(bounds.stopx).toBe(conf.width * 2 + conf.actorMargin); expect(bounds.stopy).toBe(models.lastMessage().stopy + 10); }); - it('should draw two actors, notes to the left with text wrapped and the init directive sets the theme to dark and fontFamily to Menlo, fontSize to 18, and fontWeight to 800', function () { + it('should draw two actors, notes to the left with text wrapped and the init directive sets the theme to dark and fontFamily to Menlo, fontSize to 18, and fontWeight to 800', async () => { const str = ` %%{init: { "theme": "dark", 'config': { "fontFamily": "Menlo", "fontSize": 18, "messageFontWeight": 400, "wrap": true }}}%% sequenceDiagram @@ -1847,7 +1852,7 @@ Alice->>Bob: Hello Bob, how are you? If you are not available right now, I can l Note left of Alice: Bob thinks Bob->>Alice: Fine!`; // mermaidAPI.initialize({ logLevel: 0 }); - mermaidAPI.parse(str, diagram); + await mermaidAPI.parse(str); diagram.renderer.draw(str, 'tst', '1.2.3', diagram); const { bounds, models } = diagram.renderer.bounds.getBounds(); @@ -1864,14 +1869,14 @@ Bob->>Alice: Fine!`; expect(bounds.stopx).toBe(conf.width * 2 + conf.actorMargin); expect(bounds.stopy).toBe(models.lastMessage().stopy + 10); }); - it('should draw two loops', function () { + it('should draw two loops', async () => { const str = ` sequenceDiagram Alice->Bob: Hello Bob, how are you? loop Cheers Bob->Alice: Fine! end`; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); diagram.renderer.draw(str, 'tst', '1.2.3', diagram); const { bounds, models } = diagram.renderer.bounds.getBounds(); @@ -1881,7 +1886,7 @@ end`; expect(bounds.stopx).toBe(conf.width * 2 + conf.actorMargin); expect(bounds.stopy).toBe(models.lastLoop().stopy); }); - it('should draw background rect', function () { + it('should draw background rect', async () => { const str = ` sequenceDiagram Alice->Bob: Hello Bob, are you alright? @@ -1889,7 +1894,7 @@ end`; Bob->Alice: I feel surrounded by darkness end `; - mermaidAPI.parse(str); + await mermaidAPI.parse(str); diagram.renderer.draw(str, 'tst', '1.2.3', diagram); const { bounds, models } = diagram.renderer.bounds.getBounds(); expect(bounds.startx).toBe(0); @@ -1900,7 +1905,7 @@ end`; }); }); -describe('when rendering a sequenceDiagram with actor mirror activated', function () { +describe('when rendering a sequenceDiagram with actor mirror activated', () => { beforeAll(() => { let conf = { diagramMarginX: 50, @@ -1931,14 +1936,14 @@ describe('when rendering a sequenceDiagram with actor mirror activated', functio diagram.renderer.bounds.init(); }); ['tspan', 'fo', 'old', undefined].forEach(function (textPlacement) { - it('should handle one actor, when textPlacement is' + textPlacement, function () { + it('should handle one actor, when textPlacement is' + textPlacement, async () => { mermaidAPI.initialize(addConf(conf, 'textPlacement', textPlacement)); diagram.renderer.bounds.init(); const str = ` sequenceDiagram participant Alice`; diagram.renderer.bounds.init(); - mermaidAPI.parse(str); + await mermaidAPI.parse(str); diagram.renderer.draw(str, 'tst', '1.2.3', diagram); const { bounds, models } = diagram.renderer.bounds.getBounds(); @@ -1950,7 +1955,7 @@ participant Alice`; }); }); -describe('when rendering a sequenceDiagram with directives', function () { +describe('when rendering a sequenceDiagram with directives', () => { beforeAll(function () { let conf = { diagramMarginX: 50, @@ -1975,7 +1980,7 @@ describe('when rendering a sequenceDiagram with directives', function () { diagram.renderer.bounds.init(); }); - it('should handle one actor, when theme is dark and logLevel is 1 DX1 (dfg1)', function () { + it('should handle one actor, when theme is dark and logLevel is 1 DX1 (dfg1)', async () => { const str = ` %%{init: { "theme": "dark", "logLevel": 1 } }%% sequenceDiagram @@ -1985,7 +1990,7 @@ participant Alice diagram = new Diagram(str); diagram.renderer.bounds.init(); - mermaidAPI.parse(str); + await mermaidAPI.parse(str); diagram.renderer.draw(str, 'tst', '1.2.3', diagram); @@ -2000,7 +2005,7 @@ participant Alice models.lastActor().y + models.lastActor().height + mermaid.sequence.boxMargin ); }); - it('should handle one actor, when logLevel is 3 (dfg0)', function () { + it('should handle one actor, when logLevel is 3 (dfg0)', async () => { const str = ` %%{initialize: { "logLevel": 3 }}%% sequenceDiagram @@ -2020,7 +2025,7 @@ participant Alice models.lastActor().y + models.lastActor().height + mermaid.sequence.boxMargin ); }); - it('should hide sequence numbers when autonumber is removed when autonumber is enabled', function () { + it('should hide sequence numbers when autonumber is removed when autonumber is enabled', async () => { const str1 = ` sequenceDiagram autonumber @@ -2028,7 +2033,7 @@ Alice->Bob:Hello Bob, how are you? Note right of Bob: Bob thinks Bob-->Alice: I am good thanks!`; - mermaidAPI.parse(str1, diagram); + await mermaidAPI.parse(str1); diagram.renderer.draw(str1, 'tst', '1.2.3', diagram); // needs to be rendered for the correct value of visibility auto numbers expect(diagram.db.showSequenceNumbers()).toBe(true); @@ -2038,7 +2043,7 @@ Alice->Bob:Hello Bob, how are you? Note right of Bob: Bob thinks Bob-->Alice: I am good thanks!`; - mermaidAPI.parse(str2, diagram); + await mermaidAPI.parse(str2); diagram.renderer.draw(str2, 'tst', '1.2.3', diagram); expect(diagram.db.showSequenceNumbers()).toBe(false); }); diff --git a/packages/mermaid/src/diagrams/sequence/sequenceDiagram.ts b/packages/mermaid/src/diagrams/sequence/sequenceDiagram.ts new file mode 100644 index 000000000..fdec7f86d --- /dev/null +++ b/packages/mermaid/src/diagrams/sequence/sequenceDiagram.ts @@ -0,0 +1,13 @@ +import { DiagramDefinition } from '../../diagram-api/types'; +// @ts-ignore: TODO Fix ts errors +import parser from './parser/sequenceDiagram'; +import db from './sequenceDb'; +import styles from './styles'; +import renderer from './sequenceRenderer'; + +export const diagram: DiagramDefinition = { + parser, + db, + renderer, + styles, +}; diff --git a/packages/mermaid/src/diagrams/sequence/sequenceRenderer.ts b/packages/mermaid/src/diagrams/sequence/sequenceRenderer.ts index e4ce05350..acee7bbe5 100644 --- a/packages/mermaid/src/diagrams/sequence/sequenceRenderer.ts +++ b/packages/mermaid/src/diagrams/sequence/sequenceRenderer.ts @@ -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 = {}; diff --git a/packages/mermaid/src/diagrams/state/parser/state-parser.spec.js b/packages/mermaid/src/diagrams/state/parser/state-parser.spec.js index 5ec5642e1..f8ea694a6 100644 --- a/packages/mermaid/src/diagrams/state/parser/state-parser.spec.js +++ b/packages/mermaid/src/diagrams/state/parser/state-parser.spec.js @@ -117,7 +117,7 @@ describe('state parser can parse...', () => { state "Big State 1" as bigState1 { state "inner state 1" as inner1 inner2: inner state 2 - inner1 --> inner2 + inner1 --> inner2 }`; stateDiagram.parser.parse(diagramText); stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2()); diff --git a/packages/mermaid/src/diagrams/state/stateDetector-V2.ts b/packages/mermaid/src/diagrams/state/stateDetector-V2.ts index 9e59c4a04..5fa617a76 100644 --- a/packages/mermaid/src/diagrams/state/stateDetector-V2.ts +++ b/packages/mermaid/src/diagrams/state/stateDetector-V2.ts @@ -1,11 +1,29 @@ -import type { DiagramDetector } from '../../diagram-api/types'; +import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types'; -export const stateDetectorV2: DiagramDetector = (text, config) => { +const id = 'stateDiagram'; + +const detector: DiagramDetector = (text, config) => { if (text.match(/^\s*stateDiagram-v2/) !== null) { return true; } if (text.match(/^\s*stateDiagram/) && config?.state?.defaultRenderer === 'dagre-wrapper') { return true; } + if (text.match(/^\s*stateDiagram/) && config?.state?.defaultRenderer === 'dagre-wrapper') { + return true; + } return false; }; + +const loader = async () => { + const { diagram } = await import('./stateDiagram-v2'); + return { id, diagram }; +}; + +const plugin: ExternalDiagramDefinition = { + id, + detector, + loader, +}; + +export default plugin; diff --git a/packages/mermaid/src/diagrams/state/stateDetector.ts b/packages/mermaid/src/diagrams/state/stateDetector.ts index 85338c6df..ee6b3ac2c 100644 --- a/packages/mermaid/src/diagrams/state/stateDetector.ts +++ b/packages/mermaid/src/diagrams/state/stateDetector.ts @@ -1,6 +1,8 @@ -import type { DiagramDetector } from '../../diagram-api/types'; +import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types'; -export const stateDetector: DiagramDetector = (txt, config) => { +const id = 'state'; + +const detector: DiagramDetector = (txt, config) => { // If we have confirmed to only use new state diagrams this function should always return false // as in not signalling true for a legacy state diagram if (config?.state?.defaultRenderer === 'dagre-wrapper') { @@ -8,3 +10,16 @@ export const stateDetector: DiagramDetector = (txt, config) => { } return txt.match(/^\s*stateDiagram/) !== null; }; + +const loader = async () => { + const { diagram } = await import('./stateDiagram'); + return { id, diagram }; +}; + +const plugin: ExternalDiagramDefinition = { + id, + detector, + loader, +}; + +export default plugin; diff --git a/packages/mermaid/src/diagrams/state/stateDiagram-v2.ts b/packages/mermaid/src/diagrams/state/stateDiagram-v2.ts new file mode 100644 index 000000000..f7ee4f052 --- /dev/null +++ b/packages/mermaid/src/diagrams/state/stateDiagram-v2.ts @@ -0,0 +1,20 @@ +import { DiagramDefinition } from '../../diagram-api/types'; +// @ts-ignore: TODO Fix ts errors +import parser from './parser/stateDiagram'; +import db from './stateDb'; +import styles from './styles'; +import renderer from './stateRenderer-v2'; + +export const diagram: DiagramDefinition = { + parser, + db, + renderer, + styles, + init: (cnf) => { + if (!cnf.state) { + cnf.state = {}; + } + cnf.state.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute; + db.clear(); + }, +}; diff --git a/packages/mermaid/src/diagrams/state/stateDiagram.ts b/packages/mermaid/src/diagrams/state/stateDiagram.ts new file mode 100644 index 000000000..570d599de --- /dev/null +++ b/packages/mermaid/src/diagrams/state/stateDiagram.ts @@ -0,0 +1,20 @@ +import { DiagramDefinition } from '../../diagram-api/types'; +// @ts-ignore: TODO Fix ts errors +import parser from './parser/stateDiagram'; +import db from './stateDb'; +import styles from './styles'; +import renderer from './stateRenderer'; + +export const diagram: DiagramDefinition = { + parser, + db, + renderer, + styles, + init: (cnf) => { + if (!cnf.state) { + cnf.state = {}; + } + cnf.state.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute; + db.clear(); + }, +}; diff --git a/packages/mermaid/src/diagrams/timeline/detector.ts b/packages/mermaid/src/diagrams/timeline/detector.ts index faa86a72c..9bd2b5ece 100644 --- a/packages/mermaid/src/diagrams/timeline/detector.ts +++ b/packages/mermaid/src/diagrams/timeline/detector.ts @@ -7,7 +7,7 @@ const detector = (txt: string) => { }; const loader = async () => { - const { diagram } = await import('./diagram-definition.js'); + const { diagram } = await import('./timeline-definition.js'); return { id, diagram }; }; diff --git a/packages/mermaid/src/diagrams/timeline/diagram-definition.ts b/packages/mermaid/src/diagrams/timeline/timeline-definition.ts similarity index 100% rename from packages/mermaid/src/diagrams/timeline/diagram-definition.ts rename to packages/mermaid/src/diagrams/timeline/timeline-definition.ts diff --git a/packages/mermaid/src/diagrams/user-journey/journeyDetector.ts b/packages/mermaid/src/diagrams/user-journey/journeyDetector.ts index 535e7be9d..90b2fd6e1 100644 --- a/packages/mermaid/src/diagrams/user-journey/journeyDetector.ts +++ b/packages/mermaid/src/diagrams/user-journey/journeyDetector.ts @@ -1,5 +1,20 @@ -import type { DiagramDetector } from '../../diagram-api/types'; +import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types'; -export const journeyDetector: DiagramDetector = (txt) => { +const id = 'journey'; + +const detector: DiagramDetector = (txt) => { return txt.match(/^\s*journey/) !== null; }; + +const loader = async () => { + const { diagram } = await import('./journeyDiagram'); + return { id, diagram }; +}; + +const plugin: ExternalDiagramDefinition = { + id, + detector, + loader, +}; + +export default plugin; diff --git a/packages/mermaid/src/diagrams/user-journey/journeyDiagram.ts b/packages/mermaid/src/diagrams/user-journey/journeyDiagram.ts new file mode 100644 index 000000000..c3a2a3c6b --- /dev/null +++ b/packages/mermaid/src/diagrams/user-journey/journeyDiagram.ts @@ -0,0 +1,17 @@ +import { DiagramDefinition } from '../../diagram-api/types'; +// @ts-ignore: TODO Fix ts errors +import parser from './parser/journey'; +import db from './journeyDb'; +import styles from './styles'; +import renderer from './journeyRenderer'; + +export const diagram: DiagramDefinition = { + parser, + db, + renderer, + styles, + init: (cnf) => { + renderer.setConf(cnf.journey); + db.clear(); + }, +}; diff --git a/packages/mermaid/src/docs/.vitepress/theme/Mermaid.vue b/packages/mermaid/src/docs/.vitepress/theme/Mermaid.vue index 85c13393c..5012d3067 100644 --- a/packages/mermaid/src/docs/.vitepress/theme/Mermaid.vue +++ b/packages/mermaid/src/docs/.vitepress/theme/Mermaid.vue @@ -17,7 +17,7 @@ const props = defineProps({ }, }); -const svg = ref(null); +const svg = ref(''); let mut = null; onMounted(async () => { diff --git a/packages/mermaid/src/docs/.vitepress/theme/mermaid.ts b/packages/mermaid/src/docs/.vitepress/theme/mermaid.ts index 2234ef498..4752a1c01 100644 --- a/packages/mermaid/src/docs/.vitepress/theme/mermaid.ts +++ b/packages/mermaid/src/docs/.vitepress/theme/mermaid.ts @@ -2,6 +2,6 @@ import mermaid, { type MermaidConfig } from 'mermaid'; export const render = async (id: string, code: string, config: MermaidConfig): Promise => { mermaid.initialize(config); - const svg = await mermaid.renderAsync(id, code); + const { svg } = await mermaid.render(id, code); return svg; }; diff --git a/packages/mermaid/src/docs/config/usage.md b/packages/mermaid/src/docs/config/usage.md index c805c623a..c74023952 100644 --- a/packages/mermaid/src/docs/config/usage.md +++ b/packages/mermaid/src/docs/config/usage.md @@ -14,21 +14,24 @@ Please note that you can switch versions through the dropdown box at the top rig For the majority of users, Using the [Live Editor](https://mermaid.live/) would be sufficient, however you may also opt to deploy mermaid as a dependency or using the [Mermaid API](./setup/README.md). -We have compiled some Video [Tutorials](./Tutorials.md) on how to use the mermaid Live Editor. +We have compiled some Video [Tutorials](./Tutorials.md) on how to use the Mermaid Live Editor. ### Installing and Hosting Mermaid on a Webpage **Using the npm package:** -1. You will need to install `node v16`, which would have npm. +Requirements: -2. Download `yarn` using npm. +- Node >= 16 -3. Enter the following command: `yarn add mermaid`. - -4. At this point, you can add mermaid as a dev dependency using this command: `yarn add --dev mermaid`. - -5. Alternatively, you can also deploy mermaid using the script tag in an HTML file with mermaid diagram descriptions as is shown in the example below. +```bash +# NPM +npm install mermaid +# Yarn +yarn add mermaid +# PNPM +pnpm add mermaid +``` **Hosting mermaid on a web page:** @@ -36,7 +39,9 @@ We have compiled some Video [Tutorials](./Tutorials.md) on how to use the mermai The easiest way to integrate mermaid on a web page requires two elements: -- A graph definition, inside `
` tags labeled `class=mermaid`. Example:
+- A graph definition, inside `
` tags labeled `class=mermaid`.
+
+Example:
 
 ```html
 
@@ -47,14 +52,13 @@ The easiest way to integrate mermaid on a web page requires two elements:
 
``` -- Inclusion of the mermaid address in the html page body using a `script` tag as an ESM import, and the `mermaidAPI` call. +- The mermaid js script. Added using a `script` tag as an ESM import. Example: ```html ``` @@ -65,9 +69,6 @@ Example: ```html - - -
   graph LR
@@ -77,7 +78,6 @@ Example:
     
@@ -89,11 +89,12 @@ An id attribute is also added to mermaid tags without one. Mermaid can load multiple diagrams, in the same page. -> Try it out, save this code as HTML and load it using any browser.(Except Internet Explorer, please don't use Internet Explorer.) +> Try it out, save this code as HTML and load it using any browser. +> (Except Internet Explorer, please don't use Internet Explorer.) ## Enabling Click Event and Tags in Nodes -A `securityLevel` configuration has to first be cleared, `securityLevel` sets the level of trust for the parsed diagrams and limits click functionality. This was introduce in version 8.2 as a security improvement, aimed at preventing malicious use. +A `securityLevel` configuration has to first be cleared. `securityLevel` sets the level of trust for the parsed diagrams and limits click functionality. This was introduce in version 8.2 as a security improvement, aimed at preventing malicious use. **It is the site owner's responsibility to discriminate between trustworthy and untrustworthy user-bases and we encourage the use of discretion.** @@ -101,7 +102,7 @@ A `securityLevel` configuration has to first be cleared, `securityLevel` sets th | Parameter | Description | Type | Required | Values | | ------------- | --------------------------------- | ------ | -------- | ------------------------------------------ | -| securityLevel | Level of trust for parsed diagram | String | Required | 'sandbox', 'strict', 'loose', 'antiscript' | +| securityLevel | Level of trust for parsed diagram | String | Optional | 'sandbox', 'strict', 'loose', 'antiscript' | Values: @@ -117,26 +118,17 @@ This changes the default behaviour of mermaid so that after upgrade to 8.2, unle **If you are taking responsibility for the diagram source security you can set the `securityLevel` to a value of your choosing . This allows clicks and tags are allowed.** -**To change `securityLevel`, you have to call `mermaidAPI.initialize`:** +**To change `securityLevel`, you have to call `mermaid.initialize`:** ```javascript -mermaidAPI.initialize({ +mermaid.initialize({ securityLevel: 'loose', }); ``` ### Labels out of bounds -If you use dynamically loaded fonts that are loaded through CSS, such as Google fonts, mermaid should wait for the -whole page to load (dom + assets, particularly the fonts file). - -```javascript -$(document).load(function () { - mermaid.initialize(); -}); -``` - -or +If you use dynamically loaded fonts that are loaded through CSS, such as fonts, mermaid should wait for the whole page to load (dom + assets, particularly the fonts file). ```javascript $(document).ready(function () { @@ -149,12 +141,55 @@ Not doing so will most likely result in mermaid rendering graphs that have label If your page has other fonts in its body those might be used instead of the mermaid font. Specifying the font in your styling is a workaround for this. ```css -div.mermaid { +pre.mermaid { font-family: 'trebuchet ms', verdana, arial; } ``` -### Calling `mermaid.init` +### Using `mermaid.run` + +mermaid.run was added in v10 and is the preferred way of handling more complex integration. +By default, `mermaid.run` will be called when the document is ready, rendering all elements with `class="mermaid"`. + +You can customize that behavior by calling `await mermaid.run()`. + +`mermaid.initialize({startOnLoad: false})` will prevent `mermaid.run` from being called automatically after load. + +Render all elements with querySelector ".someOtherClass" + +```js +mermaid.initialize({ startOnLoad: false }); +await mermaid.run({ + querySelector: '.someOtherClass', +}); +``` + +Render all elements passed as an array + +```js +mermaid.initialize({ startOnLoad: false }); +await mermaid.run({ + nodes: [document.getElementById('someId'), document.getElementById('anotherId')], +}); +await mermaid.run({ + nodes: document.querySelectorAll('.yetAnotherClass'), +}); +``` + +Render all `.mermaid` elements while suppressing any error + +```js +mermaid.initialize({ startOnLoad: false }); +await mermaid.run({ + suppressErrors: true, +}); +``` + +### Calling `mermaid.init` - Deprecated + +```warning +mermaid.init is deprecated in v10 and will be removed in v11. Please use mermaid.run instead. +``` By default, `mermaid.init` will be called when the document is ready, finding all elements with `class="mermaid"`. If you are adding content after mermaid is loaded, or otherwise need @@ -188,25 +223,24 @@ mermaid fully supports webpack. Here is a [working demo](https://github.com/merm ## API usage -The main idea of the API is to be able to call a render function with the graph definition as a string. The render function -will render the graph and call a callback with the resulting SVG code. With this approach it is up to the site creator to -fetch the graph definition from the site (perhaps from a textarea), render it and place the graph somewhere in the site. +The main idea of the API is to be able to call a render function with the graph definition as a string. The render function will render the graph and call a callback with the resulting SVG code. With this approach it is up to the site creator to fetch the graph definition from the site (perhaps from a textarea), render it and place the graph somewhere in the site. The example below show an outline of how this could be used. The example just logs the resulting SVG to the JavaScript console. ```html ``` @@ -219,17 +253,17 @@ The example code below is an extract of what mermaid does when using the API. Th bind events to an SVG when using the API for rendering. ```javascript -const insertSvg = function (svgCode, bindFunctions) { - element.innerHTML = svgCode; - if (typeof callback !== 'undefined') { - callback(id); +// Example of using the bindFunctions +const drawDiagram = async function () { + element = document.querySelector('#graphDiv'); + const graphDefinition = 'graph TB\na-->b'; + const { svg, bindFunctions } = await mermaid.render('graphDiv', graphDefinition); + element.innerHTML = svg; + // This can also be written as `bindFunctions?.(element);` using the `?` shorthand. + if (bindFunctions) { + bindFunctions(element); } - bindFunctions(element); }; - -const id = 'theGraph'; - -mermaidAPI.render(id, txt, insertSvg, element); ``` 1. The graph is generated using the render call. @@ -327,8 +361,8 @@ The future proof way of setting the configuration is by using the initialization on what kind of integration you use. ```html - - diff --git a/packages/mermaid/src/docs/ecosystem/integrations.md b/packages/mermaid/src/docs/ecosystem/integrations.md index cf4ccc9f8..727580664 100644 --- a/packages/mermaid/src/docs/ecosystem/integrations.md +++ b/packages/mermaid/src/docs/ecosystem/integrations.md @@ -14,6 +14,7 @@ They also serve as proof of concept, for the variety of things that can be built - [Gitea](https://gitea.io) (**Native support**) - [Azure Devops](https://docs.microsoft.com/en-us/azure/devops/project/wiki/wiki-markdown-guidance?view=azure-devops#add-mermaid-diagrams-to-a-wiki-page) (**Native support**) - [Tuleap](https://docs.tuleap.org/user-guide/writing-in-tuleap.html#graphs) (**Native support**) +- [Deepdwn](https://billiam.itch.io/deepdwn) (**Native support**) - [Joplin](https://joplinapp.org) (**Native support**) - [Swimm](https://swimm.io) (**Native support**) - [Notion](https://notion.so) (**Native support**) @@ -182,3 +183,6 @@ They also serve as proof of concept, for the variety of things that can be built - [mermaid-server: Generate diagrams using a HTTP request](https://github.com/TomWright/mermaid-server) - [ExDoc](https://github.com/elixir-lang/ex_doc) - [Rendering Mermaid graphs](https://github.com/elixir-lang/ex_doc#rendering-mermaid-graphs) +- [NiceGUI: Let any browser be the frontend of your Python code](https://nicegui.io) + - [ui.mermaid(...)](https://nicegui.io/reference#mermaid_diagrams) + - [ui.markdown(..., extras=['mermaid'])](https://nicegui.io/reference#markdown_element) diff --git a/packages/mermaid/src/docs/intro/n00b-gettingStarted.md b/packages/mermaid/src/docs/intro/n00b-gettingStarted.md index c347f2ef3..fcb3f31ee 100644 --- a/packages/mermaid/src/docs/intro/n00b-gettingStarted.md +++ b/packages/mermaid/src/docs/intro/n00b-gettingStarted.md @@ -86,7 +86,7 @@ When writing the .html file, we give two instructions inside the html code to th a. The mermaid code for the diagram we want to create. -b. The importing of mermaid library through the `mermaid.esm.js` or `mermaid.esm.min.mjs` and the `mermaid.initialize()` call, which dictates the appearance of diagrams and also starts the rendering process . +b. The importing of mermaid library through the `mermaid.esm.mjs` or `mermaid.esm.min.mjs` and the `mermaid.initialize()` call, which dictates the appearance of diagrams and also starts the rendering process . **a. The embedded mermaid diagram definition inside a `
`:**
 
@@ -118,7 +118,7 @@ b. The importing of mermaid library through the `mermaid.esm.js` or `mermaid.esm
 ```
 
 **Notes**:
-Rendering in Mermaid is initialized by `mermaid.initialize()` call. You can place `mermaid.initialize()` inside `mermaid.min.js` for brevity. However, doing the opposite lets you control when it starts looking for `
`tags inside the web page with `mermaid.initialize()`. This is useful when you think that not all `
` tags may have loaded on the execution of `mermaid.min.js` file. +Rendering in Mermaid is initialized by `mermaid.initialize()` call. However, doing the opposite lets you control when it starts looking for `
` tags inside the web page with `mermaid.initialize()`. This is useful when you think that not all `
` tags may have loaded on the execution of `mermaid.esm.min.mjs` file.
 
 `startOnLoad` is one of the parameters that can be defined by `mermaid.initialize()`
 
@@ -126,10 +126,6 @@ Rendering in Mermaid is initialized by `mermaid.initialize()` call. You can plac
 | ----------- | --------------------------------- | ------- | ----------- |
 | startOnLoad | Toggle for Rendering upon loading | Boolean | true, false |
 
-### Adding external diagrams to mermaid
-
-Please refer to the [Mindmap](../syntax/mindmap.md?id=integrating-with-your-librarywebsite) section for more information.
-
 ### Working Examples
 
 **Here is a full working example of the mermaidAPI being called through the CDN:**
diff --git a/packages/mermaid/src/docs/syntax/flowchart.md b/packages/mermaid/src/docs/syntax/flowchart.md
index 5896e0518..6997ca088 100644
--- a/packages/mermaid/src/docs/syntax/flowchart.md
+++ b/packages/mermaid/src/docs/syntax/flowchart.md
@@ -245,6 +245,15 @@ flowchart LR
    A == text ==> B
 ```
 
+### An invisible link
+
+This can be a useful tool in some instances where you want to alter the default positioning of a node.
+
+```mermaid-example
+flowchart LR
+    A ~~~ B
+```
+
 ### Chaining of links
 
 It is possible declare many links in the same line as per below:
diff --git a/packages/mermaid/src/docs/syntax/mindmap.md b/packages/mermaid/src/docs/syntax/mindmap.md
index cce7d2e3d..c8a252691 100644
--- a/packages/mermaid/src/docs/syntax/mindmap.md
+++ b/packages/mermaid/src/docs/syntax/mindmap.md
@@ -170,7 +170,7 @@ You can still use the pre 9.4.0 method to add mermaid with mindmaps to a web pag
 
 ```html
 
@@ -184,12 +184,4 @@ From version 9.4.0 you can simplify this code to:
 
 ```
 
-or if you prefer not using the ESM package:
-
-```html
-
-```
-
-Note that more complex integrations that use the **render** function directly need to use the **renderAsync** method instead in order to render mind maps.
-
 You can also refer the implementation in the live editor [here](https://github.com/mermaid-js/mermaid-live-editor/blob/develop/src/lib/util/mermaid.ts) to see how the async loading is done.
diff --git a/packages/mermaid/src/docs/syntax/timeline.md b/packages/mermaid/src/docs/syntax/timeline.md
index 94a485d22..ef48d2b61 100644
--- a/packages/mermaid/src/docs/syntax/timeline.md
+++ b/packages/mermaid/src/docs/syntax/timeline.md
@@ -298,9 +298,9 @@ Timeline uses experimental lazy loading & async rendering features which could c
 You can use this method to add mermaid including the timeline diagram to a web page:
 
 ```html
-
+
 ```
 
-Note that more complex integrations that the **render** function directly need to use the **renderAsync** method instead in order to render timeline.
-
 You can also refer the implementation in the live editor [here](https://github.com/mermaid-js/mermaid-live-editor/blob/develop/src/lib/util/mermaid.ts) to see how the async loading is done.
diff --git a/packages/mermaid/src/docs/vite.config.ts b/packages/mermaid/src/docs/vite.config.ts
index 2279e667d..179e271fd 100644
--- a/packages/mermaid/src/docs/vite.config.ts
+++ b/packages/mermaid/src/docs/vite.config.ts
@@ -12,12 +12,12 @@ export default defineConfig({
       // TODO: will be fixed in the next vitepress release.
       name: 'fix-virtual',
 
-      async resolveId(id) {
+      async resolveId(id: string) {
         if (id === virtualModuleId) {
           return resolvedVirtualModuleId;
         }
       },
-      async load(this, id) {
+      async load(this, id: string) {
         if (id === resolvedVirtualModuleId) {
           return `export default ${JSON.stringify({
             securityLevel: 'loose',
@@ -25,20 +25,15 @@ export default defineConfig({
           })};`;
         }
       },
-    },
+    } as PluginOption,
   ],
   resolve: {
     alias: {
       mermaid: path.join(__dirname, '../../dist/mermaid.esm.min.mjs'), // Use this one to build
-
       '@mermaid-js/mermaid-example-diagram': path.join(
         __dirname,
         '../../../mermaid-example-diagram/dist/mermaid-example-diagram.esm.min.mjs'
       ), // Use this one to build
-      // '@mermaid-js/mermaid-timeline': path.join(
-      //   __dirname,
-      //   '../../../mermaid-timeline/dist/mermaid-timeline.esm.min.mjs'
-      // ),
     },
   },
   server: {
diff --git a/packages/mermaid/src/errors.ts b/packages/mermaid/src/errors.ts
new file mode 100644
index 000000000..e3650c5a9
--- /dev/null
+++ b/packages/mermaid/src/errors.ts
@@ -0,0 +1,6 @@
+export class UnknownDiagramError extends Error {
+  constructor(message: string) {
+    super(message);
+    this.name = 'UnknownDiagramError';
+  }
+}
diff --git a/packages/mermaid/src/logger.ts b/packages/mermaid/src/logger.ts
index 8bd46d6db..b1c035e22 100644
--- a/packages/mermaid/src/logger.ts
+++ b/packages/mermaid/src/logger.ts
@@ -2,7 +2,7 @@
 /* eslint-disable @typescript-eslint/no-unused-vars */
 /* eslint-disable @typescript-eslint/no-empty-function */
 /* eslint-disable no-console */
-import moment from 'moment';
+import moment from 'moment-mini';
 
 export type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';
 
diff --git a/packages/mermaid/src/mermaid.spec.ts b/packages/mermaid/src/mermaid.spec.ts
index aa797af0e..58d39c348 100644
--- a/packages/mermaid/src/mermaid.spec.ts
+++ b/packages/mermaid/src/mermaid.spec.ts
@@ -1,60 +1,68 @@
 import mermaid from './mermaid';
 import { mermaidAPI } from './mermaidAPI';
 import './diagram-api/diagram-orchestration';
+import { addDiagrams } from './diagram-api/diagram-orchestration';
+
+beforeAll(async () => {
+  addDiagrams();
+});
 const spyOn = vi.spyOn;
 
 vi.mock('./mermaidAPI');
 
 afterEach(() => {
-  vi.restoreAllMocks();
+  vi.clearAllMocks();
 });
 
-describe('when using mermaid and ', function () {
-  describe('when detecting chart type ', function () {
-    it('should not start rendering with mermaid.startOnLoad set to false', function () {
+describe('when using mermaid and ', () => {
+  describe('when detecting chart type ', () => {
+    it('should not start rendering with mermaid.startOnLoad set to false', async () => {
       mermaid.startOnLoad = false;
       document.body.innerHTML = '
graph TD;\na;
'; - spyOn(mermaid, 'init'); + spyOn(mermaid, 'run'); mermaid.contentLoaded(); - expect(mermaid.init).not.toHaveBeenCalled(); + expect(mermaid.run).not.toHaveBeenCalled(); }); - it('should start rendering with both startOnLoad set', function () { + it('should start rendering with both startOnLoad set', async () => { mermaid.startOnLoad = true; document.body.innerHTML = '
graph TD;\na;
'; - spyOn(mermaid, 'init'); + spyOn(mermaid, 'run'); mermaid.contentLoaded(); - expect(mermaid.init).toHaveBeenCalled(); + expect(mermaid.run).toHaveBeenCalled(); }); - it('should start rendering with mermaid.startOnLoad', function () { + it('should start rendering with mermaid.startOnLoad', async () => { mermaid.startOnLoad = true; document.body.innerHTML = '
graph TD;\na;
'; - spyOn(mermaid, 'init'); + spyOn(mermaid, 'run'); mermaid.contentLoaded(); - expect(mermaid.init).toHaveBeenCalled(); + expect(mermaid.run).toHaveBeenCalled(); }); - it('should start rendering as a default with no changes performed', function () { + it('should start rendering as a default with no changes performed', async () => { document.body.innerHTML = '
graph TD;\na;
'; - spyOn(mermaid, 'init'); + spyOn(mermaid, 'run'); mermaid.contentLoaded(); - expect(mermaid.init).toHaveBeenCalled(); + expect(mermaid.run).toHaveBeenCalled(); }); }); - describe('when using #initThrowsErrors', function () { + describe('when using #run', () => { it('should accept single node', async () => { const node = document.createElement('div'); node.appendChild(document.createTextNode('graph TD;\na;')); - mermaid.initThrowsErrors(undefined, node); + await mermaid.run({ + nodes: [node], + }); // mermaidAPI.render function has been mocked, since it doesn't yet work // in Node.JS (only works in browser) expect(mermaidAPI.render).toHaveBeenCalled(); }); }); - describe('when using #registerExternalDiagrams', function () { + + describe('when using #registerExternalDiagrams', () => { it('should throw error (but still render) if registerExternalDiagrams fails', async () => { const node = document.createElement('div'); node.appendChild(document.createTextNode('graph TD;\na;')); @@ -63,18 +71,22 @@ describe('when using mermaid and ', function () { mermaid.registerExternalDiagrams( [ { - id: 'dummy', - detector: (text) => /dummy/.test(text), - loader: () => Promise.reject('error'), + id: 'dummyError', + detector: (text) => /dummyError/.test(text), + loader: () => Promise.reject('dummyError'), }, ], { lazyLoad: false } ) ).rejects.toThrow('Failed to load 1 external diagrams'); - expect(() => mermaid.initThrowsErrorsAsync(undefined, node)).not.toThrow(); + await expect( + mermaid.run({ + nodes: [node], + }) + ).resolves.not.toThrow(); // should still render, even if lazyLoadedDiagrams fails - expect(mermaidAPI.renderAsync).toHaveBeenCalled(); + expect(mermaidAPI.render).toHaveBeenCalled(); }); it('should defer diagram load based on parameter', async () => { @@ -137,19 +149,21 @@ describe('when using mermaid and ', function () { }); }); - describe('checking validity of input ', function () { - it('should throw for an invalid definition', function () { - expect(() => mermaid.parse('this is not a mermaid diagram definition')).toThrow(); + describe('checking validity of input ', () => { + it('should throw for an invalid definition', async () => { + await expect(mermaid.parse('this is not a mermaid diagram definition')).rejects.toThrow(); }); - it('should not throw for a valid flow definition', function () { - expect(() => mermaid.parse('graph TD;A--x|text including URL space|B;')).not.toThrow(); + it('should not throw for a valid flow definition', async () => { + await expect( + mermaid.parse('graph TD;A--x|text including URL space|B;') + ).resolves.not.toThrow(); }); - it('should throw for an invalid flow definition', function () { - expect(() => mermaid.parse('graph TQ;A--x|text including URL space|B;')).toThrow(); + it('should throw for an invalid flow definition', async () => { + await expect(mermaid.parse('graph TQ;A--x|text including URL space|B;')).rejects.toThrow(); }); - it('should not throw for a valid sequenceDiagram definition (mmds1)', function () { + it('should not throw for a valid sequenceDiagram definition (mmds1)', async () => { const text = 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n\n' + @@ -160,10 +174,10 @@ describe('when using mermaid and ', function () { 'else isSick\n' + 'Bob-->Alice: Feel sick...\n' + 'end'; - expect(() => mermaid.parse(text)).not.toThrow(); + await expect(mermaid.parse(text)).resolves.not.toThrow(); }); - it('should throw for an invalid sequenceDiagram definition', function () { + it('should throw for an invalid sequenceDiagram definition', async () => { const text = 'sequenceDiagram\n' + 'Alice:->Bob: Hello Bob, how are you?\n\n' + @@ -174,15 +188,15 @@ describe('when using mermaid and ', function () { 'else isSick\n' + 'Bob-->Alice: Feel sick...\n' + 'end'; - expect(() => mermaid.parse(text)).toThrow(); + await expect(mermaid.parse(text)).rejects.toThrow(); }); - it('should return false for invalid definition WITH a parseError() callback defined', function () { + it('should return false for invalid definition WITH a parseError() callback defined', async () => { let parseErrorWasCalled = false; mermaid.setParseErrorHandler(() => { parseErrorWasCalled = true; }); - expect(mermaid.parse('this is not a mermaid diagram definition')).toEqual(false); + await expect(mermaid.parse('this is not a mermaid diagram definition')).rejects.toThrow(); expect(parseErrorWasCalled).toEqual(true); }); }); diff --git a/packages/mermaid/src/mermaid.ts b/packages/mermaid/src/mermaid.ts index be06c2167..0b6807b3c 100644 --- a/packages/mermaid/src/mermaid.ts +++ b/packages/mermaid/src/mermaid.ts @@ -3,65 +3,44 @@ * functionality and to render the diagrams to svg code! */ import dedent from 'ts-dedent'; - import { MermaidConfig } from './config.type'; import { log } from './logger'; import utils from './utils'; -import { mermaidAPI } from './mermaidAPI'; -import { registerLazyLoadedDiagrams } from './diagram-api/detectType'; +import { mermaidAPI, ParseOptions, RenderResult } from './mermaidAPI'; +import { registerLazyLoadedDiagrams, loadRegisteredDiagrams } from './diagram-api/detectType'; import type { ParseErrorFunction } from './Diagram'; import { isDetailedError } from './utils'; import type { DetailedError } from './utils'; -import { registerDiagram } from './diagram-api/diagramAPI'; import { ExternalDiagramDefinition } from './diagram-api/types'; -export type { MermaidConfig, DetailedError, ExternalDiagramDefinition, ParseErrorFunction }; - -/** - * ## init - * - * Function that goes through the document to find the chart definitions in there and render them. - * - * The function tags the processed attributes with the attribute data-processed and ignores found - * elements with the attribute already set. This way the init function can be triggered several - * times. - * - * ```mermaid - * graph LR; - * a(Find elements)-->b{Processed} - * b-->|Yes|c(Leave element) - * b-->|No |d(Transform) - * ``` - * - * Renders the mermaid diagrams - * - * @param config - **Deprecated**, please set configuration in {@link initialize}. - * @param nodes - **Default**: `.mermaid`. One of the following: - * - A DOM Node - * - An array of DOM nodes (as would come from a jQuery selector) - * - A W3C selector, a la `.mermaid` - * @param callback - Called once for each rendered diagram's id. - */ -const init = async function ( - config?: MermaidConfig, - // eslint-disable-next-line no-undef - nodes?: string | HTMLElement | NodeListOf, - // eslint-disable-next-line @typescript-eslint/ban-types - callback?: Function -) { - try { - await initThrowsErrorsAsync(config, nodes, callback); - } catch (e) { - log.warn('Syntax Error rendering'); - if (isDetailedError(e)) { - log.warn(e.str); - } - if (mermaid.parseError) { - mermaid.parseError(e as string); - } - } +export type { + MermaidConfig, + DetailedError, + ExternalDiagramDefinition, + ParseErrorFunction, + RenderResult, + ParseOptions, }; +export interface RunOptions { + /** + * The query selector to use when finding elements to render. Default: `".mermaid"`. + */ + querySelector?: string; + /** + * The nodes to render. If this is set, `querySelector` will be ignored. + */ + nodes?: ArrayLike; + /** + * A callback to call after each diagram is rendered. + */ + postRenderCallback?: (id: string) => unknown; + /** + * If `true`, errors will be logged to the console, but not thrown. Default: `false` + */ + suppressErrors?: boolean; +} + const handleError = (error: unknown, errors: DetailedError[], parseError?: ParseErrorFunction) => { log.warn(error); if (isDetailedError(error)) { @@ -87,39 +66,69 @@ const handleError = (error: unknown, errors: DetailedError[], parseError?: Parse } }; -const initThrowsErrors = function ( - config?: MermaidConfig, - // eslint-disable-next-line no-undef - nodes?: string | HTMLElement | NodeListOf, - // eslint-disable-next-line @typescript-eslint/ban-types - callback?: Function +/** + * ## run + * + * Function that goes through the document to find the chart definitions in there and render them. + * + * The function tags the processed attributes with the attribute data-processed and ignores found + * elements with the attribute already set. This way the init function can be triggered several + * times. + * + * ```mermaid + * graph LR; + * a(Find elements)-->b{Processed} + * b-->|Yes|c(Leave element) + * b-->|No |d(Transform) + * ``` + * + * Renders the mermaid diagrams + * + * @param options - Optional runtime configs + */ +const run = async function ( + options: RunOptions = { + querySelector: '.mermaid', + } +) { + try { + await runThrowsErrors(options); + } catch (e) { + if (isDetailedError(e)) { + log.error(e.str); + } + if (mermaid.parseError) { + mermaid.parseError(e as string); + } + if (!options.suppressErrors) { + log.error('Use the suppressErrors option to suppress these errors'); + throw e; + } + } +}; + +const runThrowsErrors = async function ( + { postRenderCallback, querySelector, nodes }: Omit = { + querySelector: '.mermaid', + } ) { const conf = mermaidAPI.getConfig(); - if (config) { - // This is a legacy way of setting config. It is not documented and should be removed in the future. - // @ts-ignore: TODO Fix ts errors - mermaid.sequenceConfig = config; - } - // if last argument is a function this is the callback function - log.debug(`${!callback ? 'No ' : ''}Callback function found`); + log.debug(`${!postRenderCallback ? 'No ' : ''}Callback function found`); + let nodesToProcess: ArrayLike; - if (nodes === undefined) { - nodesToProcess = document.querySelectorAll('.mermaid'); - } else if (typeof nodes === 'string') { - nodesToProcess = document.querySelectorAll(nodes); - } else if (nodes instanceof HTMLElement) { - nodesToProcess = [nodes]; - } else if (nodes instanceof NodeList) { + if (nodes) { nodesToProcess = nodes; + } else if (querySelector) { + nodesToProcess = document.querySelectorAll(querySelector); } else { - throw new Error('Invalid argument nodes for mermaid.init'); + throw new Error('Nodes and querySelector are both undefined'); } log.debug(`Found ${nodesToProcess.length} diagrams`); - if (config?.startOnLoad !== undefined) { - log.debug('Start On Load: ' + config?.startOnLoad); - mermaidAPI.updateSiteConfig({ startOnLoad: config?.startOnLoad }); + if (conf?.startOnLoad !== undefined) { + log.debug('Start On Load: ' + conf?.startOnLoad); + mermaidAPI.updateSiteConfig({ startOnLoad: conf?.startOnLoad }); } // generate the id of the diagram @@ -153,20 +162,14 @@ const initThrowsErrors = function ( log.debug('Detected early reinit: ', init); } try { - mermaidAPI.render( - id, - txt, - (svgCode: string, bindFunctions?: (el: Element) => void) => { - element.innerHTML = svgCode; - if (callback !== undefined) { - callback(id); - } - if (bindFunctions) { - bindFunctions(element); - } - }, - element - ); + const { svg, bindFunctions } = await mermaidAPI.render(id, txt, element); + element.innerHTML = svg; + if (postRenderCallback) { + await postRenderCallback(id); + } + if (bindFunctions) { + bindFunctions(element); + } } catch (error) { handleError(error, errors, mermaid.parseError); } @@ -178,142 +181,55 @@ const initThrowsErrors = function ( }; /** - * This is an internal function and should not be made public, as it will likely change. - * @internal - * @param diagrams - Array of {@link ExternalDiagramDefinition}. + * Used to set configurations for mermaid. + * This function should be called before the run function. + * @param config - Configuration object for mermaid. */ -const loadExternalDiagrams = async (...diagrams: ExternalDiagramDefinition[]) => { - log.debug(`Loading ${diagrams.length} external diagrams`); - // Load all lazy loaded diagrams in parallel - const results = await Promise.allSettled( - diagrams.map(async ({ id, detector, loader }) => { - const { diagram } = await loader(); - registerDiagram(id, diagram, detector); - }) - ); - const failed = results.filter((result) => result.status === 'rejected'); - if (failed.length > 0) { - log.error(`Failed to load ${failed.length} external diagrams`); - for (const res of failed) { - log.error(res); - } - throw new Error(`Failed to load ${failed.length} external diagrams`); - } -}; - -/** - * Equivalent to {@link init}, except an error will be thrown on error. - * - * @alpha - * @deprecated This is an internal function and will very likely be modified in v10, or earlier. - * We recommend staying with {@link initThrowsErrors} if you don't need `lazyLoadedDiagrams`. - * - * @param config - **Deprecated** Mermaid sequenceConfig. - * @param nodes - One of: - * - A DOM Node - * - An array of DOM nodes (as would come from a jQuery selector) - * - A W3C selector, a la `.mermaid` (default) - * @param callback - Function that is called with the id of each generated mermaid diagram. - * @returns Resolves on success, otherwise the {@link Promise} will be rejected. - */ -const initThrowsErrorsAsync = async function ( - config?: MermaidConfig, - nodes?: string | HTMLElement | NodeListOf, - // eslint-disable-next-line @typescript-eslint/ban-types - callback?: Function -) { - const conf = mermaidAPI.getConfig(); - - if (config) { - // This is a legacy way of setting config. It is not documented and should be removed in the future. - // @ts-ignore: TODO Fix ts errors - mermaid.sequenceConfig = config; - } - - // if last argument is a function this is the callback function - log.debug(`${!callback ? 'No ' : ''}Callback function found`); - let nodesToProcess: ArrayLike; - if (nodes === undefined) { - nodesToProcess = document.querySelectorAll('.mermaid'); - } else if (typeof nodes === 'string') { - nodesToProcess = document.querySelectorAll(nodes); - } else if (nodes instanceof HTMLElement) { - nodesToProcess = [nodes]; - } else if (nodes instanceof NodeList) { - nodesToProcess = nodes; - } else { - throw new Error('Invalid argument nodes for mermaid.init'); - } - - log.debug(`Found ${nodesToProcess.length} diagrams`); - if (config?.startOnLoad !== undefined) { - log.debug('Start On Load: ' + config?.startOnLoad); - mermaidAPI.updateSiteConfig({ startOnLoad: config?.startOnLoad }); - } - - // generate the id of the diagram - const idGenerator = new utils.initIdGenerator(conf.deterministicIds, conf.deterministicIDSeed); - - let txt: string; - const errors: DetailedError[] = []; - - // element is the current div with mermaid class - // eslint-disable-next-line unicorn/prefer-spread - for (const element of Array.from(nodesToProcess)) { - log.info('Rendering diagram: ' + element.id); - /*! Check if previously processed */ - if (element.getAttribute('data-processed')) { - continue; - } - element.setAttribute('data-processed', 'true'); - - const id = `mermaid-${idGenerator.next()}`; - - // Fetch the graph definition including tags - txt = element.innerHTML; - - // transforms the html to pure text - txt = dedent(utils.entityDecode(txt)) // removes indentation, required for YAML parsing - .trim() - .replace(//gi, '
'); - - const init = utils.detectInit(txt); - if (init) { - log.debug('Detected early reinit: ', init); - } - try { - await mermaidAPI.renderAsync( - id, - txt, - (svgCode: string, bindFunctions?: (el: Element) => void) => { - element.innerHTML = svgCode; - if (callback !== undefined) { - callback(id); - } - if (bindFunctions) { - bindFunctions(element); - } - }, - element - ); - } catch (error) { - handleError(error, errors, mermaid.parseError); - } - } - if (errors.length > 0) { - // TODO: We should be throwing an error object. - throw errors[0]; - } -}; const initialize = function (config: MermaidConfig) { mermaidAPI.initialize(config); }; +/** + * ## init + * + * @deprecated Use {@link initialize} and {@link run} instead. + * + * Renders the mermaid diagrams + * + * @param config - **Deprecated**, please set configuration in {@link initialize}. + * @param nodes - **Default**: `.mermaid`. One of the following: + * - A DOM Node + * - An array of DOM nodes (as would come from a jQuery selector) + * - A W3C selector, a la `.mermaid` + * @param callback - Called once for each rendered diagram's id. + */ +const init = async function ( + config?: MermaidConfig, + nodes?: string | HTMLElement | NodeListOf, + callback?: (id: string) => unknown +) { + log.warn('mermaid.init is deprecated. Please use run instead.'); + if (config) { + initialize(config); + } + const runOptions: RunOptions = { postRenderCallback: callback, querySelector: '.mermaid' }; + if (typeof nodes === 'string') { + runOptions.querySelector = nodes; + } else if (nodes) { + if (nodes instanceof HTMLElement) { + runOptions.nodes = [nodes]; + } else { + runOptions.nodes = nodes; + } + } + await run(runOptions); +}; + /** * Used to register external diagram types. * @param diagrams - Array of {@link ExternalDiagramDefinition}. - * @param opts - If opts.lazyLoad is true, the diagram will be loaded on demand. + * @param opts - If opts.lazyLoad is false, the diagrams will be loaded immediately. */ const registerExternalDiagrams = async ( diagrams: ExternalDiagramDefinition[], @@ -323,10 +239,9 @@ const registerExternalDiagrams = async ( lazyLoad?: boolean; } = {} ) => { - if (lazyLoad) { - registerLazyLoadedDiagrams(...diagrams); - } else { - await loadExternalDiagrams(...diagrams); + registerLazyLoadedDiagrams(...diagrams); + if (lazyLoad === false) { + await loadRegisteredDiagrams(); } }; @@ -339,7 +254,7 @@ const contentLoaded = function () { if (mermaid.startOnLoad) { const { startOnLoad } = mermaidAPI.getConfig(); if (startOnLoad) { - mermaid.init().catch((err) => log.error('Mermaid failed to initialize', err)); + mermaid.run().catch((err) => log.error('Mermaid failed to initialize', err)); } } }; @@ -363,14 +278,10 @@ if (typeof document !== 'undefined') { * This is provided for environments where the mermaid object can't directly have a new member added * to it (eg. dart interop wrapper). (Initially there is no parseError member of mermaid). * - * @param newParseErrorHandler - New parseError() callback. + * @param parseErrorHandler - New parseError() callback. */ -const setParseErrorHandler = function (newParseErrorHandler: (err: any, hash: any) => void) { - mermaid.parseError = newParseErrorHandler; -}; - -const parse = (txt: string) => { - return mermaidAPI.parse(txt, mermaid.parseError); +const setParseErrorHandler = function (parseErrorHandler: (err: any, hash: any) => void) { + mermaid.parseError = parseErrorHandler; }; const executionQueue: (() => Promise)[] = []; @@ -394,16 +305,19 @@ const executeQueue = async () => { }; /** - * @param txt - The mermaid code to be parsed. - * @deprecated This is an internal function and should not be used. Will be removed in v10. + * 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. + * @throws Error if the diagram is invalid and parseOptions.suppressErrors is false. */ -const parseAsync = (txt: string): Promise => { +const parse = async (text: string, parseOptions?: ParseOptions): Promise => { 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.parseAsync(txt, mermaid.parseError).then( + mermaidAPI.parse(text, parseOptions).then( (r) => { // This resolves for the promise for the queue handling res(r); @@ -412,6 +326,7 @@ const parseAsync = (txt: string): Promise => { }, (e) => { log.error('Error parsing', e); + mermaid.parseError?.(e); rej(e); reject(e); } @@ -422,21 +337,13 @@ const parseAsync = (txt: string): Promise => { }); }; -/** - * @deprecated This is an internal function and should not be used. Will be removed in v10. - */ -const renderAsync = ( - id: string, - text: string, - cb?: (svgCode: string, bindFunctions?: (element: Element) => void) => void, - container?: Element -): Promise => { +const render = (id: string, text: string, container?: Element): Promise => { 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.renderAsync(id, text, cb, container).then( + mermaidAPI.render(id, text, container).then( (r) => { // This resolves for the promise for the queue handling res(r); @@ -445,6 +352,7 @@ const renderAsync = ( }, (e) => { log.error('Error parsing', e); + mermaid.parseError?.(e); rej(e); reject(e); } @@ -457,31 +365,23 @@ const renderAsync = ( const mermaid: { startOnLoad: boolean; - diagrams: any; parseError?: ParseErrorFunction; mermaidAPI: typeof mermaidAPI; parse: typeof parse; - parseAsync: typeof parseAsync; - render: typeof mermaidAPI.render; - renderAsync: typeof renderAsync; + render: typeof render; init: typeof init; - initThrowsErrors: typeof initThrowsErrors; - initThrowsErrorsAsync: typeof initThrowsErrorsAsync; + run: typeof run; registerExternalDiagrams: typeof registerExternalDiagrams; initialize: typeof initialize; contentLoaded: typeof contentLoaded; setParseErrorHandler: typeof setParseErrorHandler; } = { startOnLoad: true, - diagrams: {}, mermaidAPI, parse, - parseAsync, - render: mermaidAPI.render, - renderAsync, + render, init, - initThrowsErrors, - initThrowsErrorsAsync, + run, registerExternalDiagrams, initialize, parseError: undefined, diff --git a/packages/mermaid/src/mermaidAPI.spec.ts b/packages/mermaid/src/mermaidAPI.spec.ts index 67138435e..cf858b58e 100644 --- a/packages/mermaid/src/mermaidAPI.spec.ts +++ b/packages/mermaid/src/mermaidAPI.spec.ts @@ -76,7 +76,7 @@ import { compile, serialize } from 'stylis'; // ------------------------------------------------------------------------------------- -describe('mermaidAPI', function () { +describe('mermaidAPI', () => { describe('encodeEntities', () => { it('removes the ending ; from style [text1]:[optional word]#[text2]; with ', () => { const text = 'style this; is ; everything :something#not-nothing; and this too;'; @@ -515,13 +515,13 @@ describe('mermaidAPI', function () { }); }); - describe('initialize', function () { - beforeEach(function () { + describe('initialize', () => { + beforeEach(() => { document.body.innerHTML = ''; mermaidAPI.globalReset(); }); - it('copies a literal into the configuration', function () { + it('copies a literal into the configuration', () => { const orgConfig: any = mermaidAPI.getConfig(); expect(orgConfig.testLiteral).toBe(undefined); @@ -533,7 +533,7 @@ describe('mermaidAPI', function () { expect(config.testLiteral).toBe(true); }); - it('copies an object into the configuration', function () { + it('copies an object into the configuration', () => { const orgConfig: any = mermaidAPI.getConfig(); expect(orgConfig.testObject).toBe(undefined); @@ -559,7 +559,7 @@ describe('mermaidAPI', function () { expect(config.testObject.test3).toBe(true); }); - it('resets mermaid config to global defaults', function () { + it('resets mermaid config to global defaults', () => { const config = { logLevel: 0, securityLevel: 'loose', @@ -576,7 +576,7 @@ describe('mermaidAPI', function () { expect(mermaidAPI.getConfig().securityLevel).toBe('strict'); }); - it('prevents changes to site defaults (sneaky)', function () { + it('prevents changes to site defaults (sneaky)', () => { const config: any = { logLevel: 0, }; @@ -584,7 +584,7 @@ describe('mermaidAPI', function () { const siteConfig = mermaidAPI.getSiteConfig(); expect(mermaidAPI.getConfig().logLevel).toBe(0); config.secure = { - toString: function () { + toString: () => { mermaidAPI.initialize({ securityLevel: 'loose' }); }, }; @@ -595,7 +595,7 @@ describe('mermaidAPI', function () { expect(mermaidAPI.getSiteConfig()).toEqual(siteConfig); expect(mermaidAPI.getConfig()).toEqual(siteConfig); }); - it('prevents clobbering global defaults (direct)', function () { + it('prevents clobbering global defaults (direct)', () => { const config = assignWithDepth({}, mermaidAPI.defaultConfig); assignWithDepth(config, { logLevel: 0 }); @@ -611,7 +611,7 @@ describe('mermaidAPI', function () { ); expect(mermaidAPI.defaultConfig['logLevel']).toBe(5); }); - it('prevents changes to global defaults (direct)', function () { + it('prevents changes to global defaults (direct)', () => { let error: any = { message: '' }; try { mermaidAPI.defaultConfig['logLevel'] = 0; @@ -623,7 +623,7 @@ describe('mermaidAPI', function () { ); expect(mermaidAPI.defaultConfig['logLevel']).toBe(5); }); - it('prevents sneaky changes to global defaults (assignWithDepth)', function () { + it('prevents sneaky changes to global defaults (assignWithDepth)', () => { const config = { logLevel: 0, }; @@ -640,48 +640,61 @@ describe('mermaidAPI', function () { }); }); - describe('dompurify config', function () { - it('allows dompurify config to be set', function () { + describe('dompurify config', () => { + it('allows dompurify config to be set', () => { mermaidAPI.initialize({ dompurifyConfig: { ADD_ATTR: ['onclick'] } }); expect(mermaidAPI!.getConfig()!.dompurifyConfig!.ADD_ATTR).toEqual(['onclick']); }); }); - describe('parse', function () { + describe('parse', () => { mermaid.parseError = undefined; // ensure it parseError undefined - it('throws for an invalid definition (with no mermaid.parseError() defined)', function () { + it('throws for an invalid definition (with no mermaid.parseError() defined)', async () => { expect(mermaid.parseError).toEqual(undefined); - expect(() => mermaidAPI.parse('this is not a mermaid diagram definition')).toThrow(); + await expect( + mermaidAPI.parse('this is not a mermaid diagram definition') + ).rejects.toThrowError(); }); - it('throws for a nicer error for a invalid definition starting with `---`', function () { + it('throws for a nicer error for a invalid definition starting with `---`', async () => { expect(mermaid.parseError).toEqual(undefined); - expect(() => + await expect( mermaidAPI.parse(` --- title: a malformed YAML front-matter `) - ).toThrow( + ).rejects.toThrow( 'Diagrams beginning with --- are not valid. ' + 'If you were trying to use a YAML front-matter, please ensure that ' + "you've correctly opened and closed the YAML front-matter with unindented `---` blocks" ); }); - it('does not throw for a valid definition', function () { - expect(() => mermaidAPI.parse('graph TD;A--x|text including URL space|B;')).not.toThrow(); + it('does not throw for a valid definition', async () => { + await expect( + mermaidAPI.parse('graph TD;A--x|text including URL space|B;') + ).resolves.not.toThrow(); }); - it('returns false for invalid definition WITH a parseError() callback defined', function () { - let parseErrorWasCalled = false; - // also test setParseErrorHandler() call working to set mermaid.parseError - expect( - mermaidAPI.parse('this is not a mermaid diagram definition', () => { - parseErrorWasCalled = true; - }) - ).toEqual(false); - expect(parseErrorWasCalled).toEqual(true); + it('throws for invalid definition', async () => { + await expect( + mermaidAPI.parse('this is not a mermaid diagram definition') + ).rejects.toThrowErrorMatchingInlineSnapshot( + '"No diagram type detected for text: this is not a mermaid diagram definition"' + ); }); - it('returns true for valid definition', function () { - expect(mermaidAPI.parse('graph TD;A--x|text including URL space|B;')).toEqual(true); + 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); + }); + it('resolves for valid definition', async () => { + await expect( + mermaidAPI.parse('graph TD;A--x|text including URL space|B;') + ).resolves.not.toThrow(); + }); + 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); }); }); @@ -720,10 +733,10 @@ describe('mermaidAPI', function () { const diagramText = `${diagramType}\n accTitle: ${a11yTitle}\n accDescr: ${a11yDescr}\n`; const expectedDiagramType = testedDiagram.expectedType; - it('aria-roledscription is set to the diagram type, addSVGa11yTitleDescription is called', () => { + it('aria-roledscription is set to the diagram type, addSVGa11yTitleDescription is called', async () => { const a11yDiagramInfo_spy = vi.spyOn(accessibility, 'setA11yDiagramInfo'); const a11yTitleDesc_spy = vi.spyOn(accessibility, 'addSVGa11yTitleDescription'); - mermaidAPI.render(id, diagramText); + await mermaidAPI.render(id, diagramText); expect(a11yDiagramInfo_spy).toHaveBeenCalledWith( expect.anything(), expectedDiagramType @@ -735,7 +748,7 @@ describe('mermaidAPI', function () { }); }); - describe('renderAsync', () => { + describe('render', () => { // Be sure to add async before each test (anonymous) method // These are more like integration tests right now because nothing is mocked. @@ -775,7 +788,7 @@ describe('mermaidAPI', function () { it('aria-roledscription is set to the diagram type, addSVGa11yTitleDescription is called', async () => { const a11yDiagramInfo_spy = vi.spyOn(accessibility, 'setA11yDiagramInfo'); const a11yTitleDesc_spy = vi.spyOn(accessibility, 'addSVGa11yTitleDescription'); - await mermaidAPI.renderAsync(id, diagramText); + await mermaidAPI.render(id, diagramText); expect(a11yDiagramInfo_spy).toHaveBeenCalledWith( expect.anything(), expectedDiagramType diff --git a/packages/mermaid/src/mermaidAPI.ts b/packages/mermaid/src/mermaidAPI.ts index 68db59b34..64e0bbce2 100644 --- a/packages/mermaid/src/mermaidAPI.ts +++ b/packages/mermaid/src/mermaidAPI.ts @@ -10,17 +10,14 @@ * * In addition to the render function, a number of behavioral configuration options are available. */ +// @ts-ignore TODO: Investigate D3 issue import { select } from 'd3'; import { compile, serialize, stringify } from 'stylis'; // @ts-ignore: TODO Fix ts errors -import pkg from '../package.json'; +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'; @@ -36,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'; @@ -69,30 +66,54 @@ interface DiagramStyleClassDef { textStyles?: string[]; } +export interface ParseOptions { + suppressErrors?: boolean; +} + // 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. // @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; -// ---------------------------------------------------------------------------- - -/** - * @param text - The mermaid diagram definition. - * @param parseError - If set, handles errors. - */ -function parse(text: string, parseError?: ParseErrorFunction): boolean { - addDiagrams(); - const diagram = new Diagram(text, parseError); - return diagram.parse(text, parseError); +export interface RenderResult { + /** + * The svg code for the rendered graph. + */ + svg: 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. + * ```js + * const { svg, bindFunctions } = mermaidAPI.render('id1', 'graph TD;A-->B'); + * div.innerHTML = svg; + * bindFunctions?.(div); // To call bindFunctions only if it's present. + * ``` + */ + bindFunctions?: (element: Element) => void; } /** + * 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.suppressErrors is true. + * @throws Error if the diagram is invalid and parseOptions.suppressErrors is false. */ -async function parseAsync(text: string, parseError?: ParseErrorFunction): Promise { + +async function parse(text: string, parseOptions?: ParseOptions): Promise { 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?.suppressErrors) { + return error === undefined; + } + if (error) { + throw error; + } } /** @@ -374,12 +395,12 @@ export const removeExistingElements = ( * element will be removed when rendering is completed. * @returns Returns the rendered element as a string containing the SVG definition. */ -const render = function ( + +const render = async function ( id: string, text: string, - cb?: (svgCode: string, bindFunctions?: (element: Element) => void) => void, svgContainingElement?: Element -): string { +): Promise { addDiagrams(); configApi.reset(); @@ -395,8 +416,7 @@ const render = 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; } @@ -461,218 +481,10 @@ const render = 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 = getDiagramFromText(text); - if ('then' in diag) { - throw new Error('Diagram is a promise. Use renderAsync.'); - } - } catch (error) { - diag = new Diagram('error'); - parseEncounteredException = error; - } - - // Get the temporary div element containing the svg (the parent HTML Element) - const element = root.select(enclosingDivID_selector).node(); - const graphType = diag.type; - - // ------------------------------------------------------------------------------- - // Create and insert the styles (user styles, theme styles, config styles) - // These are dealing with HTML Elements, not d3 nodes. - - // Insert an element into svg. This is where we put the styles - const svg = element.firstChild; - const firstChild = svg.firstChild; - const diagramClassDefs = CLASSDEF_DIAGRAMS.includes(graphType) - ? diag.renderer.getClasses(text, diag) - : {}; - - const rules = createUserStyles( - config, - graphType, - // @ts-ignore convert renderer to TS. - diagramClassDefs, - idSelector - ); - - // svg is a HTML element (not a d3 node) - const style1 = document.createElement('style'); - style1.innerHTML = rules; - svg.insertBefore(style1, firstChild); - - // ------------------------------------------------------------------------------- - // Draw the diagram with the renderer - try { - diag.renderer.draw(text, id, pkg.version, diag); - } catch (e) { - errorRenderer.draw(text, id, pkg.version); - throw e; - } - - // This is the d3 node for the svg element - const svgNode = root.select(`${enclosingDivID_selector} svg`); - const a11yTitle = diag.db.getAccTitle?.(); - const a11yDescr = diag.db.getAccDescription?.(); - addA11yInfo(graphType, svgNode, a11yTitle, a11yDescr); - - // ------------------------------------------------------------------------------- - // Clean up SVG code - 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; - - log.debug('config.arrowMarkerAbsolute', config.arrowMarkerAbsolute); - svgCode = cleanUpSvgCode(svgCode, isSandboxed, evaluate(config.arrowMarkerAbsolute)); - - if (isSandboxed) { - const svgEl = root.select(enclosingDivID_selector + ' svg').node(); - svgCode = putIntoIFrame(svgCode, svgEl); - } else if (!isLooseSecurityLevel) { - // Sanitize the svgCode using DOMPurify - svgCode = DOMPurify.sanitize(svgCode, { - ADD_TAGS: DOMPURIFY_TAGS, - ADD_ATTR: DOMPURIFY_ATTR, - }); - } - - // ------------------------------------------------------------------------------- - // 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(); - - // ------------------------------------------------------------------------------- - // Remove the temporary element if appropriate - const tmpElementSelector = isSandboxed ? iFrameID_selector : enclosingDivID_selector; - const node = select(tmpElementSelector).node(); - if (node && 'remove' in node) { - node.remove(); - } - - if (parseEncounteredException) { - throw parseEncounteredException; - } - - return svgCode; -}; - -/** - * @deprecated This is an internal function and should not be used. Will be removed in v10. - */ - -const renderAsync = async function ( - id: string, - text: string, - cb?: (svgCode: string, bindFunctions?: (element: Element) => void) => void, - svgContainingElement?: Element -): Promise { - addDiagrams(); - - configApi.reset(); - - // Add Directives. Must do this before getting the config and before creating the diagram. - const graphInit = utils.detectInit(text); - if (graphInit) { - directiveSanitizer(graphInit); - configApi.addDirective(graphInit); - } - - const config = configApi.getConfig(); - log.debug(config); - - // Check the maximum allowed text size - // TODO: Remove magic number - if (text.length > (config?.maxTextSize ?? 50000)) { - text = MAX_TEXTLENGTH_EXCEEDED_MSG; - } - - // clean up text CRLFs - text = text.replace(/\r\n?/g, '\n'); // parser problems on CRLF ignore all CR and leave LF;; - - const idSelector = '#' + id; - const iFrameID = 'i' + id; - const iFrameID_selector = '#' + iFrameID; - const enclosingDivID = 'd' + id; - const enclosingDivID_selector = '#' + enclosingDivID; - - let root: any = select('body'); - - const isSandboxed = config.securityLevel === SECURITY_LVL_SANDBOX; - const isLooseSecurityLevel = config.securityLevel === SECURITY_LVL_LOOSE; - - const fontFamily = config.fontFamily; - - // ------------------------------------------------------------------------------- - // Define the root d3 node - // In regular execution the svgContainingElement will be the element with a mermaid class - - if (svgContainingElement !== undefined) { - if (svgContainingElement) { - svgContainingElement.innerHTML = ''; - } - - if (isSandboxed) { - // If we are in sandboxed mode, we do everything mermaid related in a (sandboxed )iFrame - const iframe = sandboxedIframe(select(svgContainingElement), iFrameID); - root = select(iframe.nodes()[0]!.contentDocument!.body); - root.node().style.margin = 0; - } else { - root = select(svgContainingElement); - } - appendDivSvgG(root, id, enclosingDivID, `font-family: ${fontFamily}`, XMLNS_XLINK_STD); - } else { - // No svgContainingElement was provided - - // If there is an existing element with the id, we remove it. This likely a previously rendered diagram - removeExistingElements(document, id, enclosingDivID, iFrameID); - - // Add the temporary div used for rendering with the enclosingDivID. - // This temporary div will contain a svg with the id == id - - if (isSandboxed) { - // If we are in sandboxed mode, we do everything mermaid related in a (sandboxed) iFrame - const iframe = sandboxedIframe(select('body'), iFrameID); - root = select(iframe.nodes()[0]!.contentDocument!.body); - root.node().style.margin = 0; - } else { - root = select('body'); - } - - appendDivSvgG(root, id, enclosingDivID); - } - - text = encodeEntities(text); - - // ------------------------------------------------------------------------------- - // Create the diagram - - // Important that we do not create the diagram until after the directives have been included - let diag; - let parseEncounteredException; - - try { - // diag = new Diagram(text); diag = await getDiagramFromText(text); } catch (error) { diag = new Diagram('error'); @@ -708,9 +520,9 @@ const renderAsync = async function ( // ------------------------------------------------------------------------------- // Draw the diagram with the renderer try { - await diag.renderer.draw(text, id, pkg.version, diag); + await diag.renderer.draw(text, id, version, diag); } catch (e) { - errorRenderer.draw(text, id, pkg.version); + errorRenderer.draw(text, id, version); throw e; } @@ -725,7 +537,7 @@ const renderAsync = 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)); @@ -741,27 +553,6 @@ const renderAsync = 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(); // ------------------------------------------------------------------------------- @@ -776,7 +567,10 @@ const renderAsync = async function ( throw parseEncounteredException; } - return svgCode; + return { + svg: svgCode, + bindFunctions: diag.db.bindFunctions, + }; }; /** @@ -885,9 +679,7 @@ function addA11yInfo( export const mermaidAPI = Object.freeze({ render, - renderAsync, parse, - parseAsync, parseDirective, initialize, getConfig: configApi.getConfig, diff --git a/packages/mermaid/src/styles.ts b/packages/mermaid/src/styles.ts index 055f63be5..588c26cb1 100644 --- a/packages/mermaid/src/styles.ts +++ b/packages/mermaid/src/styles.ts @@ -1,39 +1,7 @@ -import classDiagram from './diagrams/class/styles'; -import er from './diagrams/er/styles'; -import error from './diagrams/error/styles'; -import flowchart from './diagrams/flowchart/styles'; -import gantt from './diagrams/gantt/styles'; -// import gitGraph from './diagrams/git/styles'; -import info from './diagrams/info/styles'; -import pie from './diagrams/pie/styles'; -import requirement from './diagrams/requirement/styles'; -import sequence from './diagrams/sequence/styles'; -import stateDiagram from './diagrams/state/styles'; -import journey from './diagrams/user-journey/styles'; -import c4 from './diagrams/c4/styles'; -import { FlowChartStyleOptions } from './diagrams/flowchart/styles'; +import type { FlowChartStyleOptions } from './diagrams/flowchart/styles'; import { log } from './logger'; -// TODO @knut: Inject from registerDiagram. -const themes: Record = { - flowchart, - 'flowchart-v2': flowchart, - sequence, - gantt, - classDiagram, - 'classDiagram-v2': classDiagram, - class: classDiagram, - stateDiagram, - state: stateDiagram, - // gitGraph, - info, - pie, - er, - error, - journey, - requirement, - c4, -}; +const themes: Record = {}; const getStyles = ( type: string, diff --git a/packages/mermaid/src/tests/MockedD3.ts b/packages/mermaid/src/tests/MockedD3.ts index 4600e2667..ccf21a269 100644 --- a/packages/mermaid/src/tests/MockedD3.ts +++ b/packages/mermaid/src/tests/MockedD3.ts @@ -1,4 +1,4 @@ -import type {} from '@vitest/spy'; +import type {} from '@vitest/spy/dist/index'; /** * This is a mocked/stubbed version of the d3 Selection type. Each of the main functions are all diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a388cf654..d32e5545f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -16,12 +16,15 @@ importers: '@cspell/eslint-plugin': specifier: ^6.14.2 version: 6.14.2 + '@types/cors': + specifier: ^2.8.13 + version: 2.8.13 '@types/eslint': specifier: ^8.4.10 version: 8.4.10 '@types/express': - specifier: ^4.17.14 - version: 4.17.14 + specifier: ^4.17.17 + version: 4.17.17 '@types/js-yaml': specifier: ^4.0.5 version: 4.0.5 @@ -45,10 +48,10 @@ importers: version: 4.2.1 '@typescript-eslint/eslint-plugin': specifier: ^5.48.2 - version: 5.48.2_iljmjqxcygjq3saipl7gerxpvi + version: 5.48.2_azmbqzqvrlvblbdtiwxwvyvjjy '@typescript-eslint/parser': specifier: ^5.48.2 - version: 5.48.2_yygwinqv3a2io74xmwofqb7uka + version: 5.48.2_et5x32uxl7z5ldub3ye5rhlyqm '@vitest/coverage-c8': specifier: ^0.28.4 version: 0.28.4_vun5xzxu3tkrssf3erdbijyyki @@ -61,6 +64,9 @@ importers: concurrently: specifier: ^7.5.0 version: 7.5.0 + cors: + specifier: ^2.8.5 + version: 2.8.5 coveralls: specifier: ^3.1.1 version: 3.1.1 @@ -87,7 +93,7 @@ importers: version: 7.1.0 eslint-plugin-jest: specifier: ^27.1.5 - version: 27.1.5_5rcd23qw3h5vuffwo2owxb3hw4 + version: 27.1.5_i5clxtuiaceouxhg5syqkw5wwi eslint-plugin-jsdoc: specifier: ^39.6.2 version: 39.6.2_eslint@8.32.0 @@ -152,20 +158,20 @@ importers: specifier: ^5.8.3 version: 5.8.3 start-server-and-test: - specifier: ^1.14.0 - version: 1.14.0 + specifier: ^1.15.4 + version: 1.15.4 ts-node: specifier: ^10.9.1 - version: 10.9.1_cbe7ovvae6zqfnmtgctpgpys54 + version: 10.9.1_w6ufic3jqylcjznzspnj4wjqfe typescript: specifier: ^4.8.4 - version: 4.8.4 + version: 4.9.5 vite: - specifier: ^4.0.0 - version: 4.0.1_@types+node@18.11.9 + specifier: ^4.1.1 + version: 4.1.1_@types+node@18.11.9 vitest: - specifier: ^0.28.4 - version: 0.28.4_vun5xzxu3tkrssf3erdbijyyki + specifier: ^0.28.5 + version: 0.28.5_vun5xzxu3tkrssf3erdbijyyki packages/mermaid: dependencies: @@ -182,8 +188,8 @@ importers: specifier: ^2.1.0 version: 2.1.0_cytoscape@3.23.0 d3: - specifier: ^7.0.0 - version: 7.6.1 + specifier: ^7.4.0 + version: 7.8.2 dagre-d3-es: specifier: 7.0.8 version: 7.0.8 @@ -199,7 +205,7 @@ importers: lodash-es: specifier: ^4.17.21 version: 4.17.21 - moment: + moment-mini: specifier: ^2.29.4 version: 2.29.4 non-layered-tidy-tree-layout: @@ -1166,7 +1172,6 @@ packages: /@braintree/sanitize-url/6.0.0: resolution: {integrity: sha512-mgmE7XBYY/21erpzhexk4Cj1cyTQ9LzvnTxtzM17BJ7ERMNE6W72mQRo0I1Ud8eFJ+RVVIcBNhLFZ3GX4XFz5w==} - dev: false /@colors/colors/1.5.0: resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} @@ -1260,11 +1265,11 @@ packages: '@types/node': 14.18.29 chalk: 4.1.2 cosmiconfig: 7.0.1 - cosmiconfig-typescript-loader: 4.1.0_nxlrwu45zhpwmwjzs33dzt3ak4 + cosmiconfig-typescript-loader: 4.1.0_2uclxasecupgvdn72amnhmyg7y lodash: 4.17.21 resolve-from: 5.0.0 - ts-node: 10.9.1_sqjhzn5m3vxyw66a2xhtc43hby - typescript: 4.8.4 + ts-node: 10.9.1_yxpazyh7n5pql7jdaglasgwqki + typescript: 4.9.5 transitivePeerDependencies: - '@swc/core' - '@swc/wasm' @@ -1751,15 +1756,6 @@ packages: dev: true optional: true - /@esbuild/android-arm/0.16.7: - resolution: {integrity: sha512-yhzDbiVcmq6T1/XEvdcJIVcXHdLjDJ5cQ0Dp9R9p9ERMBTeO1dR5tc8YYv8zwDeBw1xZm+Eo3MRo8cwclhBS0g==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] - requiresBuild: true - dev: true - optional: true - /@esbuild/android-arm/0.17.0: resolution: {integrity: sha512-hlbX5ym1V5kIKvnwFhm6rhar7MNqfJrZyYTNfk6+WS1uQfQmszFgXeyPH2beP3lSCumZyqX0zMBfOqftOpZ7GA==} engines: {node: '>=12'} @@ -1778,15 +1774,6 @@ packages: dev: true optional: true - /@esbuild/android-arm64/0.16.7: - resolution: {integrity: sha512-tYFw0lBJSEvLoGzzYh1kXuzoX1iPkbOk3O29VqzQb0HbOy7t/yw1hGkvwoJhXHwzQUPsShyYcTgRf6bDBcfnTw==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: true - optional: true - /@esbuild/android-arm64/0.17.0: resolution: {integrity: sha512-77GVyD7ToESy/7+9eI8z62GGBdS/hsqsrpM+JA4kascky86wHbN29EEFpkVvxajPL7k6mbLJ5VBQABdj7n9FhQ==} engines: {node: '>=12'} @@ -1805,15 +1792,6 @@ packages: dev: true optional: true - /@esbuild/android-x64/0.16.7: - resolution: {integrity: sha512-3P2OuTxwAtM3k/yEWTNUJRjMPG1ce8rXs51GTtvEC5z1j8fC1plHeVVczdeHECU7aM2/Buc0MwZ6ciM/zysnWg==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - requiresBuild: true - dev: true - optional: true - /@esbuild/android-x64/0.17.0: resolution: {integrity: sha512-TroxZdZhtAz0JyD0yahtjcbKuIXrBEAoAazaYSeR2e2tUtp9uXrcbpwFJF6oxxOiOOne6y7l4hx4YVnMW/tdFw==} engines: {node: '>=12'} @@ -1832,15 +1810,6 @@ packages: dev: true optional: true - /@esbuild/darwin-arm64/0.16.7: - resolution: {integrity: sha512-VUb9GK23z8jkosHU9yJNUgQpsfJn+7ZyBm6adi2Ec5/U241eR1tAn82QicnUzaFDaffeixiHwikjmnec/YXEZg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - /@esbuild/darwin-arm64/0.17.0: resolution: {integrity: sha512-wP/v4cgdWt1m8TS/WmbaBc3NZON10eCbm6XepdVc3zJuqruHCzCKcC9dTSTEk50zX04REcRcbIbdhTMciQoFIg==} engines: {node: '>=12'} @@ -1859,15 +1828,6 @@ packages: dev: true optional: true - /@esbuild/darwin-x64/0.16.7: - resolution: {integrity: sha512-duterlv3tit3HI9vhzMWnSVaB1B6YsXpFq1Ntd6Fou82BB1l4tucYy3FI9dHv3tvtDuS0NiGf/k6XsdBqPZ01w==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - /@esbuild/darwin-x64/0.17.0: resolution: {integrity: sha512-R4WB6D6V9KGO/3LVTT8UlwRJO26IBFatOdo/bRXksfJR0vyOi2/lgmAAMBSpgcnnwvts9QsWiyM++mTTlwRseA==} engines: {node: '>=12'} @@ -1886,15 +1846,6 @@ packages: dev: true optional: true - /@esbuild/freebsd-arm64/0.16.7: - resolution: {integrity: sha512-9kkycpBFes/vhi7B7o0cf+q2WdJi+EpVzpVTqtWFNiutARWDFFLcB93J8PR1cG228sucsl3B+7Ts27izE6qiaQ==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - /@esbuild/freebsd-arm64/0.17.0: resolution: {integrity: sha512-FO7+UEZv79gen2df8StFYFHZPI9ADozpFepLZCxY+O8sYLDa1rirvenmLwJiOHmeQRJ5orYedFeLk1PFlZ6t8Q==} engines: {node: '>=12'} @@ -1913,15 +1864,6 @@ packages: dev: true optional: true - /@esbuild/freebsd-x64/0.16.7: - resolution: {integrity: sha512-5Ahf6jzWXJ4J2uh9dpy5DKOO+PeRUE/9DMys6VuYfwgQzd6n5+pVFm58L2Z2gRe611RX6SdydnNaiIKM3svY7g==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - /@esbuild/freebsd-x64/0.17.0: resolution: {integrity: sha512-qCsNRsVTaC3ekwZcb2sa7l1gwCtJK3EqCWyDgpoQocYf3lRpbAzaCvqZSF2+NOO64cV+JbedXPsFiXU1aaVcIg==} engines: {node: '>=12'} @@ -1940,15 +1882,6 @@ packages: dev: true optional: true - /@esbuild/linux-arm/0.16.7: - resolution: {integrity: sha512-QqJnyCfu5OF78Olt7JJSZ7OSv/B4Hf+ZJWp4kkq9xwMsgu7yWq3crIic8gGOpDYTqVKKMDAVDgRXy5Wd/nWZyQ==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-arm/0.17.0: resolution: {integrity: sha512-Y2G2NU6155gcfNKvrakVmZV5xUAEhXjsN/uKtbKKRnvee0mHUuaT3OdQJDJKjHVGr6B0898pc3slRpI1PqspoQ==} engines: {node: '>=12'} @@ -1967,15 +1900,6 @@ packages: dev: true optional: true - /@esbuild/linux-arm64/0.16.7: - resolution: {integrity: sha512-2wv0xYDskk2+MzIm/AEprDip39a23Chptc4mL7hsHg26P0gD8RUhzmDu0KCH2vMThUI1sChXXoK9uH0KYQKaDg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-arm64/0.17.0: resolution: {integrity: sha512-js4Vlch5XJQYISbDVJd2hsI/MsfVUz6d/FrclCE73WkQmniH37vFpuQI42ntWAeBghDIfaPZ6f9GilhwGzVFUg==} engines: {node: '>=12'} @@ -1994,15 +1918,6 @@ packages: dev: true optional: true - /@esbuild/linux-ia32/0.16.7: - resolution: {integrity: sha512-APVYbEilKbD5ptmKdnIcXej2/+GdV65TfTjxR2Uk8t1EsOk49t6HapZW6DS/Bwlvh5hDwtLapdSumIVNGxgqLg==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-ia32/0.17.0: resolution: {integrity: sha512-7tl/jSPkF59R3zeFDB2/09zLGhcM7DM+tCoOqjJbQjuL6qbMWomGT2RglCqRFpCSdzBx0hukmPPgUAMlmdj0sQ==} engines: {node: '>=12'} @@ -2021,15 +1936,6 @@ packages: dev: true optional: true - /@esbuild/linux-loong64/0.16.7: - resolution: {integrity: sha512-5wPUAGclplQrAW7EFr3F84Y/d++7G0KykohaF4p54+iNWhUnMVU8Bh2sxiEOXUy4zKIdpHByMgJ5/Ko6QhtTUw==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-loong64/0.17.0: resolution: {integrity: sha512-OG356F7dIVVF+EXJx5UfzFr1I5l6ES53GlMNSr3U1MhlaVyrP9um5PnrSJ+7TSDAzUC7YGjxb2GQWqHLd5XFoA==} engines: {node: '>=12'} @@ -2048,15 +1954,6 @@ packages: dev: true optional: true - /@esbuild/linux-mips64el/0.16.7: - resolution: {integrity: sha512-hxzlXtWF6yWfkE/SMTscNiVqLOAn7fOuIF3q/kiZaXxftz1DhZW/HpnTmTTWrzrS7zJWQxHHT4QSxyAj33COmA==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-mips64el/0.17.0: resolution: {integrity: sha512-LWQJgGpxrjh2x08UYf6G5R+Km7zhkpCvKXtFQ6SX0fimDvy1C8kslgFHGxLS0wjGV8C4BNnENW/HNy57+RB7iA==} engines: {node: '>=12'} @@ -2075,15 +1972,6 @@ packages: dev: true optional: true - /@esbuild/linux-ppc64/0.16.7: - resolution: {integrity: sha512-WM83Dac0LdXty5xPhlOuCD5Egfk1xLND/oRLYeB7Jb/tY4kzFSDgLlq91wYbHua/s03tQGA9iXvyjgymMw62Vw==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-ppc64/0.17.0: resolution: {integrity: sha512-f40N8fKiTQslUcUuhof2/syOQ+DC9Mqdnm9d063pew+Ptv9r6dBNLQCz4300MOfCLAbb0SdnrcMSzHbMehXWLw==} engines: {node: '>=12'} @@ -2102,15 +1990,6 @@ packages: dev: true optional: true - /@esbuild/linux-riscv64/0.16.7: - resolution: {integrity: sha512-3nkNnNg4Ax6MS/l8O8Ynq2lGEVJYyJ2EoY3PHjNJ4PuZ80EYLMrFTFZ4L/Hc16AxgtXKwmNP9TM0YKNiBzBiJQ==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-riscv64/0.17.0: resolution: {integrity: sha512-sc/pvLexRvxgEbmeq7LfLGnzUBFi/E2MGbnQj3CG8tnQ90tWPTi+9CbZEgIADhj6CAlCCmqxpUclIV1CRVUOTw==} engines: {node: '>=12'} @@ -2129,15 +2008,6 @@ packages: dev: true optional: true - /@esbuild/linux-s390x/0.16.7: - resolution: {integrity: sha512-3SA/2VJuv0o1uD7zuqxEP+RrAyRxnkGddq0bwHQ98v1KNlzXD/JvxwTO3T6GM5RH6JUd29RTVQTOJfyzMkkppA==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-s390x/0.17.0: resolution: {integrity: sha512-7xq9/kY0vunCL2vjHKdHGI+660pCdeEC6K6TWBVvbTGXvT8s/qacfxMgr8PCeQRbNUZLOA13G6/G1+c0lYXO1A==} engines: {node: '>=12'} @@ -2156,15 +2026,6 @@ packages: dev: true optional: true - /@esbuild/linux-x64/0.16.7: - resolution: {integrity: sha512-xi/tbqCqvPIzU+zJVyrpz12xqciTAPMi2fXEWGnapZymoGhuL2GIWIRXg4O2v5BXaYA5TSaiKYE14L0QhUTuQg==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-x64/0.17.0: resolution: {integrity: sha512-o7FhBLONk1mLT2ytlj/j/WuJcPdhWcVpysSJn1s9+zRdLwLKveipbPi5SIasJIqMq0T4CkQW76pxJYMqz9HrQA==} engines: {node: '>=12'} @@ -2183,15 +2044,6 @@ packages: dev: true optional: true - /@esbuild/netbsd-x64/0.16.7: - resolution: {integrity: sha512-NUsYbq3B+JdNKn8SXkItFvdes9qTwEoS3aLALtiWciW/ystiCKM20Fgv9XQBOXfhUHyh5CLEeZDXzLOrwBXuCQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - requiresBuild: true - dev: true - optional: true - /@esbuild/netbsd-x64/0.17.0: resolution: {integrity: sha512-V6xXsv71b8vwFCW/ky82Rs//SbyA+ORty6A7Mzkg33/4NbYZ/1Vcbk7qAN5oi0i/gS4Q0+7dYT7NqaiVZ7+Xjw==} engines: {node: '>=12'} @@ -2210,15 +2062,6 @@ packages: dev: true optional: true - /@esbuild/openbsd-x64/0.16.7: - resolution: {integrity: sha512-qjwzsgeve9I8Tbsko2FEkdSk2iiezuNGFgipQxY/736NePXDaDZRodIejYGWOlbYXugdxb0nif5yvypH6lKBmA==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - requiresBuild: true - dev: true - optional: true - /@esbuild/openbsd-x64/0.17.0: resolution: {integrity: sha512-StlQor6A0Y9SSDxraytr46Qbz25zsSDmsG3MCaNkBnABKHP3QsngOCfdBikqHVVrXeK0KOTmtX92/ncTGULYgQ==} engines: {node: '>=12'} @@ -2237,15 +2080,6 @@ packages: dev: true optional: true - /@esbuild/sunos-x64/0.16.7: - resolution: {integrity: sha512-mFWDz4RoBTzPphTCkM7Kc7Qpa0o/Z01acajR+Ai7LdfKgcP/C6jYOaKwv7nKzD0+MjOT20j7You9g4ozYy1dKQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - requiresBuild: true - dev: true - optional: true - /@esbuild/sunos-x64/0.17.0: resolution: {integrity: sha512-K64Wqw57j8KrwjR3QjsuzN/qDGK6Cno6QYtIlWAmGab5iYPBZCWz7HFtF2a86/130LmUsdXqOID7J0SmjjRFIQ==} engines: {node: '>=12'} @@ -2264,15 +2098,6 @@ packages: dev: true optional: true - /@esbuild/win32-arm64/0.16.7: - resolution: {integrity: sha512-m39UmX19RvEIuC8sYZ0M+eQtdXw4IePDSZ78ZQmYyFaXY9krq4YzQCK2XWIJomNLtg4q+W5aXr8bW3AbqWNoVg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true - /@esbuild/win32-arm64/0.17.0: resolution: {integrity: sha512-hly6iSWAf0hf3aHD18/qW7iFQbg9KAQ0RFGG9plcxkhL4uGw43O+lETGcSO/PylNleFowP/UztpF6U4oCYgpPw==} engines: {node: '>=12'} @@ -2291,15 +2116,6 @@ packages: dev: true optional: true - /@esbuild/win32-ia32/0.16.7: - resolution: {integrity: sha512-1cbzSEZA1fANwmT6rjJ4G1qQXHxCxGIcNYFYR9ctI82/prT38lnwSRZ0i5p/MVXksw9eMlHlet6pGu2/qkXFCg==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true - optional: true - /@esbuild/win32-ia32/0.17.0: resolution: {integrity: sha512-aL4EWPh0nyC5uYRfn+CHkTgawd4DjtmwquthNDmGf6Ht6+mUc+bQXyZNH1QIw8x20hSqFc4Tf36aLLWP/TPR3g==} engines: {node: '>=12'} @@ -2318,15 +2134,6 @@ packages: dev: true optional: true - /@esbuild/win32-x64/0.16.7: - resolution: {integrity: sha512-QaQ8IH0JLacfGf5cf0HCCPnQuCTd/dAI257vXBgb/cccKGbH/6pVtI1gwhdAQ0Y48QSpTIFrh9etVyNdZY+zzw==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - /@esbuild/win32-x64/0.17.0: resolution: {integrity: sha512-W6IIQ9Rt43I/GqfXeBFLk0TvowKBoirs9sw2LPfhHax6ayMlW5PhFzSJ76I1ac9Pk/aRcSMrHWvVyZs8ZPK2wA==} engines: {node: '>=12'} @@ -2708,6 +2515,10 @@ packages: resolution: {integrity: sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==} dev: true + /@sideway/formula/3.0.1: + resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==} + dev: true + /@sideway/pinpoint/2.0.0: resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} dev: true @@ -2844,6 +2655,12 @@ packages: '@types/node': 18.11.9 dev: true + /@types/cors/2.8.13: + resolution: {integrity: sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==} + dependencies: + '@types/node': 18.11.9 + dev: true + /@types/cytoscape/3.19.9: resolution: {integrity: sha512-oqCx0ZGiBO0UESbjgq052vjDAy2X53lZpMrWqiweMpvVwKw/2IiYDdzPFK6+f4tMfdv9YKEM9raO5bAZc3UYBg==} dev: true @@ -3069,6 +2886,14 @@ packages: '@types/range-parser': 1.2.4 dev: true + /@types/express-serve-static-core/4.17.33: + resolution: {integrity: sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==} + dependencies: + '@types/node': 18.11.9 + '@types/qs': 6.9.7 + '@types/range-parser': 1.2.4 + dev: true + /@types/express/4.17.14: resolution: {integrity: sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==} dependencies: @@ -3078,6 +2903,15 @@ packages: '@types/serve-static': 1.15.0 dev: true + /@types/express/4.17.17: + resolution: {integrity: sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==} + dependencies: + '@types/body-parser': 1.19.2 + '@types/express-serve-static-core': 4.17.33 + '@types/qs': 6.9.7 + '@types/serve-static': 1.15.0 + dev: true + /@types/flexsearch/0.7.3: resolution: {integrity: sha512-HXwADeHEP4exXkCIwy2n1+i0f1ilP1ETQOH5KDOugjkTFZPntWo0Gr8stZOaebkxsdx+k0X/K6obU/+it07ocg==} dev: true @@ -3154,6 +2988,10 @@ packages: resolution: {integrity: sha512-zmEmF5OIM3rb7SbLCFYoQhO4dGt2FRM9AMkxvA3LaADOF1n8in/zGJlWji9fmafLoNyz+FoL6FE0SLtGIArD7w==} dev: true + /@types/lodash/4.14.189: + resolution: {integrity: sha512-kb9/98N6X8gyME9Cf7YaqIMvYGnBSWqEci6tiettE6iJWH1XdJz/PO8LB0GtLCG7x8dU3KWhZT+lA1a35127tA==} + dev: true + /@types/markdown-it/12.2.3: resolution: {integrity: sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==} dependencies: @@ -3355,7 +3193,7 @@ packages: - supports-color dev: true - /@typescript-eslint/eslint-plugin/5.48.2_iljmjqxcygjq3saipl7gerxpvi: + /@typescript-eslint/eslint-plugin/5.48.2_azmbqzqvrlvblbdtiwxwvyvjjy: resolution: {integrity: sha512-sR0Gja9Ky1teIq4qJOl0nC+Tk64/uYdX+mi+5iB//MH8gwyx8e3SOyhEzeLZEFEEfCaLf8KJq+Bd/6je1t+CAg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -3366,18 +3204,18 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/parser': 5.48.2_yygwinqv3a2io74xmwofqb7uka + '@typescript-eslint/parser': 5.48.2_et5x32uxl7z5ldub3ye5rhlyqm '@typescript-eslint/scope-manager': 5.48.2 - '@typescript-eslint/type-utils': 5.48.2_yygwinqv3a2io74xmwofqb7uka - '@typescript-eslint/utils': 5.48.2_yygwinqv3a2io74xmwofqb7uka + '@typescript-eslint/type-utils': 5.48.2_et5x32uxl7z5ldub3ye5rhlyqm + '@typescript-eslint/utils': 5.48.2_et5x32uxl7z5ldub3ye5rhlyqm debug: 4.3.4 eslint: 8.32.0 ignore: 5.2.0 natural-compare-lite: 1.4.0 regexpp: 3.2.0 semver: 7.3.8 - tsutils: 3.21.0_typescript@4.8.4 - typescript: 4.8.4 + tsutils: 3.21.0_typescript@4.9.5 + typescript: 4.9.5 transitivePeerDependencies: - supports-color dev: true @@ -3402,7 +3240,7 @@ packages: - supports-color dev: true - /@typescript-eslint/parser/5.48.2_yygwinqv3a2io74xmwofqb7uka: + /@typescript-eslint/parser/5.48.2_et5x32uxl7z5ldub3ye5rhlyqm: resolution: {integrity: sha512-38zMsKsG2sIuM5Oi/olurGwYJXzmtdsHhn5mI/pQogP+BjYVkK5iRazCQ8RGS0V+YLk282uWElN70zAAUmaYHw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -3414,10 +3252,10 @@ packages: dependencies: '@typescript-eslint/scope-manager': 5.48.2 '@typescript-eslint/types': 5.48.2 - '@typescript-eslint/typescript-estree': 5.48.2_typescript@4.8.4 + '@typescript-eslint/typescript-estree': 5.48.2_typescript@4.9.5 debug: 4.3.4 eslint: 8.32.0 - typescript: 4.8.4 + typescript: 4.9.5 transitivePeerDependencies: - supports-color dev: true @@ -3458,7 +3296,7 @@ packages: - supports-color dev: true - /@typescript-eslint/type-utils/5.48.2_yygwinqv3a2io74xmwofqb7uka: + /@typescript-eslint/type-utils/5.48.2_et5x32uxl7z5ldub3ye5rhlyqm: resolution: {integrity: sha512-QVWx7J5sPMRiOMJp5dYshPxABRoZV1xbRirqSk8yuIIsu0nvMTZesKErEA3Oix1k+uvsk8Cs8TGJ6kQ0ndAcew==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -3468,12 +3306,12 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 5.48.2_typescript@4.8.4 - '@typescript-eslint/utils': 5.48.2_yygwinqv3a2io74xmwofqb7uka + '@typescript-eslint/typescript-estree': 5.48.2_typescript@4.9.5 + '@typescript-eslint/utils': 5.48.2_et5x32uxl7z5ldub3ye5rhlyqm debug: 4.3.4 eslint: 8.32.0 - tsutils: 3.21.0_typescript@4.8.4 - typescript: 4.8.4 + tsutils: 3.21.0_typescript@4.9.5 + typescript: 4.9.5 transitivePeerDependencies: - supports-color dev: true @@ -3509,7 +3347,28 @@ packages: - supports-color dev: true - /@typescript-eslint/typescript-estree/5.48.2_typescript@4.8.4: + /@typescript-eslint/typescript-estree/5.42.1_typescript@4.9.5: + resolution: {integrity: sha512-qElc0bDOuO0B8wDhhW4mYVgi/LZL+igPwXtV87n69/kYC/7NG3MES0jHxJNCr4EP7kY1XVsRy8C/u3DYeTKQmw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 5.42.1 + '@typescript-eslint/visitor-keys': 5.42.1 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.3.8 + tsutils: 3.21.0_typescript@4.9.5 + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/typescript-estree/5.48.2_typescript@4.9.5: resolution: {integrity: sha512-bibvD3z6ilnoVxUBFEgkO0k0aFvUc4Cttt0dAreEr+nrAHhWzkO83PEVVuieK3DqcgL6VAK5dkzK8XUVja5Zcg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -3524,12 +3383,32 @@ packages: globby: 11.1.0 is-glob: 4.0.3 semver: 7.3.8 - tsutils: 3.21.0_typescript@4.8.4 - typescript: 4.8.4 + tsutils: 3.21.0_typescript@4.9.5 + typescript: 4.9.5 transitivePeerDependencies: - supports-color dev: true + /@typescript-eslint/utils/5.42.1_et5x32uxl7z5ldub3ye5rhlyqm: + resolution: {integrity: sha512-Gxvf12xSp3iYZd/fLqiQRD4uKZjDNR01bQ+j8zvhPjpsZ4HmvEFL/tC4amGNyxN9Rq+iqvpHLhlqx6KTxz9ZyQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@types/json-schema': 7.0.11 + '@types/semver': 7.3.12 + '@typescript-eslint/scope-manager': 5.42.1 + '@typescript-eslint/types': 5.42.1 + '@typescript-eslint/typescript-estree': 5.42.1_typescript@4.9.5 + eslint: 8.32.0 + eslint-scope: 5.1.1 + eslint-utils: 3.0.0_eslint@8.32.0 + semver: 7.3.8 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + /@typescript-eslint/utils/5.42.1_yygwinqv3a2io74xmwofqb7uka: resolution: {integrity: sha512-Gxvf12xSp3iYZd/fLqiQRD4uKZjDNR01bQ+j8zvhPjpsZ4HmvEFL/tC4amGNyxN9Rq+iqvpHLhlqx6KTxz9ZyQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -3550,7 +3429,7 @@ packages: - typescript dev: true - /@typescript-eslint/utils/5.48.2_yygwinqv3a2io74xmwofqb7uka: + /@typescript-eslint/utils/5.48.2_et5x32uxl7z5ldub3ye5rhlyqm: resolution: {integrity: sha512-2h18c0d7jgkw6tdKTlNaM7wyopbLRBiit8oAxoP89YnuBOzCZ8g8aBCaCqq7h208qUTroL7Whgzam7UY3HVLow==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -3560,7 +3439,7 @@ packages: '@types/semver': 7.3.12 '@typescript-eslint/scope-manager': 5.48.2 '@typescript-eslint/types': 5.48.2 - '@typescript-eslint/typescript-estree': 5.48.2_typescript@4.8.4 + '@typescript-eslint/typescript-estree': 5.48.2_typescript@4.9.5 eslint: 8.32.0 eslint-scope: 5.1.1 eslint-utils: 3.0.0_eslint@8.32.0 @@ -3626,6 +3505,14 @@ packages: chai: 4.3.7 dev: true + /@vitest/expect/0.28.5: + resolution: {integrity: sha512-gqTZwoUTwepwGIatnw4UKpQfnoyV0Z9Czn9+Lo2/jLIt4/AXLTn+oVZxlQ7Ng8bzcNkR+3DqLJ08kNr8jRmdNQ==} + dependencies: + '@vitest/spy': 0.28.5 + '@vitest/utils': 0.28.5 + chai: 4.3.7 + dev: true + /@vitest/runner/0.28.4: resolution: {integrity: sha512-Q8UV6GjDvBSTfUoq0QXVCNpNOUrWu4P2qvRq7ssJWzn0+S0ojbVOxEjMt+8a32X6SdkhF8ak+2nkppsqV0JyNQ==} dependencies: @@ -3634,12 +3521,26 @@ packages: pathe: 1.1.0 dev: true + /@vitest/runner/0.28.5: + resolution: {integrity: sha512-NKkHtLB+FGjpp5KmneQjTcPLWPTDfB7ie+MmF1PnUBf/tGe2OjGxWyB62ySYZ25EYp9krR5Bw0YPLS/VWh1QiA==} + dependencies: + '@vitest/utils': 0.28.5 + p-limit: 4.0.0 + pathe: 1.1.0 + dev: true + /@vitest/spy/0.28.4: resolution: {integrity: sha512-8WuhfXLlvCXpNXEGJW6Gc+IKWI32435fQJLh43u70HnZ1otJOa2Cmg2Wy2Aym47ZnNCP4NolF+8cUPwd0MigKQ==} dependencies: tinyspy: 1.0.2 dev: true + /@vitest/spy/0.28.5: + resolution: {integrity: sha512-7if6rsHQr9zbmvxN7h+gGh2L9eIIErgf8nSKYDlg07HHimCxp4H6I/X/DPXktVPPLQfiZ1Cw2cbDIx9fSqDjGw==} + dependencies: + tinyspy: 1.0.2 + dev: true + /@vitest/ui/0.28.4: resolution: {integrity: sha512-LQfCCFc17n49mwtraV9/NAWl2DUqJS/9ZEa3fqJjoYO+HowdseQ5jvWflpzliCyfrIAh6cXVo1bNzHnDXe0cbw==} dependencies: @@ -3660,6 +3561,16 @@ packages: pretty-format: 27.5.1 dev: true + /@vitest/utils/0.28.5: + resolution: {integrity: sha512-UyZdYwdULlOa4LTUSwZ+Paz7nBHGTT72jKwdFSV4IjHF1xsokp+CabMdhjvVhYwkLfO88ylJT46YMilnkSARZA==} + dependencies: + cli-truncate: 3.1.0 + diff: 5.1.0 + loupe: 2.3.6 + picocolors: 1.0.0 + pretty-format: 27.5.1 + dev: true + /@vue/compiler-core/3.2.45: resolution: {integrity: sha512-rcMj7H+PYe5wBV3iYeUgbCglC+pbpN8hBLTJvRiK2eKQiWqu+fG9F+8sW99JdL4LQi7Re178UOxn09puSXvn4A==} dependencies: @@ -4239,6 +4150,10 @@ packages: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} dev: true + /arg/5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + dev: true + /argparse/1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} dependencies: @@ -4331,7 +4246,16 @@ packages: /axios/0.21.4_debug@4.3.2: resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==} dependencies: - follow-redirects: 1.15.2 + follow-redirects: 1.15.2_debug@4.3.2 + transitivePeerDependencies: + - debug + dev: true + + /axios/0.27.2_debug@4.3.4: + resolution: {integrity: sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==} + dependencies: + follow-redirects: 1.15.2_debug@4.3.4 + form-data: 4.0.0 transitivePeerDependencies: - debug dev: true @@ -5073,6 +4997,14 @@ packages: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} dev: true + /cors/2.8.5: + resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} + engines: {node: '>= 0.10'} + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + dev: true + /cose-base/1.0.3: resolution: {integrity: sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==} dependencies: @@ -5085,7 +5017,7 @@ packages: layout-base: 2.0.1 dev: false - /cosmiconfig-typescript-loader/4.1.0_nxlrwu45zhpwmwjzs33dzt3ak4: + /cosmiconfig-typescript-loader/4.1.0_2uclxasecupgvdn72amnhmyg7y: resolution: {integrity: sha512-HbWIuR5O+XO5Oj9SZ5bzgrD4nN+rfhrm2PMb0FVx+t+XIvC45n8F0oTNnztXtspWGw0i2IzHaUWFD5LzV1JB4A==} engines: {node: '>=12', npm: '>=6'} peerDependencies: @@ -5096,8 +5028,8 @@ packages: dependencies: '@types/node': 14.18.29 cosmiconfig: 7.0.1 - ts-node: 10.9.1_sqjhzn5m3vxyw66a2xhtc43hby - typescript: 4.8.4 + ts-node: 10.9.1_yxpazyh7n5pql7jdaglasgwqki + typescript: 4.9.5 dev: true /cosmiconfig/7.0.1: @@ -5508,12 +5440,10 @@ packages: engines: {node: '>=12'} dependencies: internmap: 2.0.3 - dev: false /d3-axis/3.0.0: resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==} engines: {node: '>=12'} - dev: false /d3-brush/3.0.0: resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==} @@ -5524,38 +5454,32 @@ packages: d3-interpolate: 3.0.1 d3-selection: 3.0.0 d3-transition: 3.0.1_d3-selection@3.0.0 - dev: false /d3-chord/3.0.1: resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==} engines: {node: '>=12'} dependencies: d3-path: 3.0.1 - dev: false /d3-color/3.1.0: resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} engines: {node: '>=12'} - dev: false /d3-contour/4.0.0: resolution: {integrity: sha512-7aQo0QHUTu/Ko3cP9YK9yUTxtoDEiDGwnBHyLxG5M4vqlBkO/uixMRele3nfsfj6UXOcuReVpVXzAboGraYIJw==} engines: {node: '>=12'} dependencies: d3-array: 3.2.0 - dev: false /d3-delaunay/6.0.2: resolution: {integrity: sha512-IMLNldruDQScrcfT+MWnazhHbDJhcRJyOEBAJfwQnHle1RPh6WDuLvxNArUju2VSMSUuKlY5BGHRJ2cYyoFLQQ==} engines: {node: '>=12'} dependencies: delaunator: 5.0.0 - dev: false /d3-dispatch/3.0.1: resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} engines: {node: '>=12'} - dev: false /d3-drag/3.0.0: resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} @@ -5563,7 +5487,6 @@ packages: dependencies: d3-dispatch: 3.0.1 d3-selection: 3.0.0 - dev: false /d3-dsv/3.0.1: resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} @@ -5573,19 +5496,16 @@ packages: commander: 7.2.0 iconv-lite: 0.6.3 rw: 1.3.3 - dev: false /d3-ease/3.0.1: resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} engines: {node: '>=12'} - dev: false /d3-fetch/3.0.1: resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} engines: {node: '>=12'} dependencies: d3-dsv: 3.0.1 - dev: false /d3-force/3.0.0: resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} @@ -5594,51 +5514,42 @@ packages: d3-dispatch: 3.0.1 d3-quadtree: 3.0.1 d3-timer: 3.0.1 - dev: false /d3-format/3.1.0: resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==} engines: {node: '>=12'} - dev: false /d3-geo/3.0.1: resolution: {integrity: sha512-Wt23xBych5tSy9IYAM1FR2rWIBFWa52B/oF/GYe5zbdHrg08FU8+BuI6X4PvTwPDdqdAdq04fuWJpELtsaEjeA==} engines: {node: '>=12'} dependencies: d3-array: 3.2.0 - dev: false /d3-hierarchy/3.1.2: resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} engines: {node: '>=12'} - dev: false /d3-interpolate/3.0.1: resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} engines: {node: '>=12'} dependencies: d3-color: 3.1.0 - dev: false /d3-path/3.0.1: resolution: {integrity: sha512-gq6gZom9AFZby0YLduxT1qmrp4xpBA1YZr19OI717WIdKE2OM5ETq5qrHLb301IgxhLwcuxvGZVLeeWc/k1I6w==} engines: {node: '>=12'} - dev: false /d3-polygon/3.0.1: resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==} engines: {node: '>=12'} - dev: false /d3-quadtree/3.0.1: resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} engines: {node: '>=12'} - dev: false /d3-random/3.0.1: resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} engines: {node: '>=12'} - dev: false /d3-scale-chromatic/3.0.0: resolution: {integrity: sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==} @@ -5646,7 +5557,6 @@ packages: dependencies: d3-color: 3.1.0 d3-interpolate: 3.0.1 - dev: false /d3-scale/4.0.2: resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} @@ -5657,38 +5567,32 @@ packages: d3-interpolate: 3.0.1 d3-time: 3.0.0 d3-time-format: 4.1.0 - dev: false /d3-selection/3.0.0: resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} engines: {node: '>=12'} - dev: false /d3-shape/3.1.0: resolution: {integrity: sha512-tGDh1Muf8kWjEDT/LswZJ8WF85yDZLvVJpYU9Nq+8+yW1Z5enxrmXOhTArlkaElU+CTn0OTVNli+/i+HP45QEQ==} engines: {node: '>=12'} dependencies: d3-path: 3.0.1 - dev: false /d3-time-format/4.1.0: resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} engines: {node: '>=12'} dependencies: d3-time: 3.0.0 - dev: false /d3-time/3.0.0: resolution: {integrity: sha512-zmV3lRnlaLI08y9IMRXSDshQb5Nj77smnfpnd2LrBa/2K281Jijactokeak14QacHs/kKq0AQ121nidNYlarbQ==} engines: {node: '>=12'} dependencies: d3-array: 3.2.0 - dev: false /d3-timer/3.0.1: resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} engines: {node: '>=12'} - dev: false /d3-transition/3.0.1_d3-selection@3.0.0: resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} @@ -5702,7 +5606,6 @@ packages: d3-interpolate: 3.0.1 d3-selection: 3.0.0 d3-timer: 3.0.1 - dev: false /d3-zoom/3.0.0: resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} @@ -5713,43 +5616,6 @@ packages: d3-interpolate: 3.0.1 d3-selection: 3.0.0 d3-transition: 3.0.1_d3-selection@3.0.0 - dev: false - - /d3/7.6.1: - resolution: {integrity: sha512-txMTdIHFbcpLx+8a0IFhZsbp+PfBBPt8yfbmukZTQFroKuFqIwqswF0qE5JXWefylaAVpSXFoKm3yP+jpNLFLw==} - engines: {node: '>=12'} - dependencies: - d3-array: 3.2.0 - d3-axis: 3.0.0 - d3-brush: 3.0.0 - d3-chord: 3.0.1 - d3-color: 3.1.0 - d3-contour: 4.0.0 - d3-delaunay: 6.0.2 - d3-dispatch: 3.0.1 - d3-drag: 3.0.0 - d3-dsv: 3.0.1 - d3-ease: 3.0.1 - d3-fetch: 3.0.1 - d3-force: 3.0.0 - d3-format: 3.1.0 - d3-geo: 3.0.1 - d3-hierarchy: 3.1.2 - d3-interpolate: 3.0.1 - d3-path: 3.0.1 - d3-polygon: 3.0.1 - d3-quadtree: 3.0.1 - d3-random: 3.0.1 - d3-scale: 4.0.2 - d3-scale-chromatic: 3.0.0 - d3-selection: 3.0.0 - d3-shape: 3.1.0 - d3-time: 3.0.0 - d3-time-format: 4.1.0 - d3-timer: 3.0.1 - d3-transition: 3.0.1_d3-selection@3.0.0 - d3-zoom: 3.0.0 - dev: false /d3/7.8.2: resolution: {integrity: sha512-WXty7qOGSHb7HR7CfOzwN1Gw04MUOzN8qh9ZUsvwycIMb4DYMpY9xczZ6jUorGtO6bR9BPMPaueIKwiDxu9uiQ==} @@ -5785,7 +5651,6 @@ packages: d3-timer: 3.0.1 d3-transition: 3.0.1_d3-selection@3.0.0 d3-zoom: 3.0.0 - dev: false /dagre-d3-es/7.0.8: resolution: {integrity: sha512-eykdoYQ4FwCJinEYS0gPL2f2w+BPbSLvnQSJ3Ye1vAoPjdkq6xIMKBv+UkICd3qZE26wBKIn3p+6n0QC7R1LyA==} @@ -5979,7 +5844,6 @@ packages: resolution: {integrity: sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==} dependencies: robust-predicates: 3.0.1 - dev: false /delayed-stream/1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} @@ -6226,36 +6090,6 @@ packages: '@esbuild/win32-x64': 0.16.17 dev: true - /esbuild/0.16.7: - resolution: {integrity: sha512-P6OBFYFSQOGzfApqCeYKqfKRRbCIRsdppTXFo4aAvtiW3o8TTyiIplBvHJI171saPAiy3WlawJHCveJVIOIx1A==} - engines: {node: '>=12'} - hasBin: true - requiresBuild: true - optionalDependencies: - '@esbuild/android-arm': 0.16.7 - '@esbuild/android-arm64': 0.16.7 - '@esbuild/android-x64': 0.16.7 - '@esbuild/darwin-arm64': 0.16.7 - '@esbuild/darwin-x64': 0.16.7 - '@esbuild/freebsd-arm64': 0.16.7 - '@esbuild/freebsd-x64': 0.16.7 - '@esbuild/linux-arm': 0.16.7 - '@esbuild/linux-arm64': 0.16.7 - '@esbuild/linux-ia32': 0.16.7 - '@esbuild/linux-loong64': 0.16.7 - '@esbuild/linux-mips64el': 0.16.7 - '@esbuild/linux-ppc64': 0.16.7 - '@esbuild/linux-riscv64': 0.16.7 - '@esbuild/linux-s390x': 0.16.7 - '@esbuild/linux-x64': 0.16.7 - '@esbuild/netbsd-x64': 0.16.7 - '@esbuild/openbsd-x64': 0.16.7 - '@esbuild/sunos-x64': 0.16.7 - '@esbuild/win32-arm64': 0.16.7 - '@esbuild/win32-ia32': 0.16.7 - '@esbuild/win32-x64': 0.16.7 - dev: true - /esbuild/0.17.0: resolution: {integrity: sha512-4yGk3rD95iS/wGzrx0Ji5czZcx1j2wvfF1iAJaX2FIYLB6sU6wYkDeplpZHzfwQw2yXGXsAoxmO6LnMQkl04Kg==} engines: {node: '>=12'} @@ -6377,7 +6211,7 @@ packages: htmlparser2: 8.0.1 dev: true - /eslint-plugin-jest/27.1.5_5rcd23qw3h5vuffwo2owxb3hw4: + /eslint-plugin-jest/27.1.5_i5clxtuiaceouxhg5syqkw5wwi: resolution: {integrity: sha512-CK2dekZ5VBdzsOSOH5Fc1rwC+cWXjkcyrmf1RV714nDUDKu+o73TTJiDxpbILG8PtPPpAAl3ywzh5QA7Ft0mjA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: @@ -6390,8 +6224,8 @@ packages: jest: optional: true dependencies: - '@typescript-eslint/eslint-plugin': 5.48.2_iljmjqxcygjq3saipl7gerxpvi - '@typescript-eslint/utils': 5.42.1_yygwinqv3a2io74xmwofqb7uka + '@typescript-eslint/eslint-plugin': 5.48.2_azmbqzqvrlvblbdtiwxwvyvjjy + '@typescript-eslint/utils': 5.42.1_et5x32uxl7z5ldub3ye5rhlyqm eslint: 8.32.0 jest: 29.3.1_odkjkoia5xunhxkdrka32ib6vi transitivePeerDependencies: @@ -6953,7 +6787,7 @@ packages: resolution: {integrity: sha512-XGozTsMPYkm+6b5QL3Z9wQcJjNYxp0CYn3U1gO7dwD6PAqU1SVWZxI9CCg3z+ml3YfqdPnrBehaBrnH2AGKbNA==} dev: true - /follow-redirects/1.15.2: + /follow-redirects/1.15.2_debug@4.3.2: resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} engines: {node: '>=4.0'} peerDependencies: @@ -6961,6 +6795,20 @@ packages: peerDependenciesMeta: debug: optional: true + dependencies: + debug: 4.3.2 + dev: true + + /follow-redirects/1.15.2_debug@4.3.4: + resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + dependencies: + debug: 4.3.4 dev: true /foreground-child/2.0.0: @@ -7500,7 +7348,7 @@ packages: engines: {node: '>=8.0.0'} dependencies: eventemitter3: 4.0.7 - follow-redirects: 1.15.2 + follow-redirects: 1.15.2_debug@4.3.2 requires-port: 1.0.0 transitivePeerDependencies: - debug @@ -7644,7 +7492,6 @@ packages: /internmap/2.0.3: resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} engines: {node: '>=12'} - dev: false /interpret/2.2.0: resolution: {integrity: sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==} @@ -8017,7 +7864,7 @@ packages: pretty-format: 29.3.1 slash: 3.0.0 strip-json-comments: 3.1.1 - ts-node: 10.9.1_cbe7ovvae6zqfnmtgctpgpys54 + ts-node: 10.9.1_w6ufic3jqylcjznzspnj4wjqfe transitivePeerDependencies: - supports-color dev: true @@ -8394,6 +8241,16 @@ packages: '@sideway/pinpoint': 2.0.0 dev: true + /joi/17.7.1: + resolution: {integrity: sha512-teoLhIvWE298R6AeJywcjR4sX2hHjB3/xJX4qPjg+gTg+c0mzUDsziYlqPmLomq9gVsfaMcgPaGc7VxtD/9StA==} + dependencies: + '@hapi/hoek': 9.3.0 + '@hapi/topo': 5.1.0 + '@sideway/address': 4.1.4 + '@sideway/formula': 3.0.1 + '@sideway/pinpoint': 2.0.0 + dev: true + /jpeg-js/0.4.4: resolution: {integrity: sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==} dev: true @@ -8591,7 +8448,6 @@ packages: /khroma/2.0.0: resolution: {integrity: sha512-2J8rDNlQWbtiNYThZRvmMv5yt44ZakX+Tz5ZIp/mN1pt4snn+m030Va5Z4v8xA0cQFDXBwO/8i42xL4QPsVk3g==} - dev: false /kind-of/6.0.3: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} @@ -9443,6 +9299,10 @@ packages: resolution: {integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==} dev: true + /minimist/1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + dev: true + /mkdirp/0.5.6: resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} hasBin: true @@ -9459,9 +9319,8 @@ packages: ufo: 1.0.1 dev: true - /moment/2.29.4: - resolution: {integrity: sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==} - dev: false + /moment-mini/2.29.4: + resolution: {integrity: sha512-uhXpYwHFeiTbY9KSgPPRoo1nt8OxNVdMVoTBYHfSEKeRkIkwGpO+gERmhuhBtzfaeOyTkykSrm2+noJBgqt3Hg==} /mri/1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} @@ -9564,7 +9423,6 @@ packages: /non-layered-tidy-tree-layout/2.0.2: resolution: {integrity: sha512-gkXMxRzUH+PB0ax9dUN0yYF0S25BqeAYqhgMaLUFmpXLEk7Fcu8f4emJuOAY0V8kjDICxROIKsTAKsV/v355xw==} - dev: false /normalize-package-data/2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} @@ -9624,6 +9482,11 @@ packages: resolution: {integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==} dev: true + /object-assign/4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + dev: true + /object-inspect/1.12.2: resolution: {integrity: sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==} dev: true @@ -10568,7 +10431,6 @@ packages: /robust-predicates/3.0.1: resolution: {integrity: sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g==} - dev: false /rollup-plugin-visualizer/5.8.3: resolution: {integrity: sha512-QGJk4Bqe4AOat5AjipOh8esZH1nck5X2KFpf4VytUdSUuuuSwvIQZjMGgjcxe/zXexltqaXp5Vx1V3LmnQH15Q==} @@ -10601,14 +10463,6 @@ packages: fsevents: 2.3.2 dev: true - /rollup/3.7.4: - resolution: {integrity: sha512-jN9rx3k5pfg9H9al0r0y1EYKSeiRANZRYX32SuNXAnKzh6cVyf4LZVto1KAuDnbHT03E1CpsgqDKaqQ8FZtgxw==} - engines: {node: '>=14.18.0', npm: '>=8.0.0'} - hasBin: true - optionalDependencies: - fsevents: 2.3.2 - dev: true - /run-parallel/1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} dependencies: @@ -10617,7 +10471,6 @@ packages: /rw/1.3.3: resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} - dev: false /rxjs/7.5.6: resolution: {integrity: sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw==} @@ -10625,6 +10478,12 @@ packages: tslib: 2.4.0 dev: true + /rxjs/7.8.0: + resolution: {integrity: sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==} + dependencies: + tslib: 2.4.0 + dev: true + /sade/1.8.1: resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} engines: {node: '>=6'} @@ -11093,6 +10952,23 @@ packages: - supports-color dev: true + /start-server-and-test/1.15.4: + resolution: {integrity: sha512-ucQtp5+UCr0m4aHlY+aEV2JSYNTiMZKdSKK/bsIr6AlmwAWDYDnV7uGlWWEtWa7T4XvRI5cPYcPcQgeLqpz+Tg==} + engines: {node: '>=6'} + hasBin: true + dependencies: + arg: 5.0.2 + bluebird: 3.7.2 + check-more-types: 2.24.0 + debug: 4.3.4 + execa: 5.1.1 + lazy-ass: 1.6.0 + ps-tree: 1.2.0 + wait-on: 7.0.1_debug@4.3.4 + transitivePeerDependencies: + - supports-color + dev: true + /statuses/1.5.0: resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} engines: {node: '>= 0.6'} @@ -11228,7 +11104,6 @@ packages: /stylis/4.1.2: resolution: {integrity: sha512-Nn2CCrG2ZaFziDxaZPN43CXqn+j7tcdjPFCkRBkFue8QYXC2HdEwnw5TCBo4yQZ2WxKYeSi0fdoOrtEqgDrXbA==} - dev: false /supports-color/2.0.0: resolution: {integrity: sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==} @@ -11453,7 +11328,7 @@ packages: engines: {node: '>=6.10'} dev: false - /ts-node/10.9.1_cbe7ovvae6zqfnmtgctpgpys54: + /ts-node/10.9.1_w6ufic3jqylcjznzspnj4wjqfe: resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} hasBin: true peerDependencies: @@ -11479,12 +11354,12 @@ packages: create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 4.8.4 + typescript: 4.9.5 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 dev: true - /ts-node/10.9.1_sqjhzn5m3vxyw66a2xhtc43hby: + /ts-node/10.9.1_yxpazyh7n5pql7jdaglasgwqki: resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} hasBin: true peerDependencies: @@ -11510,7 +11385,7 @@ packages: create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 4.8.4 + typescript: 4.9.5 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 dev: true @@ -11533,6 +11408,16 @@ packages: typescript: 4.8.4 dev: true + /tsutils/3.21.0_typescript@4.9.5: + resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} + engines: {node: '>= 6'} + peerDependencies: + typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' + dependencies: + tslib: 1.14.1 + typescript: 4.9.5 + dev: true + /tunnel-agent/0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} dependencies: @@ -11635,6 +11520,12 @@ packages: hasBin: true dev: true + /typescript/4.9.5: + resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} + engines: {node: '>=4.2.0'} + hasBin: true + dev: true + /uc.micro/1.0.6: resolution: {integrity: sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==} dev: true @@ -11781,7 +11672,6 @@ packages: /uuid/9.0.0: resolution: {integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==} hasBin: true - dev: false /uvu/0.5.6: resolution: {integrity: sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==} @@ -11856,7 +11746,7 @@ packages: picocolors: 1.0.0 source-map: 0.6.1 source-map-support: 0.5.21 - vite: 4.0.1_@types+node@18.11.9 + vite: 4.1.1_@types+node@18.11.9 transitivePeerDependencies: - '@types/node' - less @@ -11867,38 +11757,27 @@ packages: - terser dev: true - /vite/4.0.1_@types+node@18.11.9: - resolution: {integrity: sha512-kZQPzbDau35iWOhy3CpkrRC7It+HIHtulAzBhMqzGHKRf/4+vmh8rPDDdv98SWQrFWo6//3ozwsRmwQIPZsK9g==} - engines: {node: ^14.18.0 || >=16.0.0} + /vite-node/0.28.5_@types+node@18.11.9: + resolution: {integrity: sha512-LmXb9saMGlrMZbXTvOveJKwMTBTNUH66c8rJnQ0ZPNX+myPEol64+szRzXtV5ORb0Hb/91yq+/D3oERoyAt6LA==} + engines: {node: '>=v14.16.0'} hasBin: true - peerDependencies: - '@types/node': '>= 14' - less: '*' - sass: '*' - stylus: '*' - sugarss: '*' - terser: ^5.4.0 - peerDependenciesMeta: - '@types/node': - optional: true - less: - optional: true - sass: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true dependencies: - '@types/node': 18.11.9 - esbuild: 0.16.7 - postcss: 8.4.20 - resolve: 1.22.1 - rollup: 3.7.4 - optionalDependencies: - fsevents: 2.3.2 + cac: 6.7.14 + debug: 4.3.4 + mlly: 1.1.0 + pathe: 1.1.0 + picocolors: 1.0.0 + source-map: 0.6.1 + source-map-support: 0.5.21 + vite: 4.1.1_@types+node@18.11.9 + transitivePeerDependencies: + - '@types/node' + - less + - sass + - stylus + - sugarss + - supports-color + - terser dev: true /vite/4.1.1: @@ -11934,6 +11813,40 @@ packages: fsevents: 2.3.2 dev: true + /vite/4.1.1_@types+node@18.11.9: + resolution: {integrity: sha512-LM9WWea8vsxhr782r9ntg+bhSFS06FJgCvvB0+8hf8UWtvaiDagKYWXndjfX6kGl74keHJUcpzrQliDXZlF5yg==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + peerDependencies: + '@types/node': '>= 14' + less: '*' + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + '@types/node': 18.11.9 + esbuild: 0.16.17 + postcss: 8.4.21 + resolve: 1.22.1 + rollup: 3.15.0 + optionalDependencies: + fsevents: 2.3.2 + dev: true + /vitepress-plugin-search/1.0.4-alpha.19_g67lr3vgasogkevpbew55lljzq: resolution: {integrity: sha512-WFOPn5dStyMINd+rVjNxbEmGa7U+qGHLxLnda56EG+ATil1i0yOauGhJEh5LPMvuCUVIA9tInJnFXklOBb39dA==} engines: {node: ^14.13.1 || ^16.7.0 || >=18} @@ -12022,7 +11935,7 @@ packages: tinybench: 2.3.1 tinypool: 0.3.1 tinyspy: 1.0.2 - vite: 4.0.1_@types+node@18.11.9 + vite: 4.1.1_@types+node@18.11.9 vite-node: 0.28.4_@types+node@18.11.9 why-is-node-running: 2.2.2 transitivePeerDependencies: @@ -12034,6 +11947,63 @@ packages: - terser dev: true + /vitest/0.28.5_vun5xzxu3tkrssf3erdbijyyki: + resolution: {integrity: sha512-pyCQ+wcAOX7mKMcBNkzDwEHRGqQvHUl0XnoHR+3Pb1hytAHISgSxv9h0gUiSiYtISXUU3rMrKiKzFYDrI6ZIHA==} + engines: {node: '>=v14.16.0'} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@vitest/browser': '*' + '@vitest/ui': '*' + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + dependencies: + '@types/chai': 4.3.4 + '@types/chai-subset': 1.3.3 + '@types/node': 18.11.9 + '@vitest/expect': 0.28.5 + '@vitest/runner': 0.28.5 + '@vitest/spy': 0.28.5 + '@vitest/ui': 0.28.4 + '@vitest/utils': 0.28.5 + acorn: 8.8.1 + acorn-walk: 8.2.0 + cac: 6.7.14 + chai: 4.3.7 + debug: 4.3.4 + jsdom: 21.1.0 + local-pkg: 0.4.2 + pathe: 1.1.0 + picocolors: 1.0.0 + source-map: 0.6.1 + std-env: 3.3.2 + strip-literal: 1.0.0 + tinybench: 2.3.1 + tinypool: 0.3.1 + tinyspy: 1.0.2 + vite: 4.1.1_@types+node@18.11.9 + vite-node: 0.28.5_@types+node@18.11.9 + why-is-node-running: 2.2.2 + transitivePeerDependencies: + - less + - sass + - stylus + - sugarss + - supports-color + - terser + dev: true + /vm2/3.9.11: resolution: {integrity: sha512-PFG8iJRSjvvBdisowQ7iVF580DXb1uCIiGaXgm7tynMR1uTBlv7UJlB1zdv5KJ+Tmq1f0Upnj3fayoEOPpCBKg==} engines: {node: '>=6.0'} @@ -12145,6 +12115,20 @@ packages: - debug dev: true + /wait-on/7.0.1_debug@4.3.4: + resolution: {integrity: sha512-9AnJE9qTjRQOlTZIldAaf/da2eW0eSRSgcqq85mXQja/DW3MriHxkpODDSUEg+Gri/rKEcXUZHe+cevvYItaog==} + engines: {node: '>=12.0.0'} + hasBin: true + dependencies: + axios: 0.27.2_debug@4.3.4 + joi: 17.7.1 + lodash: 4.17.21 + minimist: 1.2.8 + rxjs: 7.8.0 + transitivePeerDependencies: + - debug + dev: true + /walker/1.0.8: resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} dependencies: diff --git a/tests/webpack/src/index.js b/tests/webpack/src/index.js index 092972694..51738aa62 100644 --- a/tests/webpack/src/index.js +++ b/tests/webpack/src/index.js @@ -4,7 +4,7 @@ const mermaid = require('mermaid'); import mindmap from '@mermaid-js/mermaid-mindmap'; const render = async (graph) => { - const svg = await mermaid.renderAsync('dummy', graph); + const svg = await mermaid.render('dummy', graph); console.log(svg); document.getElementById('graphDiv').innerHTML = svg; }; diff --git a/tsconfig.json b/tsconfig.json index fe107f205..c66d62784 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -76,7 +76,7 @@ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */, - // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "preserveSymlinks": true /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */, "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, /* Type Checking */