diff --git a/.eslintrc.json b/.eslintrc.json index 02753280c..b8053795e 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -52,24 +52,25 @@ }, "overrides": [ { - "files": "./**/*.html", - "rules": { - "no-undef": "off", - "jsdoc/require-jsdoc": "off" - } - }, - { - "files": ["./cypress/**", "./demos/**"], + "files": ["cypress/**", "demos/**"], "rules": { "no-console": "off" } }, { - "files": ["./**/*.spec.{ts,js}", "./cypress/**", "./demos/**", "./**/docs/**"], + "files": ["*.spec.{ts,js}", "cypress/**", "demos/**", "**/docs/**"], "rules": { "jsdoc/require-jsdoc": "off", "@typescript-eslint/no-unused-vars": "off" } + }, + { + "files": ["*.html", "*.md", "**/*.md/*"], + "rules": { + "no-var": "error", + "no-undef": "off", + "@typescript-eslint/no-unused-vars": "off" + } } ] } diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a8bafc91a..2a70b5901 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [16.x] + node-version: [18.x] steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 1e08a5c16..a7ad03a7a 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -16,9 +16,9 @@ jobs: name: 'Docs: Spellcheck' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 name: Check out the code - - uses: actions/setup-node@v1 + - uses: actions/setup-node@v3 name: Setup node with: node-version: '16' diff --git a/.github/workflows/e2e-applitools.yml b/.github/workflows/e2e-applitools.yml index 5c515b433..da6dbdb1f 100644 --- a/.github/workflows/e2e-applitools.yml +++ b/.github/workflows/e2e-applitools.yml @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [16.x] + node-version: [18.x] steps: - if: ${{ ! env.USE_APPLI }} name: Warn if not using Applitools diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 8925a828d..55e06f46d 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -11,7 +11,7 @@ jobs: strategy: fail-fast: false matrix: - node-version: [16.x] + node-version: [18.x] containers: [1, 2, 3, 4] steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index dd2f7aa3b..9adbb177c 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [16.x] + node-version: [18.x] steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/release-preview-publish.yml b/.github/workflows/release-preview-publish.yml index ed55c847d..2b2ff559b 100644 --- a/.github/workflows/release-preview-publish.yml +++ b/.github/workflows/release-preview-publish.yml @@ -13,7 +13,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v3 with: - node-version: 16.x + node-version: 18.x - name: Install Yarn run: npm i yarn --global diff --git a/.github/workflows/release-publish.yml b/.github/workflows/release-publish.yml index 9cf49e282..6f0806de1 100644 --- a/.github/workflows/release-publish.yml +++ b/.github/workflows/release-publish.yml @@ -14,7 +14,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v3 with: - node-version: 16.x + node-version: 18.x - name: Install Yarn run: npm i yarn --global diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fd058406d..6397e5305 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [16.x] + node-version: [18.x] steps: - uses: actions/checkout@v3 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2234d5148..ed436a8d1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,12 +6,23 @@ So you want to help? That's great! Here are a few things to know to get you started on the right path. +Below link will help you making a copy of the repository in your local system. + +https://docs.github.com/en/get-started/quickstart/fork-a-repo + +## Requirements + +- [volta](https://volta.sh/) to manage node versions. +- [Node.js](https://nodejs.org/en/). `volta install node` +- [pnpm](https://pnpm.io/) package manager. `volta install pnpm` + ## Development Installation ```bash git clone git@github.com:mermaid-js/mermaid.git cd mermaid -pnpm install +# npx is required for first install as volta support for pnpm is not added yet. +npx pnpm install pnpm test ``` diff --git a/README.md b/README.md index b30d8d438..90ae1ad4c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ -# mermaid [![Build Status](https://travis-ci.org/mermaid-js/mermaid.svg?branch=master)](https://travis-ci.org/mermaid-js/mermaid) [![NPM](https://img.shields.io/npm/v/mermaid)](https://www.npmjs.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) [![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) +# mermaid -# Whoa, whats going on here? +[![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) [![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_) + +# Whoa, what's going on here? We are transforming the Mermaid repository to a so called mono-repo. This is a part of the effort to decouple the diagrams from the core of mermaid. This will: diff --git a/README.zh-CN.md b/README.zh-CN.md index c00c539e0..fcaa1f523 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -1,4 +1,6 @@ -# mermaid [![Build Status](https://travis-ci.org/mermaid-js/mermaid.svg?branch=master)](https://travis-ci.org/mermaid-js/mermaid) [![NPM](https://img.shields.io/npm/v/mermaid)](https://www.npmjs.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) [![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) +# 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) [![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) | 简体中文 diff --git a/__mocks__/dagre-d3.ts b/__mocks__/dagre-d3.ts index a1a677591..bf6d341dc 100644 --- a/__mocks__/dagre-d3.ts +++ b/__mocks__/dagre-d3.ts @@ -1,3 +1 @@ -import { vi } from 'vitest'; - -// export const render = vi.fn(); +// DO NOT delete this file. It is used by vitest to mock the dagre-d3 module. diff --git a/cypress/platform/sidv.html b/cypress/platform/sidv.html new file mode 100644 index 000000000..c9bf56b7d --- /dev/null +++ b/cypress/platform/sidv.html @@ -0,0 +1,14 @@ + + +
+    none
+    hello world
+    
+ + + + diff --git a/cypress/platform/xss10.html b/cypress/platform/xss10.html index 6a027f514..b39728c84 100644 --- a/cypress/platform/xss10.html +++ b/cypress/platform/xss10.html @@ -93,7 +93,7 @@ throw new Error('XSS Succeeded'); } - var diagram = 'classDiagram\n'; + let diagram = 'classDiagram\n'; diagram += 'class Square~" <--> "" C2: Cool label`; // // var diagram = "stateDiagram-v2\n"; diff --git a/cypress/platform/xss19.html b/cypress/platform/xss19.html index 590a195aa..ca747b39e 100644 --- a/cypress/platform/xss19.html +++ b/cypress/platform/xss19.html @@ -93,7 +93,7 @@ throw new Error('XSS Succeeded'); } - var diagram = `classDiagram + let diagram = `classDiagram class Shape{ << { + let cnt = 0; + let a; + const handler = setInterval(() => { cnt++; a = {}; if (typeof a.polluted !== 'undefined') { diff --git a/cypress/platform/xss20.html b/cypress/platform/xss20.html index 7b8aa9f85..9efd17215 100644 --- a/cypress/platform/xss20.html +++ b/cypress/platform/xss20.html @@ -96,7 +96,7 @@ // var diagram = ` graph TD // A --> B["<a href='javasc`; // diagram += `ript#colon;xssAttack()'>AAA</a>"]`; - var diagram = ` graph TD + let diagram = ` graph TD A --> B["AAA"]`; // diagram += '//via.placeholder.com/64\' width=64 />"]'; diff --git a/cypress/platform/xss21.html b/cypress/platform/xss21.html index e65a357ee..fed0e4289 100644 --- a/cypress/platform/xss21.html +++ b/cypress/platform/xss21.html @@ -96,7 +96,7 @@ // var diagram = ` graph TD // A --> B["<a href='javasc`; // diagram += `ript#colon;xssAttack()'>AAA</a>"]`; - var diagram = ` graph TD + let diagram = ` graph TD A --> B["AAA"]`; // diagram += '//via.placeholder.com/64\' width=64 />"]'; diff --git a/cypress/platform/xss3.html b/cypress/platform/xss3.html index b72e8743c..78fabc4aa 100644 --- a/cypress/platform/xss3.html +++ b/cypress/platform/xss3.html @@ -42,9 +42,9 @@ startOnLoad: true, useMaxWidth: true, }); - var cnt = 0; - var a; - var handler = setInterval(() => { + let cnt = 0; + let a; + const handler = setInterval(() => { cnt++; a = {}; if (typeof a.polluted !== 'undefined') { diff --git a/cypress/platform/xss4.html b/cypress/platform/xss4.html index b6e36edcd..924a65e08 100644 --- a/cypress/platform/xss4.html +++ b/cypress/platform/xss4.html @@ -85,7 +85,7 @@ alert('It worked'); } - var diagram = '%%{init: {"flowchart": {"htmlLabels": "true"}} }%%\n'; + let diagram = '%%{init: {"flowchart": {"htmlLabels": "true"}} }%%\n'; diagram += 'flowchart\n'; diagram += 'A[" function testClick(nodeId) { console.log('clicked', nodeId); - var originalBgColor = document.querySelector('body').style.backgroundColor; + let originalBgColor = document.querySelector('body').style.backgroundColor; document.querySelector('body').style.backgroundColor = 'yellow'; setTimeout(function () { document.querySelector('body').style.backgroundColor = originalBgColor; diff --git a/demos/dataflowchart.html b/demos/dataflowchart.html index dc7fe05af..d49118ae0 100644 --- a/demos/dataflowchart.html +++ b/demos/dataflowchart.html @@ -46,7 +46,7 @@ - ``` -**Doing so will command the mermaid parser to look for the `
` tags with `class="mermaid"`. From these tags mermaid will try to read the diagram/chart definitions and render them into SVG charts.** +**Doing so will command the mermaid parser to look for the `
` or `
` tags with `class="mermaid"`. From these tags mermaid will try to read the diagram/chart definitions and render them into SVG charts.**
 
 **Examples can be found at** [Other examples](/examples)
 
diff --git a/docs/Setup.md b/docs/Setup.md
index 952dc5c5d..fd978e928 100644
--- a/docs/Setup.md
+++ b/docs/Setup.md
@@ -1561,7 +1561,7 @@ Returns **void**
 
 ```html
 
@@ -653,10 +653,10 @@ Beginner's tip—a full example using interactive links in an HTML page:
   
@@ -727,10 +727,10 @@ Beginner's tip—here's a full example of using interactive links in HTML: @@ -771,10 +771,10 @@ Beginner's tip—a full example using interactive links in a html context: - @@ -50,17 +48,21 @@
+ - -``` - -**b. The embedded mermaid diagram definition inside a `
`:**
+**a. The embedded mermaid diagram definition inside a `
`:**
 
 ```html
 
@@ -107,13 +97,14 @@ c. The `mermaid.initialize()` call, which dictates the appearance of diagrams an
 
 **Notes**: Every Mermaid chart/graph/diagram definition, should have separate `
` tags.
 
-**c. The `mermaid.initialize()` call.**
+**b. The import of mermaid and the `mermaid.initialize()` call.**
 
 `mermaid.initialize()` call takes all the definitions contained in all the `
` tags that it finds in the html body and renders them into diagrams. Example:
 
 ```html
 
-  
 
@@ -135,11 +126,6 @@ Rendering in Mermaid is initialized by `mermaid.initialize()` call. You can plac
 ```html
 
   
-    
-    
-
     Here is one mermaid diagram:
     
             graph TD 
@@ -156,6 +142,11 @@ Rendering in Mermaid is initialized by `mermaid.initialize()` call. You can plac
             B -->|tcp_456| C[Server1] 
             B -->|tcp_456| D[Server2]
     
+ + ``` @@ -181,8 +172,8 @@ In this example mermaid.js is referenced in `src` as a separate JavaScript file, B --> C[Server1] B --> D[Server2]
- - @@ -206,4 +197,4 @@ In this example mermaid.js is referenced in `src` as a separate JavaScript file, **Comments from Knut Sveidqvist, creator of mermaid:** -- In early versions of mermaid, the ` - ``` - -2. The `mermaidAPI` call, in a separate `script` tag. Example: - - ```html - - ``` - -3. A graph definition, inside `
` tags labeled `class=mermaid`. Example: +- A graph definition, inside `
` tags labeled `class=mermaid`. Example:
 
 ```html
 
@@ -66,8 +52,18 @@ The easiest way to integrate mermaid on a web page requires three elements:
 
``` -**Following these directions, mermaid starts at page load and (when the page has loaded) it will -locate the graph definitions inside the `div` tags with `class="mermaid"` and return diagrams in SVG form, following given definitions.** +- Inclusion of the mermaid address in the html page body using a `script` tag as an ESM import, and the `mermaidAPI` call. + +Example: + +```html + +``` + +**Following these directions, mermaid starts at page load and (when the page has loaded) it will locate the graph definitions inside the `pre` tags with `class="mermaid"` and return diagrams in SVG form, following given definitions.** ## Simple full example: @@ -84,8 +80,8 @@ locate the graph definitions inside the `div` tags with `class="mermaid"` and re B-->C[fa:fa-ban forbidden] B-->D(fa:fa-spinner);
- - @@ -204,18 +200,17 @@ fetch the graph definition from the site (perhaps from a textarea), render it an The example below show an outline of how this could be used. The example just logs the resulting SVG to the JavaScript console. ```html - - - ``` @@ -339,7 +334,7 @@ on what kind of integration you use. ```html ``` diff --git a/package.json b/package.json index 4ad882420..25d614f95 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,8 @@ "e2e": "start-server-and-test dev http://localhost:9000/ cypress", "ci": "vitest run", "test": "pnpm lint && vitest run", - "test:watch": "vitest --coverage --watch", + "test:watch": "vitest --watch", + "test:coverage": "vitest --coverage", "prepublishOnly": "pnpm build && pnpm test", "prepare": "concurrently \"husky install\" \"pnpm build\"", "pre-commit": "lint-staged" @@ -96,6 +97,7 @@ "@types/express": "^4.17.14", "@types/jsdom": "^20.0.0", "@types/lodash": "^4.14.186", + "@types/mdast": "^3.0.10", "@types/prettier": "^2.7.1", "@types/stylis": "^4.0.2", "@typescript-eslint/eslint-plugin": "^5.39.0", @@ -150,5 +152,8 @@ "sideEffects": [ "**/*.css", "**/*.scss" - ] + ], + "volta": { + "node": "18.5.0" + } } diff --git a/packages/mermaid/src/Diagram.ts b/packages/mermaid/src/Diagram.ts index 9bdc92079..0aa741994 100644 --- a/packages/mermaid/src/Diagram.ts +++ b/packages/mermaid/src/Diagram.ts @@ -8,11 +8,18 @@ export class Diagram { parser; renderer; db; + private detectTypeFailed = false; // eslint-disable-next-line @typescript-eslint/ban-types constructor(public txt: string, parseError?: Function) { const cnf = configApi.getConfig(); this.txt = txt; - this.type = detectType(txt, cnf); + try { + this.type = detectType(txt, cnf); + } catch (e) { + this.handleError(e, parseError); + this.type = 'error'; + this.detectTypeFailed = true; + } const diagram = getDiagram(this.type); log.debug('Type ' + this.type); // Setup diagram @@ -32,31 +39,39 @@ export class Diagram { // eslint-disable-next-line @typescript-eslint/ban-types parse(text: string, parseError?: Function): boolean { + if (this.detectTypeFailed) { + return false; + } try { text = text + '\n'; this.db.clear(); this.parser.parse(text); return true; } catch (error) { - // Is this the correct way to access mermiad's parseError() - // method ? (or global.mermaid.parseError()) ? - if (parseError) { - if (isDetailedError(error)) { - // handle case where error string and hash were - // wrapped in object like`const error = { str, hash };` - parseError(error.str, error.hash); - } else { - // assume it is just error string and pass it on - parseError(error); - } - } else { - // No mermaid.parseError() handler defined, so re-throw it - throw error; - } + this.handleError(error, parseError); } return false; } + // eslint-disable-next-line @typescript-eslint/ban-types + handleError(error: unknown, parseError?: Function) { + // Is this the correct way to access mermiad's parseError() + // method ? (or global.mermaid.parseError()) ? + if (parseError) { + if (isDetailedError(error)) { + // handle case where error string and hash were + // wrapped in object like`const error = { str, hash };` + parseError(error.str, error.hash); + } else { + // assume it is just error string and pass it on + parseError(error); + } + } else { + // No mermaid.parseError() handler defined, so re-throw it + throw error; + } + } + getParser() { return this.parser; } @@ -66,10 +81,8 @@ export class Diagram { } } -export default Diagram; - // eslint-disable-next-line @typescript-eslint/ban-types -export const getDiagramFromText = async (txt: string, parseError?: Function) => { +export const getDiagramFromText = async (txt: string, parseError?: Function): Promise => { const type = detectType(txt, configApi.getConfig()); try { // Trying to find the diagram @@ -79,24 +92,14 @@ export const getDiagramFromText = async (txt: string, parseError?: Function) => if (!loader) { throw new Error(`Diagram ${type} not found.`); } - // Diagram not avaiable, loading it - // const path = getPathForDiagram(type); - const { diagram } = await loader(); // eslint-disable-line @typescript-eslint/no-explicit-any - registerDiagram( - type, - { - db: diagram.db, - renderer: diagram.renderer, - parser: diagram.parser, - styles: diagram.styles, - }, - diagram.injectUtils - ); - // await loadDiagram('./packages/mermaid-mindmap/dist/mermaid-mindmap.js'); - // await loadDiagram(path + 'mermaid-' + type + '.js'); + // 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 } // If either of the above worked, we have the diagram // logic and can continue return new Diagram(txt, parseError); }; + +export default Diagram; diff --git a/packages/mermaid/src/__mocks__/mermaidAPI.ts b/packages/mermaid/src/__mocks__/mermaidAPI.ts index f15db139f..08c5b7eea 100644 --- a/packages/mermaid/src/__mocks__/mermaidAPI.ts +++ b/packages/mermaid/src/__mocks__/mermaidAPI.ts @@ -11,17 +11,13 @@ import Diagram 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. -let hasLoadedDiagrams = false; /** * @param text * @param parseError */ // eslint-disable-next-line @typescript-eslint/ban-types function parse(text: string, parseError?: Function): boolean { - if (!hasLoadedDiagrams) { - addDiagrams(); - hasLoadedDiagrams = true; - } + addDiagrams(); const diagram = new Diagram(text, parseError); return diagram.parse(text, parseError); } diff --git a/packages/mermaid/src/config.type.ts b/packages/mermaid/src/config.type.ts index 1059d5709..2343bdd34 100644 --- a/packages/mermaid/src/config.type.ts +++ b/packages/mermaid/src/config.type.ts @@ -3,7 +3,7 @@ import DOMPurify from 'dompurify'; export interface MermaidConfig { - lazyLoadedDiagrams?: any; + lazyLoadedDiagrams?: string[]; theme?: string; themeVariables?: any; themeCSS?: string; diff --git a/packages/mermaid/src/diagram-api/detectType.ts b/packages/mermaid/src/diagram-api/detectType.ts index 340cbfbae..9536fded2 100644 --- a/packages/mermaid/src/diagram-api/detectType.ts +++ b/packages/mermaid/src/diagram-api/detectType.ts @@ -1,8 +1,7 @@ import { MermaidConfig } from '../config.type'; +import { log } from '../logger'; +import { DetectorRecord, DiagramDetector, DiagramLoader } from './types'; -export type DiagramDetector = (text: string, config?: MermaidConfig) => boolean; -export type DiagramLoader = (() => any) | null; -export type DetectorRecord = { detector: DiagramDetector; loader: DiagramLoader }; const directive = /[%]{2}[{]\s*(?:(?:(\w+)\s*:|(\w+))\s*(?:(?:(\w+))|((?:(?![}][%]{2}).|\r?\n)*))?\s*)(?:[}][%]{2})?/gi; const anyComment = /\s*%%.*\n/gm; @@ -34,26 +33,22 @@ const detectors: Record = {}; */ export const detectType = function (text: string, config?: MermaidConfig): string { text = text.replace(directive, '').replace(anyComment, '\n'); - - // console.log(detectors); - for (const [key, { detector }] of Object.entries(detectors)) { const diagram = detector(text, config); if (diagram) { return key; } } - // TODO: #3391 - // throw new Error(`No diagram type detected for text: ${text}`); - return 'flowchart'; + + throw new Error(`No diagram type detected for text: ${text}`); }; -export const addDetector = ( - key: string, - detector: DiagramDetector, - loader: DiagramLoader | null -) => { +export const addDetector = (key: string, detector: DiagramDetector, loader?: DiagramLoader) => { + if (detectors[key]) { + throw new Error(`Detector with key ${key} already exists`); + } detectors[key] = { detector, loader }; + log.debug(`Detector with key ${key} added${loader ? ' with loader' : ''}`); }; export const getDiagramLoader = (key: string) => detectors[key].loader; diff --git a/packages/mermaid/src/diagram-api/diagram-orchestration.ts b/packages/mermaid/src/diagram-api/diagram-orchestration.ts index 1693f4f51..a26edb303 100644 --- a/packages/mermaid/src/diagram-api/diagram-orchestration.ts +++ b/packages/mermaid/src/diagram-api/diagram-orchestration.ts @@ -1,16 +1,4 @@ -import { - registerDiagram, - registerDetector, - DiagramDefinition, - DiagramDetector, -} from './diagramAPI'; - -// // @ts-ignore: TODO Fix ts errors -// import mindmapParser from '../diagrams/mindmap/parser/mindmap'; -// import * as mindmapDb from '../diagrams/mindmap/mindmapDb'; -// import { mindmapDetector } from '../diagrams/mindmap/mindmapDetector'; -// import mindmapRenderer from '../diagrams/mindmap/mindmapRenderer'; -// import mindmapStyles from '../diagrams/mindmap/styles'; +import { registerDiagram } from './diagramAPI'; // @ts-ignore: TODO Fix ts errors import gitGraphParser from '../diagrams/git/parser/gitGraph'; @@ -106,17 +94,15 @@ import { setConfig } from '../config'; import errorRenderer from '../diagrams/error/errorRenderer'; import errorStyles from '../diagrams/error/styles'; -const registerDiagramAndDetector = ( - id: string, - diagram: DiagramDefinition, - detector: DiagramDetector -) => { - registerDiagram(id, diagram); - registerDetector(id, detector); -}; - +let hasLoadedDiagrams = false; export const addDiagrams = () => { - registerDiagramAndDetector( + if (hasLoadedDiagrams) { + return; + } + // This is added here to avoid race-conditions. + // We could optimize the loading logic somehow. + hasLoadedDiagrams = true; + registerDiagram( 'error', // Special diagram with error messages but setup as a regular diagram { @@ -140,7 +126,7 @@ export const addDiagrams = () => { (text) => text.toLowerCase().trim() === 'error' ); - registerDiagramAndDetector( + registerDiagram( 'c4', { parser: c4Parser, @@ -153,7 +139,7 @@ export const addDiagrams = () => { }, c4Detector ); - registerDiagramAndDetector( + registerDiagram( 'class', { parser: classParser, @@ -170,7 +156,7 @@ export const addDiagrams = () => { }, classDetector ); - registerDiagramAndDetector( + registerDiagram( 'classDiagram', { parser: classParser, @@ -187,7 +173,7 @@ export const addDiagrams = () => { }, classDetectorV2 ); - registerDiagramAndDetector( + registerDiagram( 'er', { parser: erParser, @@ -197,7 +183,7 @@ export const addDiagrams = () => { }, erDetector ); - registerDiagramAndDetector( + registerDiagram( 'gantt', { parser: ganttParser, @@ -207,7 +193,7 @@ export const addDiagrams = () => { }, ganttDetector ); - registerDiagramAndDetector( + registerDiagram( 'info', { parser: infoParser, @@ -217,7 +203,7 @@ export const addDiagrams = () => { }, infoDetector ); - registerDiagramAndDetector( + registerDiagram( 'pie', { parser: pieParser, @@ -227,7 +213,7 @@ export const addDiagrams = () => { }, pieDetector ); - registerDiagramAndDetector( + registerDiagram( 'requirement', { parser: requirementParser, @@ -237,7 +223,7 @@ export const addDiagrams = () => { }, requirementDetector ); - registerDiagramAndDetector( + registerDiagram( 'sequence', { parser: sequenceParser, @@ -260,7 +246,7 @@ export const addDiagrams = () => { }, sequenceDetector ); - registerDiagramAndDetector( + registerDiagram( 'state', { parser: stateParser, @@ -277,7 +263,7 @@ export const addDiagrams = () => { }, stateDetector ); - registerDiagramAndDetector( + registerDiagram( 'stateDiagram', { parser: stateParser, @@ -294,7 +280,7 @@ export const addDiagrams = () => { }, stateDetectorV2 ); - registerDiagramAndDetector( + registerDiagram( 'journey', { parser: journeyParser, @@ -309,7 +295,7 @@ export const addDiagrams = () => { journeyDetector ); - registerDiagramAndDetector( + registerDiagram( 'flowchart', { parser: flowParser, @@ -329,7 +315,7 @@ export const addDiagrams = () => { }, flowDetector ); - registerDiagramAndDetector( + registerDiagram( 'flowchart-v2', { parser: flowParser, @@ -350,14 +336,9 @@ export const addDiagrams = () => { }, flowDetectorV2 ); - registerDiagramAndDetector( + registerDiagram( 'gitGraph', { parser: gitGraphParser, db: gitGraphDb, renderer: gitGraphRenderer, styles: gitGraphStyles }, gitGraphDetector ); - // registerDiagram( - // 'mindmap', - // { parser: mindmapParser, db: mindmapDb, renderer: mindmapRenderer, styles: mindmapStyles }, - // mindmapDetector - // ); }; diff --git a/packages/mermaid/src/diagram-api/diagramAPI.spec.ts b/packages/mermaid/src/diagram-api/diagramAPI.spec.ts index 584a36fa3..ea546fbb6 100644 --- a/packages/mermaid/src/diagram-api/diagramAPI.spec.ts +++ b/packages/mermaid/src/diagram-api/diagramAPI.spec.ts @@ -1,6 +1,7 @@ -import { detectType, DiagramDetector } from './detectType'; -import { getDiagram, registerDiagram, registerDetector } from './diagramAPI'; +import { detectType } from './detectType'; +import { getDiagram, registerDiagram } from './diagramAPI'; import { addDiagrams } from './diagram-orchestration'; +import { DiagramDetector } from './types'; addDiagrams(); @@ -15,17 +16,22 @@ describe('DiagramAPI', () => { it('should handle diagram registrations', () => { expect(() => getDiagram('loki')).toThrow(); - expect(() => detectType('loki diagram')).not.toThrow(); // TODO: #3391 + expect(() => detectType('loki diagram')).toThrow( + 'No diagram type detected for text: loki diagram' + ); const detector: DiagramDetector = (str: string) => { return str.match('loki') !== null; }; - registerDetector('loki', detector); - registerDiagram('loki', { - db: {}, - parser: {}, - renderer: {}, - styles: {}, - }); + registerDiagram( + 'loki', + { + db: {}, + parser: {}, + renderer: {}, + styles: {}, + }, + detector + ); expect(getDiagram('loki')).not.toBeNull(); expect(detectType('loki diagram')).toBe('loki'); }); diff --git a/packages/mermaid/src/diagram-api/diagramAPI.ts b/packages/mermaid/src/diagram-api/diagramAPI.ts index 002619bbb..2bc8091ec 100644 --- a/packages/mermaid/src/diagram-api/diagramAPI.ts +++ b/packages/mermaid/src/diagram-api/diagramAPI.ts @@ -1,10 +1,10 @@ -import { addDetector, DiagramDetector as _DiagramDetector } from './detectType'; +import { addDetector } from './detectType'; import { log as _log, setLogLevel as _setLogLevel } from '../logger'; import { getConfig as _getConfig } from '../config'; import { sanitizeText as _sanitizeText } from '../diagrams/common/common'; -import { MermaidConfig } from '../config.type'; import { setupGraphViewbox as _setupGraphViewbox } from '../setupGraphViewbox'; import { addStylesForDiagram } from '../styles'; +import { DiagramDefinition, DiagramDetector } from './types'; /* Packaging and exposing resources for externa diagrams so that they can import @@ -13,41 +13,19 @@ import { addStylesForDiagram } from '../styles'; */ export const log = _log; export const setLogLevel = _setLogLevel; -export type DiagramDetector = _DiagramDetector; export const getConfig = _getConfig; export const sanitizeText = (text: string) => _sanitizeText(text, getConfig()); export const setupGraphViewbox = _setupGraphViewbox; -export interface InjectUtils { - _log: any; - _setLogLevel: any; - _getConfig: any; - _sanitizeText: any; - _setupGraphViewbox: any; -} - -export interface DiagramDefinition { - db: any; - renderer: any; - parser: any; - styles: any; - init?: (config: MermaidConfig) => void; - injectUtils?: (utils: InjectUtils) => void; -} - const diagrams: Record = {}; -const connectCallbacks: Record = {}; // TODO fix, eslint-disable-line @typescript-eslint/no-explicit-any export interface Detectors { [key: string]: DiagramDetector; } -export const registerDetector = (id: string, detector: DiagramDetector) => { - addDetector(id, detector, null); -}; - export const registerDiagram = ( id: string, diagram: DiagramDefinition, + detector?: DiagramDetector, callback?: ( _log: any, _setLogLevel: any, @@ -57,9 +35,12 @@ export const registerDiagram = ( ) => void ) => { if (diagrams[id]) { - log.warn(`Diagram ${id} already registered.`); + throw new Error(`Diagram ${id} already registered.`); } diagrams[id] = diagram; + if (detector) { + addDetector(id, detector); + } addStylesForDiagram(id, diagram.styles); if (typeof callback !== 'undefined') { callback(log, setLogLevel, getConfig, sanitizeText, setupGraphViewbox); @@ -72,19 +53,3 @@ export const getDiagram = (name: string): DiagramDefinition => { } throw new Error(`Diagram ${name} not found.`); }; - -/** - * - * @param sScriptSrc - */ -export const loadDiagram = (sScriptSrc: string) => - new Promise((resolve) => { - const oHead = document.getElementsByTagName('HEAD')[0]; - const oScript = document.createElement('script'); - oScript.type = 'text/javascript'; - oScript.src = sScriptSrc; - oHead.appendChild(oScript); - oScript.onload = () => { - resolve(true); - }; - }); diff --git a/packages/mermaid/src/diagram-api/text-wrap b/packages/mermaid/src/diagram-api/text-wrap deleted file mode 100644 index 173baecec..000000000 --- a/packages/mermaid/src/diagram-api/text-wrap +++ /dev/null @@ -1,227 +0,0 @@ -export const lineBreakRegex = //gi; - -/** - * Caches results of functions based on input - * - * @param {Function} fn Function to run - * @param {Function} resolver Function that resolves to an ID given arguments the `fn` takes - * @returns {Function} An optimized caching function - */ -const memoize = (fn, resolver) => { - let cache = {}; - return (...args) => { - let n = resolver ? resolver.apply(this, args) : args[0]; - if (n in cache) { - return cache[n]; - } else { - let result = fn(...args); - cache[n] = result; - return result; - } - }; -}; -/** - * This calculates the width of the given text, font size and family. - * - * @param {any} text - The text to calculate the width of - * @param {any} config - The config for fontSize, fontFamily, and fontWeight all impacting the resulting size - * @returns {any} - The width for the given text - */ -export const calculateTextWidth = function (text, config) { - config = Object.assign({ fontSize: 12, fontWeight: 400, fontFamily: 'Arial' }, config); - return calculateTextDimensions(text, config).width; -}; - -export const getTextObj = function () { - return { - x: 0, - y: 0, - fill: undefined, - anchor: 'start', - style: '#666', - width: 100, - height: 100, - textMargin: 0, - rx: 0, - ry: 0, - valign: undefined, - }; -}; - -/** - * Adds text to an element - * - * @param {SVGElement} elem Element to add text to - * @param {{ - * text: string; - * x: number; - * y: number; - * anchor: 'start' | 'middle' | 'end'; - * fontFamily: string; - * fontSize: string | number; - * fontWeight: string | number; - * fill: string; - * class: string | undefined; - * textMargin: number; - * }} textData - * @returns {SVGTextElement} Text element with given styling and content - */ -export const drawSimpleText = function (elem, textData) { - // Remove and ignore br:s - const nText = textData.text.replace(lineBreakRegex, ' '); - - const textElem = elem.append('text'); - textElem.attr('x', textData.x); - textElem.attr('y', textData.y); - textElem.style('text-anchor', textData.anchor); - textElem.style('font-family', textData.fontFamily); - textElem.style('font-size', textData.fontSize); - textElem.style('font-weight', textData.fontWeight); - textElem.attr('fill', textData.fill); - if (typeof textData.class !== 'undefined') { - textElem.attr('class', textData.class); - } - - const span = textElem.append('tspan'); - span.attr('x', textData.x + textData.textMargin * 2); - span.attr('fill', textData.fill); - span.text(nText); - - return textElem; -}; - -/** - * This calculates the dimensions of the given text, font size, font family, font weight, and margins. - * - * @param {any} text - The text to calculate the width of - * @param {any} config - The config for fontSize, fontFamily, fontWeight, and margin all impacting - * the resulting size - * @returns - The width for the given text - */ -export const calculateTextDimensions = memoize( - function (text, config) { - config = Object.assign({ fontSize: 12, fontWeight: 400, fontFamily: 'Arial' }, config); - const { fontSize, fontFamily, fontWeight } = config; - if (!text) { - return { width: 0, height: 0 }; - } - - // We can't really know if the user supplied font family will render on the user agent; - // thus, we'll take the max width between the user supplied font family, and a default - // of sans-serif. - const fontFamilies = ['sans-serif', fontFamily]; - const lines = text.split(common.lineBreakRegex); - let dims = []; - - const body = select('body'); - // We don't want to leak DOM elements - if a removal operation isn't available - // for any reason, do not continue. - if (!body.remove) { - return { width: 0, height: 0, lineHeight: 0 }; - } - - const g = body.append('svg'); - - for (let fontFamily of fontFamilies) { - let cheight = 0; - let dim = { width: 0, height: 0, lineHeight: 0 }; - for (let line of lines) { - const textObj = getTextObj(); - textObj.text = line; - const textElem = drawSimpleText(g, textObj) - .style('font-size', fontSize) - .style('font-weight', fontWeight) - .style('font-family', fontFamily); - - let bBox = (textElem._groups || textElem)[0][0].getBBox(); - dim.width = Math.round(Math.max(dim.width, bBox.width)); - cheight = Math.round(bBox.height); - dim.height += cheight; - dim.lineHeight = Math.round(Math.max(dim.lineHeight, cheight)); - } - dims.push(dim); - } - - g.remove(); - - let index = - isNaN(dims[1].height) || - isNaN(dims[1].width) || - isNaN(dims[1].lineHeight) || - (dims[0].height > dims[1].height && - dims[0].width > dims[1].width && - dims[0].lineHeight > dims[1].lineHeight) - ? 0 - : 1; - return dims[index]; - }, - (text, config) => `${text}-${config.fontSize}-${config.fontWeight}-${config.fontFamily}` -); - -const breakString = memoize( - (word, maxWidth, hyphenCharacter = '-', config) => { - config = Object.assign( - { fontSize: 12, fontWeight: 400, fontFamily: 'Arial', margin: 0 }, - config - ); - const characters = word.split(''); - const lines = []; - let currentLine = ''; - characters.forEach((character, index) => { - const nextLine = `${currentLine}${character}`; - const lineWidth = calculateTextWidth(nextLine, config); - if (lineWidth >= maxWidth) { - const currentCharacter = index + 1; - const isLastLine = characters.length === currentCharacter; - const hyphenatedNextLine = `${nextLine}${hyphenCharacter}`; - lines.push(isLastLine ? nextLine : hyphenatedNextLine); - currentLine = ''; - } else { - currentLine = nextLine; - } - }); - return { hyphenatedStrings: lines, remainingWord: currentLine }; - }, - (word, maxWidth, hyphenCharacter = '-', config) => - `${word}-${maxWidth}-${hyphenCharacter}-${config.fontSize}-${config.fontWeight}-${config.fontFamily}` -); - -export const wrapLabel = memoize( - (label, maxWidth, config) => { - if (!label) { - return label; - } - config = Object.assign( - { fontSize: 12, fontWeight: 400, fontFamily: 'Arial', joinWith: '
' }, - config - ); - if (lineBreakRegex.test(label)) { - return label; - } - const words = label.split(' '); - const completedLines = []; - let nextLine = ''; - words.forEach((word, index) => { - const wordLength = calculateTextWidth(`${word} `, config); - const nextLineLength = calculateTextWidth(nextLine, config); - if (wordLength > maxWidth) { - const { hyphenatedStrings, remainingWord } = breakString(word, maxWidth, '-', config); - completedLines.push(nextLine, ...hyphenatedStrings); - nextLine = remainingWord; - } else if (nextLineLength + wordLength >= maxWidth) { - completedLines.push(nextLine); - nextLine = word; - } else { - nextLine = [nextLine, word].filter(Boolean).join(' '); - } - const currentWord = index + 1; - const isLastWord = currentWord === words.length; - if (isLastWord) { - completedLines.push(nextLine); - } - }); - return completedLines.filter((line) => line !== '').join(config.joinWith); - }, - (label, maxWidth, config) => - `${label}-${maxWidth}-${config.fontSize}-${config.fontWeight}-${config.fontFamily}-${config.joinWith}` -); diff --git a/packages/mermaid/src/diagram-api/types.ts b/packages/mermaid/src/diagram-api/types.ts new file mode 100644 index 000000000..30ff25969 --- /dev/null +++ b/packages/mermaid/src/diagram-api/types.ts @@ -0,0 +1,26 @@ +import { MermaidConfig } from '../config.type'; + +export interface InjectUtils { + _log: any; + _setLogLevel: any; + _getConfig: any; + _sanitizeText: any; + _setupGraphViewbox: any; +} + +export interface DiagramDefinition { + db: any; + renderer: any; + parser: any; + styles: any; + init?: (config: MermaidConfig) => void; + injectUtils?: (utils: InjectUtils) => void; +} + +export interface DetectorRecord { + detector: DiagramDetector; + loader?: DiagramLoader; +} + +export type DiagramDetector = (text: string, config?: MermaidConfig) => boolean; +export type DiagramLoader = (() => Promise<{ id: string; diagram: DiagramDefinition }>) | null; diff --git a/packages/mermaid/src/diagrams/c4/c4Detector.ts b/packages/mermaid/src/diagrams/c4/c4Detector.ts index 2be62bff1..49ba95b8e 100644 --- a/packages/mermaid/src/diagrams/c4/c4Detector.ts +++ b/packages/mermaid/src/diagrams/c4/c4Detector.ts @@ -1,4 +1,4 @@ -import type { DiagramDetector } from '../../diagram-api/detectType'; +import type { DiagramDetector } from '../../diagram-api/types'; export const c4Detector: DiagramDetector = (txt) => { return txt.match(/^\s*C4Context|C4Container|C4Component|C4Dynamic|C4Deployment/) !== null; diff --git a/packages/mermaid/src/diagrams/class/classDetector-V2.ts b/packages/mermaid/src/diagrams/class/classDetector-V2.ts index a0e270100..d65caf9a8 100644 --- a/packages/mermaid/src/diagrams/class/classDetector-V2.ts +++ b/packages/mermaid/src/diagrams/class/classDetector-V2.ts @@ -1,4 +1,4 @@ -import type { DiagramDetector } from '../../diagram-api/detectType'; +import type { DiagramDetector } from '../../diagram-api/types'; export const classDetectorV2: DiagramDetector = (txt, config) => { // If we have confgured to use dagre-wrapper then we should return true in this function for classDiagram code thus making it use the new class diagram diff --git a/packages/mermaid/src/diagrams/class/classDetector.ts b/packages/mermaid/src/diagrams/class/classDetector.ts index 19d8bd2f5..ef6389a60 100644 --- a/packages/mermaid/src/diagrams/class/classDetector.ts +++ b/packages/mermaid/src/diagrams/class/classDetector.ts @@ -1,4 +1,4 @@ -import type { DiagramDetector } from '../../diagram-api/detectType'; +import type { DiagramDetector } from '../../diagram-api/types'; export const classDetector: DiagramDetector = (txt, config) => { // If we have confgured to use dagre-wrapper then we should never return true in this function diff --git a/packages/mermaid/src/diagrams/er/erDetector.ts b/packages/mermaid/src/diagrams/er/erDetector.ts index a17eafb81..5a87a949e 100644 --- a/packages/mermaid/src/diagrams/er/erDetector.ts +++ b/packages/mermaid/src/diagrams/er/erDetector.ts @@ -1,4 +1,4 @@ -import type { DiagramDetector } from '../../diagram-api/detectType'; +import type { DiagramDetector } from '../../diagram-api/types'; export const erDetector: DiagramDetector = (txt) => { return txt.match(/^\s*erDiagram/) !== null; diff --git a/packages/mermaid/src/diagrams/flowchart/flowDb.js b/packages/mermaid/src/diagrams/flowchart/flowDb.js index 192da23d3..5aa203225 100644 --- a/packages/mermaid/src/diagrams/flowchart/flowDb.js +++ b/packages/mermaid/src/diagrams/flowchart/flowDb.js @@ -429,8 +429,7 @@ export const clear = function (ver = 'gen-1') { vertices = {}; classes = {}; edges = []; - funs = []; - funs.push(setupToolTips); + funs = [setupToolTips]; subGraphs = []; subGraphLookup = {}; subCount = 0; diff --git a/packages/mermaid/src/diagrams/flowchart/flowDetector-v2.ts b/packages/mermaid/src/diagrams/flowchart/flowDetector-v2.ts index f73748c79..c2ec736c7 100644 --- a/packages/mermaid/src/diagrams/flowchart/flowDetector-v2.ts +++ b/packages/mermaid/src/diagrams/flowchart/flowDetector-v2.ts @@ -1,4 +1,4 @@ -import type { DiagramDetector } from '../../diagram-api/detectType'; +import type { DiagramDetector } from '../../diagram-api/types'; export const flowDetectorV2: DiagramDetector = (txt, config) => { // If we have confgured to use dagre-wrapper then we should return true in this function for graph code thus making it use the new flowchart diagram diff --git a/packages/mermaid/src/diagrams/flowchart/flowDetector.ts b/packages/mermaid/src/diagrams/flowchart/flowDetector.ts index edc9096c0..740d12847 100644 --- a/packages/mermaid/src/diagrams/flowchart/flowDetector.ts +++ b/packages/mermaid/src/diagrams/flowchart/flowDetector.ts @@ -1,4 +1,4 @@ -import type { DiagramDetector } from '../../diagram-api/detectType'; +import type { DiagramDetector } from '../../diagram-api/types'; export const flowDetector: DiagramDetector = (txt, config) => { // If we have confired to only use new flow charts this function shohuld always return false diff --git a/packages/mermaid/src/diagrams/gantt/ganttDetector.ts b/packages/mermaid/src/diagrams/gantt/ganttDetector.ts index 926792dcf..5de167010 100644 --- a/packages/mermaid/src/diagrams/gantt/ganttDetector.ts +++ b/packages/mermaid/src/diagrams/gantt/ganttDetector.ts @@ -1,4 +1,4 @@ -import type { DiagramDetector } from '../../diagram-api/detectType'; +import type { DiagramDetector } from '../../diagram-api/types'; export const ganttDetector: DiagramDetector = (txt) => { return txt.match(/^\s*gantt/) !== null; diff --git a/packages/mermaid/src/diagrams/git/gitGraphDetector.ts b/packages/mermaid/src/diagrams/git/gitGraphDetector.ts index 1c0a015e7..f890501a5 100644 --- a/packages/mermaid/src/diagrams/git/gitGraphDetector.ts +++ b/packages/mermaid/src/diagrams/git/gitGraphDetector.ts @@ -1,4 +1,4 @@ -import type { DiagramDetector } from '../../diagram-api/detectType'; +import type { DiagramDetector } from '../../diagram-api/types'; export const gitGraphDetector: DiagramDetector = (txt) => { return txt.match(/^\s*gitGraph/) !== null; diff --git a/packages/mermaid/src/diagrams/info/infoDetector.ts b/packages/mermaid/src/diagrams/info/infoDetector.ts index 68f2ac794..8bccb578f 100644 --- a/packages/mermaid/src/diagrams/info/infoDetector.ts +++ b/packages/mermaid/src/diagrams/info/infoDetector.ts @@ -1,4 +1,4 @@ -import type { DiagramDetector } from '../../diagram-api/detectType'; +import type { DiagramDetector } from '../../diagram-api/types'; export const infoDetector: DiagramDetector = (txt) => { return txt.match(/^\s*info/) !== null; diff --git a/packages/mermaid/src/diagrams/pie/pieDetector.ts b/packages/mermaid/src/diagrams/pie/pieDetector.ts index 1e122b0e0..65a011c7a 100644 --- a/packages/mermaid/src/diagrams/pie/pieDetector.ts +++ b/packages/mermaid/src/diagrams/pie/pieDetector.ts @@ -1,4 +1,4 @@ -import type { DiagramDetector } from '../../diagram-api/detectType'; +import type { DiagramDetector } from '../../diagram-api/types'; export const pieDetector: DiagramDetector = (txt) => { return txt.match(/^\s*pie/) !== null; diff --git a/packages/mermaid/src/diagrams/requirement/requirementDetector.ts b/packages/mermaid/src/diagrams/requirement/requirementDetector.ts index 2e1aa93ae..164da6c1a 100644 --- a/packages/mermaid/src/diagrams/requirement/requirementDetector.ts +++ b/packages/mermaid/src/diagrams/requirement/requirementDetector.ts @@ -1,4 +1,4 @@ -import type { DiagramDetector } from '../../diagram-api/detectType'; +import type { DiagramDetector } from '../../diagram-api/types'; export const requirementDetector: DiagramDetector = (txt) => { return txt.match(/^\s*requirement(Diagram)?/) !== null; diff --git a/packages/mermaid/src/diagrams/sequence/sequenceDetector.ts b/packages/mermaid/src/diagrams/sequence/sequenceDetector.ts index e68433255..52640b134 100644 --- a/packages/mermaid/src/diagrams/sequence/sequenceDetector.ts +++ b/packages/mermaid/src/diagrams/sequence/sequenceDetector.ts @@ -1,4 +1,4 @@ -import type { DiagramDetector } from '../../diagram-api/detectType'; +import type { DiagramDetector } from '../../diagram-api/types'; export const sequenceDetector: DiagramDetector = (txt) => { return txt.match(/^\s*sequenceDiagram/) !== null; diff --git a/packages/mermaid/src/diagrams/state/stateDetector-V2.ts b/packages/mermaid/src/diagrams/state/stateDetector-V2.ts index 8082a47bd..7fd9633c6 100644 --- a/packages/mermaid/src/diagrams/state/stateDetector-V2.ts +++ b/packages/mermaid/src/diagrams/state/stateDetector-V2.ts @@ -1,4 +1,4 @@ -import type { DiagramDetector } from '../../diagram-api/detectType'; +import type { DiagramDetector } from '../../diagram-api/types'; export const stateDetectorV2: DiagramDetector = (text, config) => { if (text.match(/^\s*stateDiagram-v2/) !== null) return true; diff --git a/packages/mermaid/src/diagrams/state/stateDetector.ts b/packages/mermaid/src/diagrams/state/stateDetector.ts index 79dd6586b..614f327c2 100644 --- a/packages/mermaid/src/diagrams/state/stateDetector.ts +++ b/packages/mermaid/src/diagrams/state/stateDetector.ts @@ -1,4 +1,4 @@ -import type { DiagramDetector } from '../../diagram-api/detectType'; +import type { DiagramDetector } from '../../diagram-api/types'; export const stateDetector: DiagramDetector = (txt, config) => { // If we have confired to only use new state diagrams this function should always return false diff --git a/packages/mermaid/src/diagrams/user-journey/journeyDetector.ts b/packages/mermaid/src/diagrams/user-journey/journeyDetector.ts index 77c8688ae..535e7be9d 100644 --- a/packages/mermaid/src/diagrams/user-journey/journeyDetector.ts +++ b/packages/mermaid/src/diagrams/user-journey/journeyDetector.ts @@ -1,4 +1,4 @@ -import type { DiagramDetector } from '../../diagram-api/detectType'; +import type { DiagramDetector } from '../../diagram-api/types'; export const journeyDetector: DiagramDetector = (txt) => { return txt.match(/^\s*journey/) !== null; diff --git a/packages/mermaid/src/docs.mts b/packages/mermaid/src/docs.mts index 59bcfc544..384357fe4 100644 --- a/packages/mermaid/src/docs.mts +++ b/packages/mermaid/src/docs.mts @@ -35,12 +35,16 @@ import { exec } from 'child_process'; import { globby } from 'globby'; import { JSDOM } from 'jsdom'; import type { Code, Root } from 'mdast'; -import { join, dirname } from 'path'; +import { posix, dirname } from 'path'; import prettier from 'prettier'; import { remark } from 'remark'; // @ts-ignore No typescript declaration file import flatmap from 'unist-util-flatmap'; +const MERMAID_MAJOR_VERSION = ( + JSON.parse(readFileSync('packages/mermaid/package.json', 'utf8')).version as string +).split('.')[0]; + // These paths are from the root of the mono-repo, not from the // mermaid sub-directory const SOURCE_DOCS_DIR = 'packages/mermaid/src/docs'; @@ -146,7 +150,7 @@ const readSyncedUTF8file = (filename: string): string => { * @param file {string} name of the file that will be verified */ const transformMarkdown = (file: string) => { - const doc = readSyncedUTF8file(file); + const doc = readSyncedUTF8file(file).replace(//g, MERMAID_MAJOR_VERSION); const ast: Root = remark.parse(doc); const out = flatmap(ast, (c: Code) => { if (c.type !== 'code') { @@ -187,7 +191,10 @@ const transformHtml = (filename: string) => { * @returns {string} The contents of the file with the comment inserted */ const insertAutoGeneratedComment = (fileName: string): string => { - const fileContents = readSyncedUTF8file(fileName); + const fileContents = readSyncedUTF8file(fileName).replace( + //g, + MERMAID_MAJOR_VERSION + ); const jsdom = new JSDOM(fileContents); const htmlDoc = jsdom.window.document; const autoGeneratedComment = jsdom.window.document.createComment(generateHeader(fileName)); @@ -205,30 +212,28 @@ const transformHtml = (filename: string) => { copyTransformedContents(filename, !verifyOnly, formattedHTML); }; +const getFilesFromGlobs = async (globs: string[]): Promise => { + return await globby(globs, { dot: true }); +}; + /** Main method (entry point) */ (async () => { if (verifyOnly) { console.log('Verifying that all files are in sync with the source files'); } - const sourceDirGlob = join('.', SOURCE_DOCS_DIR, '**'); - const includeFilesStartingWithDot = true; + const sourceDirGlob = posix.join('.', SOURCE_DOCS_DIR, '**'); + const action = verifyOnly ? 'Verifying' : 'Transforming'; - console.log('Transforming markdown files...'); - const mdFiles = await globby([join(sourceDirGlob, '*.md')], { - dot: includeFilesStartingWithDot, - }); + const mdFiles = await getFilesFromGlobs([posix.join(sourceDirGlob, '*.md')]); + console.log(`${action} ${mdFiles.length} markdown files...`); mdFiles.forEach(transformMarkdown); - console.log('Transforming html files...'); - const htmlFiles = await globby([join(sourceDirGlob, '*.html')], { - dot: includeFilesStartingWithDot, - }); + const htmlFiles = await getFilesFromGlobs([posix.join(sourceDirGlob, '*.html')]); + console.log(`${action} ${htmlFiles.length} html files...`); htmlFiles.forEach(transformHtml); - console.log('Transforming all other files...'); - const otherFiles = await globby([sourceDirGlob, '!**/*.md', '!**/*.html'], { - dot: includeFilesStartingWithDot, - }); + const otherFiles = await getFilesFromGlobs([sourceDirGlob, '!**/*.md', '!**/*.html']); + console.log(`${action} ${otherFiles.length} other files...`); otherFiles.forEach((file: string) => { copyTransformedContents(file, !verifyOnly); // no transformation }); @@ -239,7 +244,7 @@ const transformHtml = (filename: string) => { process.exit(1); } if (git) { - console.log('Adding changes in ${FINAL_DOCS_DIR} folder to git'); + console.log(`Adding changes in ${FINAL_DOCS_DIR} folder to git`); exec('git add docs'); } } diff --git a/packages/mermaid/src/docs/README.md b/packages/mermaid/src/docs/README.md index 9040eea39..880e40b43 100644 --- a/packages/mermaid/src/docs/README.md +++ b/packages/mermaid/src/docs/README.md @@ -8,7 +8,7 @@ It is a JavaScript based diagramming and charting tool that renders Markdown-ins -[![Build Status](https://travis-ci.org/mermaid-js/mermaid.svg?branch=master)](https://travis-ci.org/mermaid-js/mermaid) [![NPM](https://img.shields.io/npm/v/mermaid)](https://www.npmjs.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) [![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) +[![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) [![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_) @@ -187,16 +187,16 @@ To Deploy Mermaid: ### [Mermaid API](./Setup.md): -**To deploy mermaid without a bundler, one can insert a `script` tag with an absolute address and a `mermaidAPI` call into the HTML like so:** +**To deploy mermaid without a bundler, one can insert a `script` tag with an absolute address and a `mermaid.initialize` call into the HTML like so:** ```html - - ``` -**Doing so will command the mermaid parser to look for the `
` tags with `class="mermaid"`. From these tags mermaid will try to read the diagram/chart definitions and render them into SVG charts.** +**Doing so will command the mermaid parser to look for the `
` or `
` tags with `class="mermaid"`. From these tags mermaid will try to read the diagram/chart definitions and render them into SVG charts.**
 
 **Examples can be found at** [Other examples](/examples)
 
diff --git a/packages/mermaid/src/docs/Setup.md b/packages/mermaid/src/docs/Setup.md
index 0c8f50bb8..95ae2dde4 100644
--- a/packages/mermaid/src/docs/Setup.md
+++ b/packages/mermaid/src/docs/Setup.md
@@ -1559,7 +1559,7 @@ Returns **void**
 
 ```html
 
@@ -451,10 +451,10 @@ Beginner's tip—a full example using interactive links in an HTML page:
   
@@ -471,10 +471,10 @@ Beginner's tip—here's a full example of using interactive links in HTML:
@@ -495,10 +495,10 @@ Beginner's tip—a full example using interactive links in a html context:
- @@ -50,17 +48,21 @@
+ - -``` - -**b. The embedded mermaid diagram definition inside a `
`:**
+**a. The embedded mermaid diagram definition inside a `
`:**
 
 ```html
 
@@ -105,13 +95,14 @@ c. The `mermaid.initialize()` call, which dictates the appearance of diagrams an
 
 **Notes**: Every Mermaid chart/graph/diagram definition, should have separate `
` tags.
 
-**c. The `mermaid.initialize()` call.**
+**b. The import of mermaid and the `mermaid.initialize()` call.**
 
 `mermaid.initialize()` call takes all the definitions contained in all the `
` tags that it finds in the html body and renders them into diagrams. Example:
 
 ```html
 
-  
 
@@ -133,11 +124,6 @@ Rendering in Mermaid is initialized by `mermaid.initialize()` call. You can plac
 ```html
 
   
-    
-    
-
     Here is one mermaid diagram:
     
             graph TD 
@@ -154,6 +140,11 @@ Rendering in Mermaid is initialized by `mermaid.initialize()` call. You can plac
             B -->|tcp_456| C[Server1] 
             B -->|tcp_456| D[Server2]
     
+ + ``` @@ -179,8 +170,8 @@ In this example mermaid.js is referenced in `src` as a separate JavaScript file, B --> C[Server1] B --> D[Server2]
- - @@ -204,4 +195,4 @@ In this example mermaid.js is referenced in `src` as a separate JavaScript file, **Comments from Knut Sveidqvist, creator of mermaid:** -- In early versions of mermaid, the ` - ``` - -2. The `mermaidAPI` call, in a separate `script` tag. Example: - - ```html - - ``` - -3. A graph definition, inside `
` tags labeled `class=mermaid`. Example: +- A graph definition, inside `
` tags labeled `class=mermaid`. Example:
 
 ```html
 
@@ -66,8 +52,18 @@ The easiest way to integrate mermaid on a web page requires three elements:
 
``` -**Following these directions, mermaid starts at page load and (when the page has loaded) it will -locate the graph definitions inside the `div` tags with `class="mermaid"` and return diagrams in SVG form, following given definitions.** +- Inclusion of the mermaid address in the html page body using a `script` tag as an ESM import, and the `mermaidAPI` call. + +Example: + +```html + +``` + +**Following these directions, mermaid starts at page load and (when the page has loaded) it will locate the graph definitions inside the `pre` tags with `class="mermaid"` and return diagrams in SVG form, following given definitions.** ## Simple full example: @@ -84,8 +80,8 @@ locate the graph definitions inside the `div` tags with `class="mermaid"` and re B-->C[fa:fa-ban forbidden] B-->D(fa:fa-spinner);
- - @@ -204,18 +200,17 @@ fetch the graph definition from the site (perhaps from a textarea), render it an The example below show an outline of how this could be used. The example just logs the resulting SVG to the JavaScript console. ```html - - - ``` @@ -339,7 +334,7 @@ on what kind of integration you use. ```html ``` diff --git a/packages/mermaid/src/mermaid.ts b/packages/mermaid/src/mermaid.ts index 7ddbc9f06..ae6c62547 100644 --- a/packages/mermaid/src/mermaid.ts +++ b/packages/mermaid/src/mermaid.ts @@ -7,14 +7,6 @@ import { log } from './logger'; import utils from './utils'; import { mermaidAPI } from './mermaidAPI'; import { addDetector } from './diagram-api/detectType'; -import { - registerDiagram, - DiagramDefinition, - setLogLevel, - getConfig, - setupGraphViewbox, - sanitizeText, -} from './diagram-api/diagramAPI'; import { isDetailedError } from './utils'; /** @@ -53,17 +45,16 @@ const init = async function ( callback?: Function ) { try { - log.info('Detectors in init', mermaid.detectors); // eslint-disable-line const conf = mermaidAPI.getConfig(); - if (typeof conf.lazyLoadedDiagrams !== 'undefined' && conf.lazyLoadedDiagrams.length > 0) { - for (let i = 0; i < conf.lazyLoadedDiagrams.length; i++) { - const { id, detector, loadDiagram } = await import(conf.lazyLoadedDiagrams[i]); - addDetector(id, detector, loadDiagram); - } + if (conf?.lazyLoadedDiagrams && conf.lazyLoadedDiagrams.length > 0) { + // Load all lazy loaded diagrams in parallel + await Promise.allSettled( + conf.lazyLoadedDiagrams.map(async (diagram: string) => { + const { id, detector, loadDiagram } = await import(diagram); + addDetector(id, detector, loadDiagram); + }) + ); } - mermaid.detectors.forEach(({ id, detector, path }) => { - addDetector(id, detector, path); - }); await initThrowsErrors(config, nodes, callback); } catch (e) { log.warn('Syntax Error rendering'); @@ -218,22 +209,6 @@ const parse = (txt: string) => { return mermaidAPI.parse(txt, mermaid.parseError); }; -const connectDiagram = ( - id: string, - diagram: DiagramDefinition, - callback: ( - _log: any, - _setLogLevel: any, - _getConfig: any, - _sanitizeText: any, - _setupGraphViewbox: any - ) => void -) => { - registerDiagram(id, diagram, callback); - // Todo move this connect call to after the diagram is actually loaded. - callback(log, setLogLevel, getConfig, sanitizeText, setupGraphViewbox); -}; - const mermaid: { startOnLoad: boolean; diagrams: any; @@ -247,9 +222,6 @@ const mermaid: { initialize: typeof initialize; contentLoaded: typeof contentLoaded; setParseErrorHandler: typeof setParseErrorHandler; - // Array of functions to use for detecting diagram types - detectors: Array; // eslint-disable-line @typescript-eslint/no-explicit-any - connectDiagram: (id: string, diagram: DiagramDefinition, callback: (id: string) => void) => void; } = { startOnLoad: true, diagrams: {}, @@ -262,8 +234,6 @@ const mermaid: { parseError: undefined, contentLoaded, setParseErrorHandler, - detectors: [], - connectDiagram: connectDiagram, }; export default mermaid; diff --git a/packages/mermaid/src/mermaidAPI.ts b/packages/mermaid/src/mermaidAPI.ts index f9544ee44..7c967e5fd 100644 --- a/packages/mermaid/src/mermaidAPI.ts +++ b/packages/mermaid/src/mermaidAPI.ts @@ -18,7 +18,6 @@ import { compile, serialize, stringify } from 'stylis'; import pkg from '../package.json'; import * as configApi from './config'; import { addDiagrams } from './diagram-api/diagram-orchestration'; -import { addDetector } from './diagram-api/detectType'; import classDb from './diagrams/class/classDb'; import flowDb from './diagrams/flowchart/flowDb'; import flowRenderer from './diagrams/flowchart/flowRenderer'; @@ -34,18 +33,13 @@ import DOMPurify from 'dompurify'; import { MermaidConfig } from './config.type'; import { evaluate } from './diagrams/common/common'; -let hasLoadedDiagrams = false; - /** * @param text * @param parseError */ // eslint-disable-next-line @typescript-eslint/ban-types function parse(text: string, parseError?: Function): boolean { - if (!hasLoadedDiagrams) { - addDiagrams(); - hasLoadedDiagrams = true; - } + addDiagrams(); const diagram = new Diagram(text, parseError); return diagram.parse(text, parseError); } @@ -122,10 +116,7 @@ const render = async function ( cb: (svgCode: string, bindFunctions?: (element: Element) => void) => void, container?: Element ): Promise { - if (!hasLoadedDiagrams) { - addDiagrams(); - hasLoadedDiagrams = true; - } + addDiagrams(); configApi.reset(); text = text.replace(/\r\n?/g, '\n'); // parser problems on CRLF ignore all CR and leave LF;; const graphInit = utils.detectInit(text); @@ -486,11 +477,7 @@ async function initialize(options: MermaidConfig) { typeof options === 'object' ? configApi.setSiteConfig(options) : configApi.getSiteConfig(); setLogLevel(config.logLevel); - - if (!hasLoadedDiagrams) { - addDiagrams(); - hasLoadedDiagrams = true; - } + addDiagrams(); } export const mermaidAPI = Object.freeze({ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 89b929342..b2f88060c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,6 +17,7 @@ importers: '@types/express': ^4.17.14 '@types/jsdom': ^20.0.0 '@types/lodash': ^4.14.186 + '@types/mdast': ^3.0.10 '@types/node': ^18.8.1 '@types/prettier': ^2.7.1 '@types/stylis': ^4.0.2 @@ -103,6 +104,7 @@ importers: '@types/express': 4.17.14 '@types/jsdom': 20.0.0 '@types/lodash': 4.14.186 + '@types/mdast': 3.0.10 '@types/prettier': 2.7.1 '@types/stylis': 4.0.2 '@typescript-eslint/eslint-plugin': 5.39.0_xyciw6oqjoiiono4dhv3uhn5my diff --git a/renovate.json b/renovate.json new file mode 100644 index 000000000..1413a3cea --- /dev/null +++ b/renovate.json @@ -0,0 +1,24 @@ +{ + "extends": [ + "config:base", + ":rebaseStalePrs", + "group:allNonMajor", + "schedule:earlyMondays", + ":automergeMinor", + ":automergeTesters", + ":automergeLinters", + ":automergeTypes", + ":automergePatch" + ], + "packageRules": [ + { + "matchUpdateTypes": ["minor", "patch", "pin", "digest"], + "automerge": true + } + ], + "dependencyDashboard": true, + "major": { + "dependencyDashboardApproval": true + }, + "dependencyDashboardAutoclose": true +} diff --git a/todo-fix-root-level-tsconfig.json b/todo-fix-root-level-tsconfig.json deleted file mode 100644 index 0ffa0002e..000000000 --- a/todo-fix-root-level-tsconfig.json +++ /dev/null @@ -1,108 +0,0 @@ -{ - "compilerOptions": { - /* Visit https://aka.ms/tsconfig.json to read more about this file */ - - /* Projects */ - // "incremental": true /* Enable incremental compilation */, - // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ - // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */ - // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */ - // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ - // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ - - /* Language and Environment */ - "target": "ES6" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, - "lib": [ - "DOM", - "ES2021" - ] /* Specify a set of bundled library declaration files that describe the target runtime environment. */, - // "jsx": "preserve", /* Specify what JSX code is generated. */ - // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ - // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ - // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */ - // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ - // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */ - // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */ - // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ - // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ - - /* Modules */ - "module": "ES6" /* Specify what module code is generated. */, - "rootDir": "./src" /* Specify the root folder within your source files. */, - "moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */, - // "baseUrl": "./src" /* Specify the base directory to resolve non-relative module names. */, - // "paths": {} /* Specify a set of entries that re-map imports to additional lookup locations. */, - // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ - // "typeRoots": [] /* Specify multiple folders that act like `./node_modules/@types`. */, - "types": [ - "vitest/globals" - ] /* Specify type package names to be included without being referenced in a source file. */, - - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - "resolveJsonModule": true /* Enable importing .json files */, - // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */ - - /* JavaScript Support */ - "allowJs": true /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */, - // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ - // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ - - /* Emit */ - "declaration": true /* Generate .d.ts files from TypeScript and JavaScript files in your project. */, - // "declarationMap": true, /* Create sourcemaps for d.ts files. */ - // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ - // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ - // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ - "outDir": "./dist" /* Specify an output folder for all emitted files. */, - // "removeComments": true, /* Disable emitting comments. */ - // "noEmit": true, /* Disable emitting files from a compilation. */ - // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ - // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */ - // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ - // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ - // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ - // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ - // "newLine": "crlf", /* Set the newline character for emitting files. */ - // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */ - // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */ - // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ - // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */ - // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ - // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ - - /* Interop Constraints */ - // "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. */ - "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, - - /* Type Checking */ - "strict": true /* Enable all strict type-checking options. */, - // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */ - // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ - // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ - // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ - // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ - // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */ - // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ - // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ - // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */ - // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */ - // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ - // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ - // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ - // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ - // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ - // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */ - // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ - // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ - - /* Completeness */ - // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ - }, - "include": ["./src/**/*.ts", "./package.json"] -} diff --git a/vdocs/config/Setup.md b/vdocs/config/Setup.md index bcf8ef583..fb58b78ea 100644 --- a/vdocs/config/Setup.md +++ b/vdocs/config/Setup.md @@ -29,7 +29,7 @@ mermaid.initialize({ flowchart: { htmlLabels: false } }); **Example 2:** ```js -var config = { +const config = { startOnLoad: true, flowchart: { useMaxWidth: true, htmlLabels: true, curve: 'cardinal' }, @@ -1560,7 +1560,7 @@ Returns **void** ```html - ``` - -2. The `mermaidAPI` call, in a separate `script` tag. Example: - - ```html - - ``` - -3. A graph definition, inside `
` tags labeled `class=mermaid`. Example: +- A graph definition, inside `
` tags labeled `class=mermaid`. Example:
 
 ```html
 
@@ -66,8 +52,18 @@ The easiest way to integrate mermaid on a web page requires three elements:
 
``` -**Following these directions, mermaid starts at page load and (when the page has loaded) it will -locate the graph definitions inside the `div` tags with `class="mermaid"` and return diagrams in SVG form, following given definitions.** +- Inclusion of the mermaid address in the html page body using a `script` tag as an ESM import, and the `mermaidAPI` call. + +Example: + +```html + +``` + +**Following these directions, mermaid starts at page load and (when the page has loaded) it will locate the graph definitions inside the `pre` tags with `class="mermaid"` and return diagrams in SVG form, following given definitions.** ## Simple full example: @@ -84,8 +80,8 @@ locate the graph definitions inside the `div` tags with `class="mermaid"` and re B-->C[fa:fa-ban forbidden] B-->D(fa:fa-spinner);
- - @@ -211,11 +207,11 @@ The example below show an outline of how this could be used. The example just lo $(function () { // Example of using the API var element = document.querySelector('#graphDiv'); - var insertSvg = function (svgCode, bindFunctions) { + const insertSvg = function (svgCode, bindFunctions) { element.innerHTML = svgCode; }; - var graphDefinition = 'graph TB\na-->b'; - var graph = mermaid.mermaidAPI.render('graphDiv', graphDefinition, insertSvg); + const graphDefinition = 'graph TB\na-->b'; + const graph = mermaid.mermaidAPI.render('graphDiv', graphDefinition, insertSvg); }); ``` @@ -339,7 +335,7 @@ on what kind of integration you use. ```html ``` diff --git a/vdocs/intro/index.md b/vdocs/intro/index.md index 030409c6d..e2f36651f 100644 --- a/vdocs/intro/index.md +++ b/vdocs/intro/index.md @@ -8,7 +8,7 @@ It is a JavaScript based diagramming and charting tool that renders Markdown-ins -[![Build Status](https://travis-ci.org/mermaid-js/mermaid.svg?branch=master)](https://travis-ci.org/mermaid-js/mermaid) [![NPM](https://img.shields.io/npm/v/mermaid)](https://www.npmjs.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) [![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) +[![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) [![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_) @@ -262,16 +262,16 @@ To Deploy Mermaid: ### [Mermaid API](../config/Setup.md): -**To deploy mermaid without a bundler, one can insert a `script` tag with an absolute address and a `mermaidAPI` call into the HTML like so:** +**To deploy mermaid without a bundler, one can insert a `script` tag with an absolute address and a `mermaid.initialize` call into the HTML like so:** ```html - - ``` -**Doing so will command the mermaid parser to look for the `
` tags with `class="mermaid"`. From these tags mermaid will try to read the diagram/chart definitions and render them into SVG charts.** +**Doing so will command the mermaid parser to look for the `
` or `
` tags with `class="mermaid"`. From these tags mermaid will try to read the diagram/chart definitions and render them into SVG charts.**
 
 **Examples can be found at** [Other examples](../syntax/examples)
 
diff --git a/vdocs/intro/n00b-gettingStarted.md b/vdocs/intro/n00b-gettingStarted.md
index 14b49057e..b5abe96d6 100644
--- a/vdocs/intro/n00b-gettingStarted.md
+++ b/vdocs/intro/n00b-gettingStarted.md
@@ -82,23 +82,13 @@ The API works by pulling rendering instructions from the source `mermaid.js` in
 
 ### Requirements for the Mermaid API.
 
-When writing the .html file, we give three instructions inside the html code to the web browser:
+When writing the .html file, we give two instructions inside the html code to the web browser:
 
-a. A reference for fetching the online mermaid renderer, through the `mermaid.js` or `mermaid.min.js`.
+a. The mermaid code for the diagram we want to create.
 
-b. 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 .
 
-c. The `mermaid.initialize()` call, which dictates the appearance of diagrams and also starts the rendering process .
-
-**a. A reference to the external CDN in a `
-
-```
-
-**b. The embedded mermaid diagram definition inside a `
`:**
+**a. The embedded mermaid diagram definition inside a `
`:**
 
 ```html
 
@@ -114,13 +104,14 @@ c. The `mermaid.initialize()` call, which dictates the appearance of diagrams an
 
 **Notes**: Every Mermaid chart/graph/diagram definition, should have separate `
` tags.
 
-**c. The `mermaid.initialize()` call.**
+**b. The import of mermaid and the `mermaid.initialize()` call.**
 
 `mermaid.initialize()` call takes all the definitions contained in all the `
` tags that it finds in the html body and renders them into diagrams. Example:
 
 ```html
 
-  
 
@@ -142,11 +133,6 @@ Rendering in Mermaid is initialized by `mermaid.initialize()` call. You can plac
 ```html
 
   
-    
-    
-
     Here is one mermaid diagram:
     
             graph TD 
@@ -163,6 +149,11 @@ Rendering in Mermaid is initialized by `mermaid.initialize()` call. You can plac
             B -->|tcp_456| C[Server1] 
             B -->|tcp_456| D[Server2]
     
+ + ``` @@ -188,8 +179,8 @@ In this example mermaid.js is referenced in `src` as a separate JavaScript file, B --> C[Server1] B --> D[Server2]
- - @@ -213,4 +204,4 @@ In this example mermaid.js is referenced in `src` as a separate JavaScript file, **Comments from Knut Sveidqvist, creator of mermaid:** -- In early versions of mermaid, the ` @@ -451,10 +451,10 @@ Beginner's tip—a full example using interactive links in an HTML page:
@@ -502,10 +502,10 @@ Beginner's tip—a full example using interactive links in a html context: