mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-01-21 06:53:17 +08:00
Merge branch 'develop' into pr/rhysd/4359
* develop: (255 commits) chore(deps): update all minor dependencies chore: Run codecov based on E2E test status change REAMDME.md coverage from coveralls into codecov Add codecov.yaml Upload E2E set normal mode for vitest coverage Fix path name Add codecov to unit tests Add codecov to E2E chore: Add coverage scripts chore: add excludes chore: update deps Merge coverages Add coverage paths Rebuild chore: update pnpm Add coverage for E2E tests rename plugin variable into info in infoDetector.ts remove cypress/platform/index.html update pnpm-lock.yaml ...
This commit is contained in:
commit
8d48f8d8b0
@ -5,3 +5,4 @@ cypress.config.js
|
||||
cypress/plugins/index.js
|
||||
coverage
|
||||
*.json
|
||||
node_modules
|
||||
|
26
.github/ISSUE_TEMPLATE/diagram_proposal.yml
vendored
26
.github/ISSUE_TEMPLATE/diagram_proposal.yml
vendored
@ -3,6 +3,7 @@ description: Suggest a new Diagram Type to add to Mermaid.
|
||||
labels:
|
||||
- 'Status: Triage'
|
||||
- 'Type: Enhancement'
|
||||
- 'Type: New Diagram'
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
@ -17,6 +18,14 @@ body:
|
||||
- Use a clear and concise title
|
||||
- Fill out the text fields with as much detail as possible.
|
||||
- Never be shy to give us screenshots and/or code samples. It will help!
|
||||
|
||||
## Example issues
|
||||
|
||||
Refer to the discussions here to get an idea of how the diagram syntax is created.
|
||||
|
||||
- https://github.com/mermaid-js/mermaid/issues/4269
|
||||
- https://github.com/mermaid-js/mermaid/issues/4282
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Proposal
|
||||
@ -35,8 +44,17 @@ body:
|
||||
description: If applicable, add screenshots to show possible examples of how the diagram may look like.
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Code Sample
|
||||
label: Syntax
|
||||
description: |-
|
||||
If applicable, add a code sample for how to implement this new diagram.
|
||||
The text will automatically be rendered as JavaScript code.
|
||||
render: javascript
|
||||
If possible, include a syntax which could be used to write the diagram.
|
||||
Try to add one or two examples of valid use-cases here.
|
||||
- type: dropdown
|
||||
id: implementation
|
||||
attributes:
|
||||
label: Implementation
|
||||
description: |-
|
||||
Would you like to implement this yourself, or is it a proposal for the community?
|
||||
If there is no corresponding PR from your side after 30 days, the diagram will be open for everyone to implement.
|
||||
options:
|
||||
- I will try and implement it myself.
|
||||
- This is a proposal which I'd love to see built into mermaid by the wonderful community.
|
||||
|
13
.github/workflows/e2e.yml
vendored
13
.github/workflows/e2e.yml
vendored
@ -33,7 +33,7 @@ jobs:
|
||||
# Otherwise (e.g. if running from fork), we run on a single container only
|
||||
if: ${{ ( env.CYPRESS_RECORD_KEY != '' ) || ( matrix.containers == 1 ) }}
|
||||
with:
|
||||
start: pnpm run dev
|
||||
start: pnpm run dev:coverage
|
||||
wait-on: 'http://localhost:9000'
|
||||
# Disable recording if we don't have an API key
|
||||
# e.g. if this action was run from a fork
|
||||
@ -41,7 +41,16 @@ jobs:
|
||||
parallel: ${{ secrets.CYPRESS_RECORD_KEY != '' }}
|
||||
env:
|
||||
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
|
||||
|
||||
VITEST_COVERAGE: true
|
||||
- name: Upload Coverage to Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
if: steps.cypress.conclusion == 'success'
|
||||
with:
|
||||
files: coverage/cypress/lcov.info
|
||||
flags: e2e
|
||||
name: mermaid-codecov
|
||||
fail_ci_if_error: true
|
||||
verbose: true
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
if: ${{ failure() && steps.cypress.conclusion == 'failure' }}
|
||||
|
2
.github/workflows/link-checker.yml
vendored
2
.github/workflows/link-checker.yml
vendored
@ -36,7 +36,7 @@ jobs:
|
||||
restore-keys: cache-lychee-
|
||||
|
||||
- name: Link Checker
|
||||
uses: lycheeverse/lychee-action@v1.7.0
|
||||
uses: lycheeverse/lychee-action@v1.8.0
|
||||
with:
|
||||
args: >-
|
||||
--verbose
|
||||
|
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
@ -42,7 +42,7 @@ jobs:
|
||||
if ! pnpm run lint; then
|
||||
# print a nice error message on lint failure
|
||||
ERROR_MESSAGE='Running `pnpm run lint` failed.'
|
||||
ERROR_MESSAGE+=' Running `pnpm run lint:fix` may fix this issue. '
|
||||
ERROR_MESSAGE+=' Running `pnpm -w run lint:fix` may fix this issue. '
|
||||
ERROR_MESSAGE+=" If this error doesn't occur on your local machine,"
|
||||
ERROR_MESSAGE+=' make sure your packages are up-to-date by running `pnpm install`.'
|
||||
ERROR_MESSAGE+=' You may also need to delete your prettier cache by running'
|
||||
|
24
.github/workflows/test.yml
vendored
24
.github/workflows/test.yml
vendored
@ -31,7 +31,7 @@ jobs:
|
||||
|
||||
- name: Run Unit Tests
|
||||
run: |
|
||||
pnpm run ci --coverage
|
||||
pnpm test:coverage
|
||||
|
||||
- name: Run ganttDb tests using California timezone
|
||||
env:
|
||||
@ -39,13 +39,19 @@ jobs:
|
||||
# since some days have 25 hours instead of 24.
|
||||
TZ: America/Los_Angeles
|
||||
run: |
|
||||
pnpm exec vitest run ./packages/mermaid/src/diagrams/gantt/ganttDb.spec.ts
|
||||
pnpm exec vitest run ./packages/mermaid/src/diagrams/gantt/ganttDb.spec.ts --coverage
|
||||
|
||||
- name: Upload Coverage to Coveralls
|
||||
# it feels a bit weird to use @master, but that's what the docs use
|
||||
# (coveralls also doesn't publish a @v1 we can use)
|
||||
# https://github.com/marketplace/actions/coveralls-github-action
|
||||
uses: coverallsapp/github-action@master
|
||||
- name: Upload Coverage to Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
flag-name: unit
|
||||
files: ./coverage/vitest/lcov.info
|
||||
flags: unit
|
||||
name: mermaid-codecov
|
||||
fail_ci_if_error: true
|
||||
verbose: true
|
||||
# Coveralls is throwing 500. Disabled for now.
|
||||
# - name: Upload Coverage to Coveralls
|
||||
# uses: coverallsapp/github-action@v2
|
||||
# with:
|
||||
# github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# flag-name: unit
|
||||
|
7
.gitignore
vendored
7
.gitignore
vendored
@ -3,8 +3,10 @@
|
||||
node_modules/
|
||||
coverage/
|
||||
.idea/
|
||||
.pnpm-store/
|
||||
|
||||
dist
|
||||
v8-compile-cache-0
|
||||
|
||||
yarn-error.log
|
||||
.npmrc
|
||||
@ -36,3 +38,8 @@ tsconfig.tsbuildinfo
|
||||
knsv*.html
|
||||
local*.html
|
||||
stats/
|
||||
|
||||
**/user-avatars/*
|
||||
**/contributor-names.json
|
||||
.pnpm-store
|
||||
.nyc_output
|
||||
|
@ -1,5 +1,5 @@
|
||||
export default {
|
||||
'!(docs/**/*)*.{ts,js,json,html,md,mts}': [
|
||||
'!(docs/**/*)*.{ts,js,html,md,mts}': [
|
||||
'eslint --cache --cache-strategy content --fix',
|
||||
// don't cache prettier yet, since we use `prettier-plugin-jsdoc`,
|
||||
// and prettier doesn't invalidate cache on plugin updates"
|
||||
|
@ -9,3 +9,9 @@ https://twitter.com/mermaidjs_
|
||||
|
||||
# Don't check files that are generated during the build via `pnpm docs:code`
|
||||
packages/mermaid/src/docs/config/setup/*
|
||||
|
||||
# Ignore localhost
|
||||
http://localhost:3333/
|
||||
|
||||
# Ignore slack invite
|
||||
https://join.slack.com/
|
||||
|
@ -5,3 +5,4 @@ coverage
|
||||
# Autogenerated by PNPM
|
||||
pnpm-lock.yaml
|
||||
stats
|
||||
packages/mermaid/src/docs/.vitepress/components.d.ts
|
||||
|
@ -6,10 +6,12 @@ import { readFileSync } from 'fs';
|
||||
import typescript from '@rollup/plugin-typescript';
|
||||
import { visualizer } from 'rollup-plugin-visualizer';
|
||||
import type { TemplateType } from 'rollup-plugin-visualizer/dist/plugin/template-types.js';
|
||||
import istanbul from 'vite-plugin-istanbul';
|
||||
|
||||
const visualize = process.argv.includes('--visualize');
|
||||
const watch = process.argv.includes('--watch');
|
||||
const mermaidOnly = process.argv.includes('--mermaid');
|
||||
const coverage = process.env.VITE_COVERAGE === 'true';
|
||||
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
||||
const sourcemap = false;
|
||||
|
||||
@ -44,6 +46,11 @@ const packageOptions = {
|
||||
packageName: 'mermaid-example-diagram',
|
||||
file: 'detector.ts',
|
||||
},
|
||||
'mermaid-zenuml': {
|
||||
name: 'mermaid-zenuml',
|
||||
packageName: 'mermaid-zenuml',
|
||||
file: 'detector.ts',
|
||||
},
|
||||
};
|
||||
|
||||
interface BuildOptions {
|
||||
@ -116,6 +123,12 @@ export const getBuildConfig = ({ minify, core, watch, entryName }: BuildOptions)
|
||||
jisonPlugin(),
|
||||
// @ts-expect-error According to the type definitions, rollup plugins are incompatible with vite
|
||||
typescript({ compilerOptions: { declaration: false } }),
|
||||
istanbul({
|
||||
exclude: ['node_modules', 'test/', '__mocks__'],
|
||||
extension: ['.js', '.ts'],
|
||||
requireEnv: true,
|
||||
forceBuildInstrument: coverage,
|
||||
}),
|
||||
...visualizerOptions(packageName, core),
|
||||
],
|
||||
};
|
||||
@ -146,6 +159,7 @@ if (watch) {
|
||||
build(getBuildConfig({ minify: false, watch, core: false, entryName: 'mermaid' }));
|
||||
if (!mermaidOnly) {
|
||||
build(getBuildConfig({ minify: false, watch, entryName: 'mermaid-example-diagram' }));
|
||||
build(getBuildConfig({ minify: false, watch, entryName: 'mermaid-zenuml' }));
|
||||
}
|
||||
} else if (visualize) {
|
||||
await build(getBuildConfig({ minify: false, core: true, entryName: 'mermaid' }));
|
||||
|
@ -1,8 +1,6 @@
|
||||
// @ts-ignore No typings for jison
|
||||
import jison from 'jison';
|
||||
|
||||
export const transformJison = (src: string): string => {
|
||||
// @ts-ignore No typings for jison
|
||||
const parser = new jison.Generator(src, {
|
||||
moduleType: 'js',
|
||||
'token-stack': true,
|
||||
|
@ -15,6 +15,7 @@ async function createServer() {
|
||||
|
||||
app.use(cors());
|
||||
app.use(express.static('./packages/mermaid/dist'));
|
||||
app.use(express.static('./packages/mermaid-zenuml/dist'));
|
||||
app.use(express.static('./packages/mermaid-example-diagram/dist'));
|
||||
app.use(vite.middlewares);
|
||||
app.use(express.static('demos'));
|
||||
|
179
CONTRIBUTING.md
179
CONTRIBUTING.md
@ -1,14 +1,10 @@
|
||||
# Contributing
|
||||
|
||||
So you want to help? That's great!
|
||||
Please read in detail about how to contribute documentation and code on the [Mermaid documentation site.](https://mermaid-js.github.io/mermaid/#/development)
|
||||
|
||||
![Happy people jumping with excitement](https://media.giphy.com/media/BlVnrxJgTGsUw/giphy.gif)
|
||||
---
|
||||
|
||||
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
|
||||
# Mermaid contribution cheat-sheet
|
||||
|
||||
## Requirements
|
||||
|
||||
@ -18,163 +14,58 @@ https://docs.github.com/en/get-started/quickstart/fork-a-repo
|
||||
|
||||
## Development Installation
|
||||
|
||||
If you don't have direct access to push to mermaid repositories, make a fork first. Then clone. Or clone directly from mermaid-js:
|
||||
|
||||
```bash
|
||||
git clone git@github.com:mermaid-js/mermaid.git
|
||||
cd mermaid
|
||||
```
|
||||
|
||||
Install required packages:
|
||||
|
||||
```bash
|
||||
# npx is required for first install as volta support for pnpm is not added yet.
|
||||
npx pnpm install
|
||||
pnpm test
|
||||
```
|
||||
|
||||
## Committing code
|
||||
### Docker
|
||||
|
||||
We make all changes via pull requests. As we have many pull requests from developers new to mermaid, the current approach is to have _knsv, Knut Sveidqvist_ as a main reviewer of changes and merging pull requests. More precisely like this:
|
||||
|
||||
- Large changes reviewed by knsv or other developer asked to review by knsv
|
||||
- Smaller low-risk changes like dependencies, documentation, etc. can be merged by active collaborators
|
||||
- Documentation (updates to the `package/mermaid/src/docs` folder is also allowed via direct commits)
|
||||
|
||||
To commit code, create a branch, let it start with the type like feature or bug followed by the issue number for reference and some describing text.
|
||||
|
||||
One example:
|
||||
|
||||
`feature/945_state_diagrams`
|
||||
|
||||
Another:
|
||||
|
||||
`bug/123_nasty_bug_branch`
|
||||
|
||||
## Committing documentation
|
||||
|
||||
Less strict here, it is OK to commit directly in the `develop` branch if you are a collaborator.
|
||||
|
||||
The documentation is written in **Markdown**. For more information about Markdown [see the GitHub Markdown help page](https://help.github.com/en/github/writing-on-github/basic-writing-and-formatting-syntax).
|
||||
|
||||
### Documentation source files are in [`/packages/mermaid/src/docs`](packages/mermaid/src/docs)
|
||||
|
||||
The source files for the project documentation are located in the [`/packages/mermaid/src/docs`](packages/mermaid/src/docs) directory. This is where you should make changes.
|
||||
The files under `/packages/mermaid/src/docs` are processed to generate the published documentation, and the resulting files are put into the `/docs` directory.
|
||||
|
||||
After editing files in the [`/packages/mermaid/src/docs`](packages/mermaid/src/docs) directory, be sure to run `pnpm install` and `pnpm run --filter mermaid docs:build` locally to build the `/docs` directory.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
classDef default fill:#fff,color:black,stroke:black
|
||||
|
||||
source["files in /packages/mermaid/src/docs\n(changes should be done here)"] -- automatic processing\nto generate the final documentation--> published["files in /docs\ndisplayed on the official documentation site"]
|
||||
If you are using docker and docker-compose, you have self-documented `run` bash script, which is a convenient alias for docker-compose commands:
|
||||
|
||||
```bash
|
||||
./run install # npx pnpm install
|
||||
./run test # pnpm test
|
||||
```
|
||||
|
||||
You can use `note`, `tip`, `warning` and `danger` in triple backticks to add a note, tip, warning or danger box.
|
||||
Do not use vitepress specific markdown syntax `::: warning` as it will not be processed correctly.
|
||||
## Testing
|
||||
|
||||
````
|
||||
```note
|
||||
Note content
|
||||
```bash
|
||||
# Run unit test
|
||||
pnpm test
|
||||
# Run unit test in watch mode
|
||||
pnpm test:watch
|
||||
# Run E2E test
|
||||
pnpm e2e
|
||||
# Debug E2E tests
|
||||
pnpm dev
|
||||
pnpm cypress:open # in another terminal
|
||||
```
|
||||
|
||||
```tip
|
||||
Tip content
|
||||
## Branch name format:
|
||||
|
||||
```text
|
||||
[feature | bug | chore | docs]/[issue number]_[short description using dashes ('-') or underscores ('_') instead of spaces]
|
||||
```
|
||||
|
||||
```warning
|
||||
Warning content
|
||||
```
|
||||
eg: `feature/2945_state-diagram-new-arrow-florbs`, `bug/1123_fix_random_ugly_red_text`
|
||||
|
||||
```danger
|
||||
Danger content
|
||||
```
|
||||
## Documentation
|
||||
|
||||
````
|
||||
Documentation is necessary for all non bugfix/refactoring changes.
|
||||
|
||||
Only make changes to files are in [`/packages/mermaid/src/docs`](packages/mermaid/src/docs)
|
||||
|
||||
**_DO NOT CHANGE FILES IN `/docs`_**
|
||||
|
||||
### The official documentation site
|
||||
|
||||
**[The mermaid documentation site](https://mermaid-js.github.io/mermaid/) is powered by [Vitepress](https://vitepress.vuejs.org/), a simple documentation site generator.**
|
||||
|
||||
If you want to preview the whole documentation site on your machine:
|
||||
|
||||
```sh
|
||||
cd packages/mermaid
|
||||
pnpm i
|
||||
pnpm docs:dev
|
||||
```
|
||||
|
||||
You can now build and serve the documentation site:
|
||||
|
||||
```sh
|
||||
pnpm docs:serve
|
||||
```
|
||||
|
||||
## Branching
|
||||
|
||||
Going forward we will use a git flow inspired approach to branching. So development is done in develop, to do the development in the develop.
|
||||
|
||||
Once development is done we branch a release branch from develop for testing.
|
||||
|
||||
Once the release happens we merge the release branch to master and kill the release branch.
|
||||
|
||||
This means... **branch off your pull request from develop**
|
||||
|
||||
## Content of a pull request
|
||||
|
||||
A new feature has been born. Great! But without the steps below it might just ... fade away ...
|
||||
|
||||
### **Add unit tests for the parsing part**
|
||||
|
||||
This is important so that, if someone else does a change to the grammar that does not know about this great feature, gets notified early on when that change breaks the parser. Another important aspect is that without proper parsing tests refactoring is pretty much impossible.
|
||||
|
||||
### **Add e2e tests**
|
||||
|
||||
This tests the rendering and visual appearance of the diagram. This ensures that the rendering of that feature in the e2e will be reviewed in the release process going forward. Less chance that it breaks!
|
||||
|
||||
To start working with the e2e tests, run `pnpm run dev` to start the dev server, after that start cypress by running `pnpm exec cypress open` in the mermaid folder.
|
||||
|
||||
The rendering tests are very straightforward to create. There is a function imgSnapshotTest. This function takes a diagram in text form, the mermaid options and renders that diagram in cypress.
|
||||
|
||||
When running in ci it will take a snapshot of the rendered diagram and compare it with the snapshot from last build and flag for review it if it differs.
|
||||
|
||||
This is what a rendering test looks like:
|
||||
|
||||
```javascript
|
||||
it('should render forks and joins', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
stateDiagram
|
||||
state fork_state <<fork>>
|
||||
[*] --> fork_state
|
||||
fork_state --> State2
|
||||
fork_state --> State3
|
||||
|
||||
state join_state <<join>>
|
||||
State2 --> join_state
|
||||
State3 --> join_state
|
||||
join_state --> State4
|
||||
State4 --> [*]
|
||||
`,
|
||||
{ logLevel: 0 }
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
```
|
||||
|
||||
### **Add documentation for it**
|
||||
|
||||
Finally, if it is not in the documentation, no one will know about it and then **no one will use it**. Wouldn't that be sad? With all the effort that was put into the feature?
|
||||
|
||||
The source files for documentation are in `/packages/mermaid/src/docs` and are written in markdown. Just pick the right section and start typing. See the [Committing Documentation](#committing-documentation) section for more about how the documentation is generated.
|
||||
|
||||
#### Adding to or changing the documentation organization
|
||||
|
||||
If you want to add a new section or change the organization (structure), then you need to make sure to **change the side navigation** in `mermaid/src/docs/.vitepress/config.js`.
|
||||
|
||||
When changes are committed and then released, they become part of the `master` branch and become part of the published documentation on https://mermaid-js.github.io/mermaid/
|
||||
|
||||
## Last words
|
||||
|
||||
Don't get daunted if it is hard in the beginning. We have a great community with only encouraging words. So if you get stuck, ask for help and hints in the slack forum. If you want to show off something good, show it off there.
|
||||
|
||||
[Join our slack community if you want closer contact!](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE)
|
||||
|
||||
![A superhero wishing you good luck](https://media.giphy.com/media/l49JHz7kJvl6MCj3G/giphy.gif)
|
||||
|
18
README.md
18
README.md
@ -27,7 +27,7 @@ Generate diagrams from markdown-like text.
|
||||
[![NPM](https://img.shields.io/npm/v/mermaid)](https://www.npmjs.com/package/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 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)
|
||||
[![Coverage Status](https://codecov.io/github/mermaid-js/mermaid/branch/develop/graph/badge.svg)](https://app.codecov.io/github/mermaid-js/mermaid/tree/develop)
|
||||
[![CDN Status](https://img.shields.io/jsdelivr/npm/hm/mermaid)](https://www.jsdelivr.com/package/npm/mermaid)
|
||||
[![NPM Downloads](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)
|
||||
@ -165,6 +165,13 @@ class Class10 {
|
||||
int id
|
||||
size()
|
||||
}
|
||||
namespace Namespace01 {
|
||||
class Class11
|
||||
class Class12 {
|
||||
int id
|
||||
size()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```mermaid
|
||||
@ -184,6 +191,13 @@ class Class10 {
|
||||
int id
|
||||
size()
|
||||
}
|
||||
namespace Namespace01 {
|
||||
class Class11
|
||||
class Class12 {
|
||||
int id
|
||||
size()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### State diagram [<a href="https://mermaid-js.github.io/mermaid/#/stateDiagram">docs</a> - <a href="https://mermaid.live/edit#pako:eNpdkEFvgzAMhf8K8nEqpYSNthx22Xbcqcexg0sCiZQQlDhIFeK_L8A6TfXp6fOz9ewJGssFVOAJSbwr7ByadGR1n8T6evpO0vQ1uZDSekOrXGFsPqJPO6q-2-imH8f_0TeHXm50lfelsAMjnEHFY6xpMdRAUhhRQxUlFy0GTTXU_RytYeAx-AdXZB1ULWovdoCB7OXWN1CRC-Ju-r3uz6UtchGHJqDbsPygU57iysb2reoWHpyOWBINvsqypb3vFMlw3TfWZF5xiY7keC6zkpUnZIUojwW-FAVvrvn51LLnvOXHQ84Q5nn-AVtLcwk">live editor</a>]
|
||||
@ -396,7 +410,7 @@ _Unfortunately you can not have a cake and eat it at the same time which in this
|
||||
|
||||
## 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.
|
||||
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
|
||||
|
||||
|
@ -27,7 +27,7 @@ Mermaid
|
||||
[![NPM](https://img.shields.io/npm/v/mermaid)](https://www.npmjs.com/package/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 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)
|
||||
[![Coverage Status](https://codecov.io/github/mermaid-js/mermaid/branch/develop/graph/badge.svg)](https://app.codecov.io/github/mermaid-js/mermaid/tree/develop)
|
||||
[![CDN Status](https://img.shields.io/jsdelivr/npm/hm/mermaid)](https://www.jsdelivr.com/package/npm/mermaid)
|
||||
[![NPM Downloads](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)
|
||||
|
@ -1,4 +1,3 @@
|
||||
// @ts-nocheck TODO: Fix TS
|
||||
import { MockedD3 } from '../packages/mermaid/src/tests/MockedD3.js';
|
||||
|
||||
export const select = function () {
|
||||
|
34
cSpell.json
34
cSpell.json
@ -5,11 +5,14 @@
|
||||
"acyclicer",
|
||||
"adamiecki",
|
||||
"alois",
|
||||
"aloisklink",
|
||||
"antiscript",
|
||||
"antlr",
|
||||
"appli",
|
||||
"applitools",
|
||||
"asciidoctor",
|
||||
"ashish",
|
||||
"ashishjain",
|
||||
"astah",
|
||||
"bbox",
|
||||
"bilkent",
|
||||
@ -23,6 +26,7 @@
|
||||
"classdef",
|
||||
"codedoc",
|
||||
"colour",
|
||||
"commitlint",
|
||||
"cpettitt",
|
||||
"customizability",
|
||||
"cuzon",
|
||||
@ -48,30 +52,42 @@
|
||||
"grav",
|
||||
"greywolf",
|
||||
"huynh",
|
||||
"huynhicode",
|
||||
"inkdrop",
|
||||
"jaoude",
|
||||
"jgreywolf",
|
||||
"jison",
|
||||
"jiti",
|
||||
"kaufmann",
|
||||
"khroma",
|
||||
"klemm",
|
||||
"klink",
|
||||
"knsv",
|
||||
"knut",
|
||||
"knutsveidqvist",
|
||||
"laganeckas",
|
||||
"linetype",
|
||||
"lintstagedrc",
|
||||
"logmsg",
|
||||
"lucida",
|
||||
"markdownish",
|
||||
"matthieu",
|
||||
"matthieumorel",
|
||||
"mdast",
|
||||
"mdbook",
|
||||
"mermaidjs",
|
||||
"mermerd",
|
||||
"mindaugas",
|
||||
"mindmap",
|
||||
"mindmaps",
|
||||
"mitigations",
|
||||
"mkdocs",
|
||||
"mmorel",
|
||||
"mult",
|
||||
"nextra",
|
||||
"orlandoni",
|
||||
"pathe",
|
||||
"pbrolin",
|
||||
"phpbb",
|
||||
"plantuml",
|
||||
"playfair",
|
||||
@ -83,6 +99,7 @@
|
||||
"rect",
|
||||
"rects",
|
||||
"redmine",
|
||||
"rehype",
|
||||
"roledescription",
|
||||
"sandboxed",
|
||||
"setupgraphviewbox",
|
||||
@ -90,9 +107,14 @@
|
||||
"sidharth",
|
||||
"sidharthv",
|
||||
"sphinxcontrib",
|
||||
"startx",
|
||||
"starty",
|
||||
"statediagram",
|
||||
"steph",
|
||||
"stopx",
|
||||
"stopy",
|
||||
"stylis",
|
||||
"subhash-halder",
|
||||
"substate",
|
||||
"sveidqvist",
|
||||
"swimm",
|
||||
@ -101,16 +123,23 @@
|
||||
"textlength",
|
||||
"treemap",
|
||||
"ts-nocheck",
|
||||
"tsdoc",
|
||||
"tuleap",
|
||||
"tylerlong",
|
||||
"ugge",
|
||||
"unist",
|
||||
"unocss",
|
||||
"upvoting",
|
||||
"valign",
|
||||
"verdana",
|
||||
"viewports",
|
||||
"vinod",
|
||||
"visio",
|
||||
"vitepress",
|
||||
"vueuse",
|
||||
"xlink",
|
||||
"yash"
|
||||
"yash",
|
||||
"zenuml"
|
||||
],
|
||||
"patterns": [
|
||||
{ "name": "Markdown links", "pattern": "\\((.*)\\)", "description": "" },
|
||||
@ -150,6 +179,7 @@
|
||||
],
|
||||
"ignorePaths": [
|
||||
"packages/mermaid/src/docs/CHANGELOG.md",
|
||||
"packages/mermaid/src/docs/.vitepress/redirect.ts"
|
||||
"packages/mermaid/src/docs/.vitepress/redirect.ts",
|
||||
"packages/mermaid/src/docs/.vitepress/contributor-names.json"
|
||||
]
|
||||
}
|
||||
|
6
codecov.yaml
Normal file
6
codecov.yaml
Normal file
@ -0,0 +1,6 @@
|
||||
comment:
|
||||
layout: 'reach, diff, flags, files'
|
||||
behavior: default
|
||||
require_changes: false # if true: only post the comment if coverage changes
|
||||
require_base: no # [yes :: must have a base report to post]
|
||||
require_head: yes # [yes :: must have a head report to post]
|
@ -2,12 +2,14 @@
|
||||
|
||||
const { defineConfig } = require('cypress');
|
||||
const { addMatchImageSnapshotPlugin } = require('cypress-image-snapshot/plugin');
|
||||
const coverage = require('@cypress/code-coverage/task');
|
||||
|
||||
module.exports = defineConfig({
|
||||
projectId: 'n2sma2',
|
||||
e2e: {
|
||||
specPattern: 'cypress/integration/**/*.{js,jsx,ts,tsx}',
|
||||
setupNodeEvents(on, config) {
|
||||
coverage(on, config);
|
||||
addMatchImageSnapshotPlugin(on, config);
|
||||
// copy any needed variables from process.env to config.env
|
||||
config.env.useAppli = process.env.USE_APPLI ? true : false;
|
||||
|
@ -60,7 +60,7 @@ export const renderGraph = (graphStr, options, api) => {
|
||||
openURLAndVerifyRendering(url, options);
|
||||
};
|
||||
|
||||
const openURLAndVerifyRendering = (url, options, validation = undefined) => {
|
||||
export const openURLAndVerifyRendering = (url, options, validation = undefined) => {
|
||||
const useAppli = Cypress.env('useAppli');
|
||||
const name = (options.name || cy.state('runnable').fullTitle()).replace(/\s+/g, '-');
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { urlSnapshotTest } from '../../helpers/util.js';
|
||||
import { urlSnapshotTest, openURLAndVerifyRendering } from '../../helpers/util.js';
|
||||
|
||||
describe('CSS injections', () => {
|
||||
it('should not allow CSS injections outside of the diagram', () => {
|
||||
@ -13,4 +13,11 @@ describe('CSS injections', () => {
|
||||
flowchart: { htmlLabels: false },
|
||||
});
|
||||
});
|
||||
it('should not allow manipulating styletags using arrowheads', () => {
|
||||
openURLAndVerifyRendering('http://localhost:9000/xss23-css.html', {
|
||||
logLevel: 1,
|
||||
arrowMarkerAbsolute: false,
|
||||
flowchart: { htmlLabels: true },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -548,4 +548,18 @@ class C13["With Città foreign language"]
|
||||
`
|
||||
);
|
||||
});
|
||||
it('should add classes namespaces', function () {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
classDiagram
|
||||
namespace Namespace1 {
|
||||
class C1
|
||||
class C2
|
||||
}
|
||||
C1 --> C2
|
||||
class C3
|
||||
class C4
|
||||
`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -684,6 +684,20 @@ A --> B
|
||||
{ titleTopMargin: 0 }
|
||||
);
|
||||
});
|
||||
it('elk: should include classes on the edges', () => {
|
||||
renderGraph(
|
||||
`flowchart-elk TD
|
||||
A --> B --> C --> D
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg').should((svg) => {
|
||||
const edges = svg.querySelectorAll('.edges > path');
|
||||
edges.forEach((edge) => {
|
||||
expect(edge).to.have.class('flowchart-link');
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('Markdown strings flowchart-elk (#4220)', () => {
|
||||
describe('html labels', () => {
|
||||
it('With styling and classes', () => {
|
||||
|
@ -172,7 +172,7 @@ describe('Flowchart v2', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('52: handle nested subgraphs in several levels', () => {
|
||||
it('52: handle nested subgraphs in several levels.', () => {
|
||||
imgSnapshotTest(
|
||||
`flowchart TB
|
||||
b-->B
|
||||
|
@ -1,13 +0,0 @@
|
||||
import { imgSnapshotTest } from '../../helpers/util.js';
|
||||
|
||||
describe('Sequencediagram', () => {
|
||||
it('should render a simple info diagrams', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
info
|
||||
showInfo
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
});
|
11
cypress/integration/rendering/info.spec.ts
Normal file
11
cypress/integration/rendering/info.spec.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { imgSnapshotTest } from '../../helpers/util.js';
|
||||
|
||||
describe('info diagram', () => {
|
||||
it('should handle an info definition', () => {
|
||||
imgSnapshotTest(`info`);
|
||||
});
|
||||
|
||||
it('should handle an info definition with showInfo', () => {
|
||||
imgSnapshotTest(`info showInfo`);
|
||||
});
|
||||
});
|
@ -52,6 +52,17 @@ root[A root with a long text that wraps to keep the node size in check]
|
||||
);
|
||||
});
|
||||
|
||||
it('a root with wrapping text and long words that exceed width', () => {
|
||||
imgSnapshotTest(
|
||||
`mindmap
|
||||
root[A few smaller words but then averylongsetofcharacterswithoutwhitespacetoseparate that we expect to wrapontonextlinesandnotexceedwidthparameters]
|
||||
`,
|
||||
{},
|
||||
undefined,
|
||||
shouldHaveRoot
|
||||
);
|
||||
});
|
||||
|
||||
it('a root with an icon', () => {
|
||||
imgSnapshotTest(
|
||||
`mindmap
|
||||
|
163
cypress/integration/rendering/quadrantChart.spec.js
Normal file
163
cypress/integration/rendering/quadrantChart.spec.js
Normal file
@ -0,0 +1,163 @@
|
||||
import { imgSnapshotTest, renderGraph } from '../../helpers/util.js';
|
||||
|
||||
describe('Quadrant Chart', () => {
|
||||
it('should render if only chart type is provided', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
quadrantChart
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render a complete quadrant chart', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
quadrantChart
|
||||
title Reach and engagement of campaigns
|
||||
x-axis Low Reach --> High Reach
|
||||
y-axis Low Engagement --> High Engagement
|
||||
quadrant-1 We should expand
|
||||
quadrant-2 Need to promote
|
||||
quadrant-3 Re-evaluate
|
||||
quadrant-4 May be improved
|
||||
Campaign A: [0.3, 0.6]
|
||||
Campaign B: [0.45, 0.23]
|
||||
Campaign C: [0.57, 0.69]
|
||||
Campaign D: [0.78, 0.34]
|
||||
Campaign E: [0.40, 0.34]
|
||||
Campaign F: [0.35, 0.78]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render without points', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
quadrantChart
|
||||
title Reach and engagement of campaigns
|
||||
x-axis Low Reach --> High Reach
|
||||
y-axis Low Engagement --> High Engagement
|
||||
quadrant-1 We should expand
|
||||
quadrant-2 Need to promote
|
||||
quadrant-3 Re-evaluate
|
||||
quadrant-4 May be improved
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should able to render y-axix on right side', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
%%{init: {"quadrantChart": {"yAxisPosition": "right"}}}%%
|
||||
quadrantChart
|
||||
title Reach and engagement of campaigns
|
||||
x-axis Low Reach --> High Reach
|
||||
y-axis Low Engagement --> High Engagement
|
||||
quadrant-1 We should expand
|
||||
quadrant-2 Need to promote
|
||||
quadrant-3 Re-evaluate
|
||||
quadrant-4 May be improved
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should able to render x-axix on bottom', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
%%{init: {"quadrantChart": {"xAxisPosition": "bottom"}}}%%
|
||||
quadrantChart
|
||||
title Reach and engagement of campaigns
|
||||
x-axis Low Reach --> High Reach
|
||||
y-axis Low Engagement --> High Engagement
|
||||
quadrant-1 We should expand
|
||||
quadrant-2 Need to promote
|
||||
quadrant-3 Re-evaluate
|
||||
quadrant-4 May be improved
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should able to render x-axix on bottom and y-axis on right', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
%%{init: {"quadrantChart": {"xAxisPosition": "bottom", "yAxisPosition": "right"}}}%%
|
||||
quadrantChart
|
||||
title Reach and engagement of campaigns
|
||||
x-axis Low Reach --> High Reach
|
||||
y-axis Low Engagement --> High Engagement
|
||||
quadrant-1 We should expand
|
||||
quadrant-2 Need to promote
|
||||
quadrant-3 Re-evaluate
|
||||
quadrant-4 May be improved
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should render without title', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
quadrantChart
|
||||
x-axis Low Reach --> High Reach
|
||||
y-axis Low Engagement --> High Engagement
|
||||
quadrant-1 We should expand
|
||||
quadrant-2 Need to promote
|
||||
quadrant-3 Re-evaluate
|
||||
quadrant-4 May be improved
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should use all the config', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
%%{init: {"quadrantChart": {"chartWidth": 600, "chartHeight": 600, "titlePadding": 20, "titleFontSize": 10, "quadrantPadding": 20, "quadrantTextTopPadding": 40, "quadrantLabelFontSize": 20, "quadrantInternalBorderStrokeWidth": 3, "quadrantExternalBorderStrokeWidth": 5, "xAxisLabelPadding": 20, "xAxisLabelFontSize": 20, "yAxisLabelPadding": 20, "yAxisLabelFontSize": 20, "pointTextPadding": 20, "pointLabelFontSize": 20, "pointRadius": 10 }}}%%
|
||||
quadrantChart
|
||||
title Reach and engagement of campaigns
|
||||
x-axis Low Reach --> High Reach
|
||||
y-axis Low Engagement --> High Engagement
|
||||
quadrant-1 We should expand
|
||||
quadrant-2 Need to promote
|
||||
quadrant-3 Re-evaluate
|
||||
quadrant-4 May be improved
|
||||
Campaign A: [0.3, 0.6]
|
||||
Campaign B: [0.45, 0.23]
|
||||
Campaign C: [0.57, 0.69]
|
||||
Campaign D: [0.78, 0.34]
|
||||
Campaign E: [0.40, 0.34]
|
||||
Campaign F: [0.35, 0.78]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
it('should use all the theme variable', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
%%{init: {"themeVariables": {"quadrant1Fill": "#b4dcff","quadrant2Fill": "#fef0ff", "quadrant3Fill": "#fffaf0", "quadrant4Fill": "#f0fff2", "quadrant1TextFill": "#ff0000", "quadrant2TextFill": "#2d00df", "quadrant3TextFill": "#00ffda", "quadrant4TextFill": "#e68300", "quadrantPointFill": "#0149ff", "quadrantPointTextFill": "#dc00ff", "quadrantXAxisTextFill": "#ffb500", "quadrantYAxisTextFill": "#fae604", "quadrantInternalBorderStrokeFill": "#3636f2", "quadrantExternalBorderStrokeFill": "#ff1010", "quadrantTitleFill": "#00ea19"} }}%%
|
||||
quadrantChart
|
||||
title Reach and engagement of campaigns
|
||||
x-axis Low Reach --> High Reach
|
||||
y-axis Low Engagement --> High Engagement
|
||||
quadrant-1 We should expand
|
||||
quadrant-2 Need to promote
|
||||
quadrant-3 Re-evaluate
|
||||
quadrant-4 May be improved
|
||||
Campaign A: [0.3, 0.6]
|
||||
Campaign B: [0.45, 0.23]
|
||||
Campaign C: [0.57, 0.69]
|
||||
Campaign D: [0.78, 0.34]
|
||||
Campaign E: [0.40, 0.34]
|
||||
Campaign F: [0.35, 0.78]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
cy.get('svg');
|
||||
});
|
||||
});
|
@ -88,6 +88,16 @@ context('Sequence diagram', () => {
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('should handle empty lines', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice->>John: Hello John<br/>
|
||||
John-->>Alice: Great<br/><br/>day!
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('should handle line breaks and wrap annotations', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
@ -123,6 +133,29 @@ context('Sequence diagram', () => {
|
||||
}
|
||||
);
|
||||
});
|
||||
it('should render a sequence diagram with par_over', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
participant John
|
||||
par_over Section title
|
||||
Alice ->> Bob: Message 1<br>Second line
|
||||
Bob ->> John: Message 2
|
||||
end
|
||||
par_over Two line<br>section title
|
||||
Note over Alice: Alice note
|
||||
Note over Bob: Bob note<br>Second line
|
||||
Note over John: John note
|
||||
end
|
||||
par_over Mixed section
|
||||
Alice ->> Bob: Message 1
|
||||
Note left of Bob: Alice/Bob Note
|
||||
end
|
||||
`
|
||||
);
|
||||
});
|
||||
context('font settings', () => {
|
||||
it('should render different note fonts when configured', () => {
|
||||
imgSnapshotTest(
|
||||
|
19
cypress/integration/rendering/zenuml.spec.js
Normal file
19
cypress/integration/rendering/zenuml.spec.js
Normal file
@ -0,0 +1,19 @@
|
||||
import { imgSnapshotTest } from '../../helpers/util.js';
|
||||
|
||||
describe('Zen UML', () => {
|
||||
it('Basic Zen UML diagram', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
zenuml
|
||||
A.method() {
|
||||
if(x) {
|
||||
B.method() {
|
||||
selfCall() { return X }
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
});
|
@ -1,23 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>info below</h1>
|
||||
<pre class="mermaid">
|
||||
info
|
||||
</pre>
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
mermaid.initialize({
|
||||
theme: 'forest',
|
||||
// themeCSS: '.node rect { fill: red; }',
|
||||
logLevel: 3,
|
||||
flowchart: { curve: 'linear' },
|
||||
gantt: { axisFormat: '%m/%d/%Y' },
|
||||
sequence: { actorMargin: 50 },
|
||||
// sequenceDiagram: { actorMargin: 300 } // deprecated
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -42,368 +42,86 @@
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<pre class="mermaid2" style="width: 50%">
|
||||
flowchart LR
|
||||
subgraph one
|
||||
direction LR
|
||||
A[myClass1] --> B[default]
|
||||
subgraph two
|
||||
direction BT
|
||||
C[myClass2] --> D[default]
|
||||
end
|
||||
end
|
||||
<pre class="mermaid" style="width: 50%">
|
||||
%%{init: {"flowchart": {"htmlLabels": true}} }%%
|
||||
flowchart LR
|
||||
b("`The dog in **the** hog.(1).. a a a a *very long text* about it
|
||||
Word!
|
||||
|
||||
Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words. Another line with many, many words.`") --apa--> c
|
||||
|
||||
</pre
|
||||
>
|
||||
<pre class="mermaid" style="width: 50%">
|
||||
classDiagram-v2
|
||||
|
||||
classA -- classB : Inheritance
|
||||
classA -- classC : link
|
||||
classC -- classD : link
|
||||
classB -- classD
|
||||
</pre>
|
||||
<pre class="mermaid2" style="width: 50%">
|
||||
flowchart LR
|
||||
classDef aPID stroke:#4e4403,fill:#fdde29,color:#4e4403,rx:5px,ry:5px;
|
||||
classDef crm stroke:#333333,fill:#DCDCDC,color:#333333,rx:5px,ry:5px;
|
||||
classDef type stroke:#502604,fill:#FAB565,color:#502604,rx:20px,ry:20px;;
|
||||
|
||||
O0("Joe")
|
||||
class O0 aPID;
|
||||
|
||||
O1("Person")
|
||||
class O1 crm;
|
||||
O0 -- has type -->O1["Person"]
|
||||
|
||||
O2("aat:300411314")
|
||||
class O2 type;
|
||||
click O2 function "Sorry the newline html tags are not being processed correctly<br/> So all of this appears on the <br/> same line."
|
||||
O0 -- has type -->O2["Bug"]
|
||||
click O0 function "Lots of great info about Joe<br>Lots of great info about Joe<br>burt<br>fred";
|
||||
<pre class="mermaid" style="width: 50%">
|
||||
sequenceDiagram
|
||||
Alice->>Bob: Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
|
||||
loop Loopy
|
||||
Bob->>Alice: Pasten
|
||||
end
|
||||
</pre>
|
||||
<pre class="mermaid2" style="width: 50%">
|
||||
flowchart TD
|
||||
subgraph test
|
||||
direction TB
|
||||
subgraph test2
|
||||
direction LR
|
||||
F --> D
|
||||
end
|
||||
subgraph test3
|
||||
direction TB
|
||||
G --> H
|
||||
end
|
||||
end
|
||||
<pre class="mermaid" style="width: 50%">
|
||||
%%{init: {"flowchart": {"htmlLabels": false}} }%%
|
||||
flowchart LR
|
||||
b("`The dog in **the** hog.(1)
|
||||
NL`") --"`1o **bold**`"--> c[new strings svg labels]
|
||||
</pre>
|
||||
<pre class="mermaid2" style="width: 50%">
|
||||
flowchart TD
|
||||
|
||||
release-branch[Create Release Branch]:::relClass
|
||||
develop-branch[Update Develop Branch]:::relClass
|
||||
github-release-draft[GitHub Release Draft]:::relClass
|
||||
trigger-pipeline[Trigger Jenkins pipeline]:::fixClass
|
||||
github-release[GitHub Release]:::postClass
|
||||
|
||||
build-ready --> release-branch
|
||||
build-ready --> develop-branch
|
||||
release-branch --> jenkins-release-build
|
||||
jenkins-release-build --> github-release-draft
|
||||
jenkins-release-build --> install-release
|
||||
install-release --> verify-release
|
||||
jenkins-release-build --> announce
|
||||
github-release-draft --> github-release
|
||||
verify-release --> verify-check
|
||||
verify-check -- Yes --> github-release
|
||||
verify-check -- No --> release-fix
|
||||
release-fix --> release-branch-pr
|
||||
verify-check -- No --> delete-artifacts
|
||||
release-branch-pr --> trigger-pipeline
|
||||
delete-artifacts --> trigger-pipeline
|
||||
trigger-pipeline --> jenkins-release-build
|
||||
|
||||
|
||||
<pre class="mermaid" style="width: 50%">
|
||||
%%{init: {"flowchart": {"htmlLabels": true}} }%%
|
||||
flowchart LR
|
||||
b("`The dog in **the** hog.(1)
|
||||
NL`") --"`1o **bold**`"--> c[new strings html labels]
|
||||
</pre>
|
||||
<pre class="mermaid2" style="width: 50%">
|
||||
flowchart LR
|
||||
a["<strong>Haiya</strong>"]===>b
|
||||
<pre class="mermaid" style="width: 50%">
|
||||
%%{init: {"flowchart": {"htmlLabels": true}} }%%
|
||||
flowchart LR
|
||||
b("The dog in the hog.(1)\nNL") --"1o bold"--> c[old strings svg labels]
|
||||
</pre>
|
||||
<pre class="mermaid2" style="width: 50%">
|
||||
flowchart TD
|
||||
A --> B
|
||||
A --> C
|
||||
B --> C
|
||||
</pre>
|
||||
<pre class="mermaid2" style="width: 50%">
|
||||
flowchart TD
|
||||
A([stadium shape test])
|
||||
A -->|Get money| B([Go shopping])
|
||||
B --> C([Let me think...<br />Do I want something for work,<br />something to spend every free second with,<br />or something to get around?])
|
||||
C -->|One| D([Laptop])
|
||||
C -->|Two| E([iPhone])
|
||||
C -->|Three| F([Car<br/>wroom wroom])
|
||||
click A "index.html#link-clicked" "link test"
|
||||
click B testClick "click test"
|
||||
classDef someclass fill:#f96;
|
||||
class A someclass;
|
||||
class C someclass;
|
||||
</pre>
|
||||
<pre class="mermaid2" style="width: 50%">
|
||||
sequenceDiagram
|
||||
title: My Sequence Diagram Title
|
||||
accTitle: My Acc Sequence Diagram
|
||||
accDescr: My Sequence Diagram Description
|
||||
|
||||
Alice->>John: Hello John, how are you?
|
||||
John-->>Alice: Great!
|
||||
Alice-)John: See you later!
|
||||
</pre>
|
||||
<pre class="mermaid2" style="width: 50%">
|
||||
graph TD
|
||||
A -->|000| B
|
||||
B -->|111| C
|
||||
|
||||
linkStyle 1 stroke:#ff3,stroke-width:4px,color:red;
|
||||
</pre>
|
||||
<pre class="mermaid2" style="width: 100%">
|
||||
journey
|
||||
accTitle: My User Journey Diagram
|
||||
accDescr: My User Journey Diagram Description
|
||||
|
||||
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: 5: Me
|
||||
</pre>
|
||||
<pre class="mermaid2" style="width: 100%">
|
||||
info
|
||||
</pre>
|
||||
<pre class="mermaid2" style="width: 100%">
|
||||
requirementDiagram
|
||||
accTitle: My req Diagram
|
||||
accDescr: My req Diagram Description
|
||||
|
||||
requirement test_req {
|
||||
id: 1
|
||||
text: the test text.
|
||||
risk: high
|
||||
verifymethod: test
|
||||
}
|
||||
|
||||
functionalRequirement test_req2 {
|
||||
id: 1.1
|
||||
text: the second test text.
|
||||
risk: low
|
||||
verifymethod: inspection
|
||||
}
|
||||
|
||||
performanceRequirement test_req3 {
|
||||
id: 1.2
|
||||
text: the third test text.
|
||||
risk: medium
|
||||
verifymethod: demonstration
|
||||
}
|
||||
|
||||
element test_entity {
|
||||
type: simulation
|
||||
}
|
||||
|
||||
element test_entity2 {
|
||||
type: word doc
|
||||
docRef: reqs/test_entity
|
||||
}
|
||||
|
||||
|
||||
test_entity - satisfies -> test_req2
|
||||
test_req - traces -> test_req2
|
||||
test_req - contains -> test_req3
|
||||
test_req <- copies - test_entity2
|
||||
</pre>
|
||||
<pre class="mermaid2" style="width: 100%">
|
||||
gantt
|
||||
dateFormat YYYY-MM-DD
|
||||
title Adding GANTT diagram functionality to mermaid
|
||||
excludes weekends
|
||||
%% (`excludes` accepts specific dates in YYYY-MM-DD format, days of the week ("sunday") or "weekends", but not the word "weekdays".)
|
||||
|
||||
section A section
|
||||
Completed task :done, des1, 2014-01-06,2014-01-08
|
||||
Active task :active, des2, 2014-01-09, 3d
|
||||
Future task : des3, after des2, 5d
|
||||
Future task2 : des4, after des3, 5d
|
||||
|
||||
section Critical tasks
|
||||
Completed task in the critical line :crit, done, 2014-01-06,24h
|
||||
Implement parser and jison :crit, done, after des1, 2d
|
||||
Create tests for parser :crit, active, 3d
|
||||
Future task in critical line :crit, 5d
|
||||
Create tests for renderer :2d
|
||||
Add to mermaid :1d
|
||||
Functionality added :milestone, 2014-01-25, 0d
|
||||
|
||||
section Documentation
|
||||
Describe gantt syntax :active, a1, after des1, 3d
|
||||
Add gantt diagram to demo page :after a1 , 20h
|
||||
Add another diagram to demo page :doc1, after a1 , 48h
|
||||
|
||||
section Last section
|
||||
Describe gantt syntax :after doc1, 3d
|
||||
Add gantt diagram to demo page :20h
|
||||
Add another diagram to demo page :48h
|
||||
</pre>
|
||||
<pre class="mermaid2" style="width: 100%">
|
||||
stateDiagram
|
||||
state Active {
|
||||
Idle
|
||||
}
|
||||
Inactive --> Idle: ACT
|
||||
Active --> Active: LOG
|
||||
</pre>
|
||||
<pre class="mermaid2" style="width: 100%">
|
||||
flowchart TB
|
||||
accTitle: My flowchart
|
||||
accDescr: My flowchart Description
|
||||
subgraph One
|
||||
a1-->a2-->a3
|
||||
end
|
||||
</pre>
|
||||
<pre class="mermaid2" style="width: 100%">
|
||||
sequenceDiagram
|
||||
A ->> B: 1
|
||||
rect rgb(204, 0, 102)
|
||||
break yes
|
||||
rect rgb(0, 204, 204)
|
||||
C ->> C: 0
|
||||
end
|
||||
end
|
||||
end
|
||||
B ->> A: Return
|
||||
</pre>
|
||||
<pre class="mermaid2" style="width: 100%">
|
||||
classDiagram
|
||||
accTitle: My class diagram
|
||||
accDescr: My class diagram Description
|
||||
Class01 <|-- AveryLongClass : Cool
|
||||
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()
|
||||
}
|
||||
</pre>
|
||||
<pre class="mermaid2" style="width: 100%">
|
||||
%%{init: {'config': {'wrap': true }}}%%
|
||||
sequenceDiagram
|
||||
participant A as Extremely utterly long line of longness which had previously overflown the actor box as it is much longer than what it should be
|
||||
A->>Bob: Hola
|
||||
Bob-->A: Pasten !
|
||||
</pre>
|
||||
<pre class="mermaid2" style="width: 100%">
|
||||
gitGraph
|
||||
commit id: "ZERO"
|
||||
branch develop
|
||||
commit id:"A"
|
||||
checkout main
|
||||
commit id:"ONE"
|
||||
checkout develop
|
||||
commit id:"B"
|
||||
branch featureA
|
||||
commit id:"FIX"
|
||||
commit id: "FIX-2"
|
||||
checkout main
|
||||
commit id:"TWO"
|
||||
cherry-pick id:"A"
|
||||
commit id:"THREE"
|
||||
cherry-pick id:"FIX"
|
||||
checkout develop
|
||||
commit id:"C"
|
||||
merge featureA
|
||||
</pre>
|
||||
<pre class="mermaid2" style="width: 100%">
|
||||
flowchart TD
|
||||
A[Christmas] -->|Get money| B(Go shopping)
|
||||
B --> C{Let me think}
|
||||
C -->|One| D[Laptop]
|
||||
C -->|Two| E[iPhone]
|
||||
C -->|Three| F[fa:fa-car Car]
|
||||
</pre>
|
||||
<pre class="mermaid2" style="width: 100%">
|
||||
classDiagram
|
||||
Animal "1" <|-- Duck
|
||||
Animal <|-- Fish
|
||||
Animal <--o Zebra
|
||||
Animal : +int age
|
||||
Animal : +String gender
|
||||
Animal: +isMammal()
|
||||
Animal: +mate()
|
||||
class Duck{
|
||||
+String beakColor
|
||||
+swim()
|
||||
+quack()
|
||||
}
|
||||
class Fish{
|
||||
-int sizeInFeet
|
||||
-canEat()
|
||||
}
|
||||
class Zebra{
|
||||
+bool is_wild
|
||||
+run()
|
||||
}
|
||||
</pre>
|
||||
<pre class="mermaid2" style="width: 100%">
|
||||
erDiagram
|
||||
CAR ||--o{ NAMED-DRIVER : allows
|
||||
CAR {
|
||||
string registrationNumber
|
||||
string make
|
||||
string model
|
||||
}
|
||||
PERSON ||--o{ NAMED-DRIVER : is
|
||||
PERSON {
|
||||
string firstName
|
||||
string lastName
|
||||
int age
|
||||
}
|
||||
</pre>
|
||||
|
||||
<!-- <script src="./mermaid.js"></script> -->
|
||||
<script src="./mermaid.js"></script>
|
||||
<script>
|
||||
<script type="module">
|
||||
// import mindmap from '../../packages/mermaid-mindmap/src/detector';
|
||||
// import example from '../../packages/mermaid-example-diagram/src/mermaid-example-diagram.core.mjs';
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
// await mermaid.registerExternalDiagrams([example]);
|
||||
mermaid.parseError = function (err, hash) {
|
||||
// console.error('Mermaid error: ', err);
|
||||
};
|
||||
mermaid.initialize({
|
||||
maxTextSize: 900000,
|
||||
// theme: 'forest',
|
||||
startOnLoad: true,
|
||||
securityLevel: 'loose',
|
||||
logLevel: 0,
|
||||
fontFamily: 'courier',
|
||||
flowchart: {
|
||||
// curve: 'curveLinear',
|
||||
useMaxWidth: true,
|
||||
htmlLabels: false,
|
||||
fontFamily: 'courier',
|
||||
// defaultRenderer: 'elk',
|
||||
useMaxWidth: false,
|
||||
// htmlLabels: false,
|
||||
htmlLabels: true,
|
||||
},
|
||||
lazyLoadedDiagrams: ['./mermaid-mindmap-detector.js'],
|
||||
// htmlLabels: false,
|
||||
gantt: {
|
||||
useMaxWidth: false,
|
||||
},
|
||||
sequence: {
|
||||
wrap: true,
|
||||
},
|
||||
useMaxWidth: false,
|
||||
});
|
||||
function callback() {
|
||||
alert('It worked');
|
||||
}
|
||||
|
||||
function clickByFlow(elemName) {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'created-by-click';
|
||||
div.style = 'padding: 20px; background: green; color: white;';
|
||||
div.innerText = 'Clicked By Flow';
|
||||
|
||||
document.getElementsByTagName('body')[0].appendChild(div);
|
||||
}
|
||||
|
||||
mermaid.parseError = function (err, hash) {
|
||||
console.error('In parse error:');
|
||||
console.error(err);
|
||||
};
|
||||
// mermaid.test1('first_slow', 1200).then((r) => console.info(r));
|
||||
// mermaid.test1('second_fast', 200).then((r) => console.info(r));
|
||||
// mermaid.test1('third_fast', 200).then((r) => console.info(r));
|
||||
// mermaid.test1('forth_slow', 1200).then((r) => console.info(r));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,5 +1,6 @@
|
||||
import mermaid2 from './mermaid.esm.mjs';
|
||||
import externalExample from '../../packages/mermaid-example-diagram/dist/mermaid-example-diagram.core.mjs';
|
||||
import zenUml from '../../packages/mermaid-zenuml/dist/mermaid-zenuml.core.mjs';
|
||||
|
||||
function b64ToUtf8(str) {
|
||||
return decodeURIComponent(escape(window.atob(str)));
|
||||
@ -44,7 +45,7 @@ const contentLoaded = async function () {
|
||||
document.getElementsByTagName('body')[0].appendChild(div);
|
||||
}
|
||||
|
||||
await mermaid2.registerExternalDiagrams([externalExample]);
|
||||
await mermaid2.registerExternalDiagrams([externalExample, zenUml]);
|
||||
mermaid2.initialize(graphObj.mermaid);
|
||||
await mermaid2.run();
|
||||
}
|
||||
|
85
cypress/platform/xss23-css.html
Normal file
85
cypress/platform/xss23-css.html
Normal file
@ -0,0 +1,85 @@
|
||||
<html>
|
||||
<head>
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<style>
|
||||
body {
|
||||
/* background: rgb(221, 208, 208); */
|
||||
/* background:#333; */
|
||||
font-family: 'Arial';
|
||||
/* font-size: 18px !important; */
|
||||
}
|
||||
h1 {
|
||||
color: grey;
|
||||
}
|
||||
.mermaid2 {
|
||||
display: none;
|
||||
}
|
||||
.mermaid svg {
|
||||
/* font-size: 18px !important; */
|
||||
}
|
||||
.malware {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 150px;
|
||||
background: red;
|
||||
color: black;
|
||||
display: flex;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family: monospace;
|
||||
font-size: 72px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div>Security check</div>
|
||||
<div class="flex">
|
||||
<div id="diagram" class="mermaid"></div>
|
||||
<div id="graph-div"></div>
|
||||
<div id="res" class=""></div>
|
||||
</div>
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
mermaid.parseError = function (err, hash) {
|
||||
// console.error('Mermaid error: ', err);
|
||||
};
|
||||
mermaid.initialize({
|
||||
theme: 'base',
|
||||
startOnLoad: false,
|
||||
flowcharts: { htmlLabels: true },
|
||||
});
|
||||
function callback() {
|
||||
alert('It worked');
|
||||
}
|
||||
function xssAttack() {
|
||||
const div = document.createElement('div');
|
||||
div.id = 'the-malware';
|
||||
div.className = 'malware';
|
||||
div.innerHTML = 'XSS Succeeded';
|
||||
document.getElementsByTagName('body')[0].appendChild(div);
|
||||
throw new Error('XSS Succeeded');
|
||||
}
|
||||
|
||||
let diagram = `graph TD
|
||||
A[["a marker-end=#quot;url(<s title='#<style>*{background:red}</style>'>b"]]
|
||||
`;
|
||||
const el = document.querySelector('#graph-div');
|
||||
console.log(diagram);
|
||||
const { svg } = await mermaid.render('graph-div', diagram);
|
||||
document.querySelector('#res').innerHTML = svg;
|
||||
window.rendered = true;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -13,8 +13,8 @@
|
||||
// https://on.cypress.io/configuration
|
||||
// ***********************************************************
|
||||
|
||||
import '@cypress/code-coverage/support';
|
||||
import '@applitools/eyes-cypress/commands';
|
||||
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import './commands';
|
||||
|
||||
|
@ -45,6 +45,9 @@
|
||||
<li>
|
||||
<h2><a href="./git.html">Git</a></h2>
|
||||
</li>
|
||||
<li>
|
||||
<h2><a href="./info.html">Info</a></h2>
|
||||
</li>
|
||||
<li>
|
||||
<h2><a href="./journey.html">Journey</a></h2>
|
||||
</li>
|
||||
@ -54,6 +57,9 @@
|
||||
<li>
|
||||
<h2><a href="./pie.html">Pie</a></h2>
|
||||
</li>
|
||||
<li>
|
||||
<h2><a href="./quadrantchart.html">Quadrant charts</a></h2>
|
||||
</li>
|
||||
<li>
|
||||
<h2><a href="./requirements.html">Requirements</a></h2>
|
||||
</li>
|
||||
@ -63,6 +69,12 @@
|
||||
<li>
|
||||
<h2><a href="./state.html">State</a></h2>
|
||||
</li>
|
||||
<li>
|
||||
<h2><a href="./timeline.html">Timeline</a></h2>
|
||||
</li>
|
||||
<li>
|
||||
<h2><a href="./zenuml.html">ZenUML</a></h2>
|
||||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
|
35
demos/info.html
Normal file
35
demos/info.html
Normal file
@ -0,0 +1,35 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>Mermaid Quick Test Page</title>
|
||||
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=" />
|
||||
<style>
|
||||
div.mermaid {
|
||||
font-family: 'Courier New', Courier, monospace !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Info diagram demos</h1>
|
||||
<pre class="mermaid">
|
||||
info
|
||||
</pre>
|
||||
|
||||
<hr />
|
||||
<pre class="mermaid">
|
||||
info showInfo
|
||||
</pre>
|
||||
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
mermaid.initialize({
|
||||
theme: 'forest',
|
||||
logLevel: 3,
|
||||
securityLevel: 'loose',
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
55
demos/quadrantchart.html
Normal file
55
demos/quadrantchart.html
Normal file
@ -0,0 +1,55 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>Mermaid Quick Test Page</title>
|
||||
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=" />
|
||||
<style>
|
||||
div.mermaid {
|
||||
/* font-family: 'trebuchet ms', verdana, arial; */
|
||||
font-family: 'Courier New', Courier, monospace !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Quadrant chart demos</h1>
|
||||
<pre class="mermaid">
|
||||
%%{init: {"quadrantChart": {"quadrantPadding": 10}, "theme": "forest", "themeVariables": {"quadrant1TextFill": "blue"}} }%%
|
||||
quadrantChart
|
||||
x-axis Urgent --> Not Urgent
|
||||
y-axis Not Important --> important
|
||||
quadrant-1 Plan
|
||||
quadrant-2 Do
|
||||
quadrant-3 Deligate
|
||||
quadrant-4 Delete
|
||||
</pre>
|
||||
|
||||
<pre class="mermaid">
|
||||
%%{init: {"quadrantChart": {"chartWidth": 600, "chartHeight": 600} } }%%
|
||||
quadrantChart
|
||||
title Analytics and Business Intelligence Platforms
|
||||
x-axis "Completeness of Vision ❤" -->
|
||||
y-axis Ability to Execute
|
||||
quadrant-1 Leaders
|
||||
quadrant-2 Challengers
|
||||
quadrant-3 Niche
|
||||
quadrant-4 Visionaries
|
||||
Microsoft: [0.75, 0.75]
|
||||
Salesforce: [0.55, 0.60]
|
||||
IBM: [0.51, 0.40]
|
||||
Incorta: [0.20, 0.30]
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
mermaid.initialize({
|
||||
theme: 'default',
|
||||
logLevel: 3,
|
||||
securityLevel: 'loose',
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -144,6 +144,26 @@
|
||||
>
|
||||
<hr />
|
||||
|
||||
<pre class="mermaid">
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
participant John
|
||||
par_over Section title
|
||||
Alice ->> Bob: Message 1<br>Second line
|
||||
Bob ->> John: Message 2
|
||||
end
|
||||
par_over Two line<br>section title
|
||||
Note over Alice: Alice note
|
||||
Note over Bob: Bob note<br>Second line
|
||||
Note over John: John note
|
||||
end
|
||||
par_over Mixed section
|
||||
Alice ->> Bob: Message 1
|
||||
Note left of Bob: Alice/Bob Note
|
||||
end
|
||||
</pre>
|
||||
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
mermaid.initialize({
|
||||
|
53
demos/zenuml.html
Normal file
53
demos/zenuml.html
Normal file
@ -0,0 +1,53 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>Mermaid Zenuml Test Page</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Zenuml demos</h1>
|
||||
<pre class="mermaid">
|
||||
zenuml
|
||||
title Sync Messages (Design Pattern: Adapter)
|
||||
@Starter(Client)
|
||||
Adapter.interfaceMethod() {
|
||||
translateParameter(parameter)
|
||||
|
||||
result = Implementation.implementationMethod()
|
||||
|
||||
translateResult()
|
||||
return translatedResult
|
||||
}
|
||||
</pre>
|
||||
<pre class="mermaid">
|
||||
zenuml
|
||||
title Async Messages (SPA Authentication)
|
||||
// ```
|
||||
// GET https://${account.namespace}/authorize/?
|
||||
// response_type=token
|
||||
// &client_id=${account.clientId}
|
||||
// &redirect_url=YOUR_CALLBACK_URL
|
||||
// &state=VALUE_THAT_SURVIVES_REDIRECTS
|
||||
// &scope=openid
|
||||
// ```
|
||||
Browser->Auth0: 1. initiate the authentication
|
||||
Auth0->"Identity Provider": 2. OAuth2 / SAML, etc
|
||||
"Identity Provider"->"Identity Provider": 3. user gets authenticated
|
||||
Auth0->Browser: 4. redirect to ${YOUR_CALLBACK_URL}/#id_token=e68...
|
||||
Browser->Auth0: 5. validate id_token and get user profile
|
||||
Browser->"Your API": 6. call API sending JWT in Authorization header
|
||||
"Your API"->"Your API": 7. validate token
|
||||
</pre>
|
||||
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
import zenuml from './mermaid-zenuml.esm.mjs';
|
||||
await mermaid.registerExternalDiagrams([zenuml]);
|
||||
mermaid.initialize({
|
||||
logLevel: 3,
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
9
docker-compose.yml
Normal file
9
docker-compose.yml
Normal file
@ -0,0 +1,9 @@
|
||||
version: '3.9'
|
||||
services:
|
||||
mermaid:
|
||||
image: node:18.16.0-alpine3.18
|
||||
stdin_open: true
|
||||
tty: true
|
||||
working_dir: /mermaid
|
||||
volumes:
|
||||
- ./:/mermaid
|
1054
docs/CHANGELOG.md
1054
docs/CHANGELOG.md
File diff suppressed because it is too large
Load Diff
@ -4,7 +4,17 @@
|
||||
>
|
||||
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/community/development.md](../../packages/mermaid/src/docs/community/development.md).
|
||||
|
||||
# Development and Contribution 🙌
|
||||
# Contributing to Mermaid
|
||||
|
||||
## Contents
|
||||
|
||||
- [Technical Requirements and Setup](#technical-requirements-and-setup)
|
||||
- [Contributing Code](#contributing-code)
|
||||
- [Contributing Documentation](#contributing-documentation)
|
||||
- [Questions or Suggestions?](#questions-or-suggestions)
|
||||
- [Last Words](#last-words)
|
||||
|
||||
---
|
||||
|
||||
So you want to help? That's great!
|
||||
|
||||
@ -12,72 +22,167 @@ So you want to help? That's great!
|
||||
|
||||
Here are a few things to get you started on the right path.
|
||||
|
||||
**The Docs Structure is dictated by [.vitepress/config.ts](https://github.com/mermaid-js/mermaid/blob/develop/packages/mermaid/src/docs/.vitepress/config.ts)**.
|
||||
## Technical Requirements and Setup
|
||||
|
||||
**Note: Commits and Pull Requests should be directed to the develop branch.**
|
||||
### Technical Requirements
|
||||
|
||||
## Branching
|
||||
These are the tools we use for working with the code and documentation.
|
||||
|
||||
Mermaid uses a [Git Flow](https://guides.github.com/introduction/flow/)–inspired approach to branching. So development is done in the `develop` branch.
|
||||
- [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`
|
||||
- [npx](https://docs.npmjs.com/cli/v8/commands/npx) the packaged executor in npm. This is needed [to install pnpm.](#2-install-pnpm)
|
||||
|
||||
Once development is done we branch a `release` branch from `develop` for testing.
|
||||
Follow [the setup steps below](#setup) to install them and verify they are working
|
||||
|
||||
Once the release happens we merge the `release` branch with `master` and kill the `release` branch.
|
||||
### Setup
|
||||
|
||||
This means that **you should branch off your pull request from develop** and direct all Pull Requests to it.
|
||||
Follow these steps to set up the environment you need to work on code and/or documentation.
|
||||
|
||||
#### 1. Fork and clone the repository
|
||||
|
||||
In GitHub, you first _fork_ a repository when you are going to make changes and submit pull requests.
|
||||
|
||||
Then you _clone_ a copy to your local development machine (e.g. where you code) to make a copy with all the files to work with.
|
||||
|
||||
[Here is a GitHub document that gives an overview of the process.](https://docs.github.com/en/get-started/quickstart/fork-a-repo)
|
||||
|
||||
#### 2. Install pnpm
|
||||
|
||||
Once you have cloned the repository onto your development machine, change into the `mermaid` project folder so that you can install `pnpm`. You will need `npx` to install pnpm because volta doesn't support it yet.
|
||||
|
||||
Ex:
|
||||
|
||||
```bash
|
||||
# Change into the mermaid directory (the top level director of the mermaid project repository)
|
||||
cd mermaid
|
||||
# npx is required for first install because volta does not support pnpm yet
|
||||
npx pnpm install
|
||||
```
|
||||
|
||||
#### 3. Verify Everything Is Working
|
||||
|
||||
Once you have installed pnpm, you can run the `test` script to verify that pnpm is working _and_ that the repository has been cloned correctly:
|
||||
|
||||
```bash
|
||||
pnpm test
|
||||
```
|
||||
|
||||
The `test` script and others are in the top-level `package.json` file.
|
||||
|
||||
All tests should run successfully without any errors or failures. (You might see _lint_ or _formatting_ warnings; those are ok during this step.)
|
||||
|
||||
### Docker
|
||||
|
||||
If you are using docker and docker-compose, you have self-documented `run` bash script, which is a convenient alias for docker-compose commands:
|
||||
|
||||
```bash
|
||||
./run install # npx pnpm install
|
||||
./run test # pnpm test
|
||||
```
|
||||
|
||||
## Contributing Code
|
||||
|
||||
We make all changes via Pull Requests. As we have many Pull Requests from developers new to mermaid, we have put in place a process, wherein _knsv, Knut Sveidqvist_ is the primary reviewer of changes and merging pull requests. The process is as follows:
|
||||
The basic steps for contributing code are:
|
||||
|
||||
- Large changes reviewed by knsv or other developer asked to review by knsv
|
||||
- Smaller, low-risk changes like dependencies, documentation, etc. can be merged by active collaborators
|
||||
- Documentation (we encourage updates to the `/packages/mermaid/src/docs` folder; you can submit them via direct commits)
|
||||
```mermaid-example
|
||||
graph LR
|
||||
git[1. Checkout a git branch] --> codeTest[2. Write tests and code] --> doc[3. Update documentation] --> submit[4. Submit a PR] --> review[5. Review and merge]
|
||||
```
|
||||
|
||||
When you commit code, create a branch with the following naming convention:
|
||||
```mermaid
|
||||
graph LR
|
||||
git[1. Checkout a git branch] --> codeTest[2. Write tests and code] --> doc[3. Update documentation] --> submit[4. Submit a PR] --> review[5. Review and merge]
|
||||
```
|
||||
|
||||
Start with the type, such as **feature** or **bug**, followed by the issue number for reference, and a text that describes the issue.
|
||||
1. **Create** and checkout a git branch and work on your code in the branch
|
||||
2. Write and update **tests** (unit and perhaps even integration (e2e) tests) (If you do TDD/BDD, the order might be different.)
|
||||
3. **Let users know** that things have changed or been added in the documents! This is often overlooked, but _critical_
|
||||
4. **Submit** your code as a _pull request_.
|
||||
5. Maintainers will **review** your code. If there are no changes necessary, the PR will be merged. Otherwise, make the requested changes and repeat.
|
||||
|
||||
**One example:**
|
||||
### 1. Checkout a git branch
|
||||
|
||||
`feature/945_state_diagrams`
|
||||
Mermaid uses a [Git Flow](https://guides.github.com/introduction/flow/)–inspired approach to branching.
|
||||
|
||||
**Another example:**
|
||||
Development is done in the `develop` branch.
|
||||
|
||||
`bug/123_nasty_bug_branch`
|
||||
Once development is done we create a `release/vX.X.X` branch from `develop` for testing.
|
||||
|
||||
## Contributing to Documentation
|
||||
Once the release happens we add a tag to the `release` branch and merge it with `master`. The live product and on-line documentation are what is in the `master` branch.
|
||||
|
||||
If it is not in the documentation, it's like it never happened. Wouldn't that be sad? With all the effort that was put into the feature?
|
||||
**All new work should be based on the `develop` branch.**
|
||||
|
||||
The docs are located in the `src/docs` folder and are written in Markdown. Just pick the right section and start typing. If you want to propose changes to the structure of the documentation, such as adding a new section or a new file you do that via **[.vitepress/config.ts](https://github.com/mermaid-js/mermaid/blob/develop/packages/mermaid/src/docs/.vitepress/config.ts)**.
|
||||
**When you are ready to do work, always, ALWAYS:**
|
||||
|
||||
> **All the documents displayed in the GitHub.io page are listed in [.vitepress/config.ts](https://github.com/mermaid-js/mermaid/blob/develop/packages/mermaid/src/docs/.vitepress/config.ts)**.
|
||||
1. Make sure you have the most up-to-date version of the `develop` branch. (fetch or pull to update it)
|
||||
2. Check out the `develop` branch
|
||||
3. Create a new branch for your work. Please name the branch following our naming convention below.
|
||||
|
||||
The contents of <https://mermaid-js.github.io/mermaid/> are based on the docs from the `master` branch. Updates committed to the `master` branch are reflected in the [Mermaid Docs](https://mermaid-js.github.io/mermaid/) once released.
|
||||
We use the follow naming convention for branches:
|
||||
|
||||
## How to Contribute to Documentation
|
||||
```text
|
||||
[feature | bug | chore | docs]/[issue number]_[short description using dashes ('-') or underscores ('_') instead of spaces]
|
||||
```
|
||||
|
||||
We are a little less strict here, it is OK to commit directly in the `develop` branch if you are a collaborator.
|
||||
- The first part is the **type** of change: a feature, bug, chore, or documentation change ('docs')
|
||||
- followed by a _slash_ (which helps to group like types together in many git tools)
|
||||
- followed by the **issue number**
|
||||
- followed by an _underscore_ ('\_')
|
||||
- followed by a short text description (but use dashes ('-') or underscores ('\_') instead of spaces)
|
||||
|
||||
The documentation is located in the `src/docs` directory and organized according to relevant subfolder.
|
||||
If your work is specific to a single diagram type, it is a good idea to put the diagram type at the start of the description. This will help us keep release notes organized: it will help us keep changes for a diagram type together.
|
||||
|
||||
The `docs` folder will be automatically generated when committing to `src/docs` and should not be edited manually.
|
||||
**Ex: A new feature described in issue 2945 that adds a new arrow type called 'florbs' to state diagrams**
|
||||
|
||||
We encourage contributions to the documentation at [mermaid-js/mermaid/src/docs](https://github.com/mermaid-js/mermaid/tree/develop/packages/mermaid/src/docs). We publish documentation using GitHub Pages with [Docsify](https://www.youtube.com/watch?v=TV88lp7egMw&t=3s)
|
||||
`feature/2945_state-diagram-new-arrow-florbs`
|
||||
|
||||
### Add Unit Tests for Parsing
|
||||
**Ex: A bug described in issue 1123 that causes random ugly red text in multiple diagram types**
|
||||
`bug/1123_fix_random_ugly_red_text`
|
||||
|
||||
This is important so that, if someone that does not know about this great feature suggests a change to the grammar, they get notified early on when that change breaks the parser. Another important aspect is that, without proper parsing, tests refactoring is pretty much impossible.
|
||||
### 2. Write Tests
|
||||
|
||||
### Add E2E Tests
|
||||
Tests ensure that each function, module, or part of code does what it says it will do. This is critically
|
||||
important when other changes are made to ensure that existing code is not broken (no regression).
|
||||
|
||||
This tests the rendering and visual appearance of the diagrams. This ensures that the rendering of that feature in the e2e will be reviewed in the release process going forward. Less chance that it breaks!
|
||||
Just as important, the tests act as _specifications:_ they specify what the code does (or should do).
|
||||
Whenever someone is new to a section of code, they should be able to read the tests to get a thorough understanding of what it does and why.
|
||||
|
||||
If you are fixing a bug, you should add tests to ensure that your code has actually fixed the bug, to specify/describe what the code is doing, and to ensure the bug doesn't happen again.
|
||||
(If there had been a test for the situation, the bug never would have happened in the first place.)
|
||||
You may need to change existing tests if they were inaccurate.
|
||||
|
||||
If you are adding a feature, you will definitely need to add tests. Depending on the size of your feature, you may need to add integration tests.
|
||||
|
||||
#### Unit Tests
|
||||
|
||||
Unit tests are tests that test a single function or module. They are the easiest to write and the fastest to run.
|
||||
|
||||
Unit tests are mandatory all code except the renderers. (The renderers are tested with integration tests.)
|
||||
|
||||
We use [Vitest](https://vitest.dev) to run unit tests.
|
||||
|
||||
You can use the following command to run the unit tests:
|
||||
|
||||
```sh
|
||||
pnpm test
|
||||
```
|
||||
|
||||
When writing new tests, it's easier to have the tests automatically run as you make changes. You can do this by running the following command:
|
||||
|
||||
```sh
|
||||
pnpm test:watch
|
||||
```
|
||||
|
||||
#### Integration/End-to-End (e2e) tests
|
||||
|
||||
These test the rendering and visual appearance of the diagrams.
|
||||
This ensures that the rendering of that feature in the e2e will be reviewed in the release process going forward. Less chance that it breaks!
|
||||
|
||||
To start working with the e2e tests:
|
||||
|
||||
1. Run `pnpm run dev` to start the dev server
|
||||
2. Start **Cypress** by running `pnpm exec cypress open` in the **mermaid** folder.
|
||||
1. Run `pnpm dev` to start the dev server
|
||||
2. Start **Cypress** by running `pnpm cypress:open`.
|
||||
|
||||
The rendering tests are very straightforward to create. There is a function `imgSnapshotTest`, which takes a diagram in text form and the mermaid options, and it renders that diagram in Cypress.
|
||||
|
||||
@ -107,30 +212,162 @@ it('should render forks and joins', () => {
|
||||
});
|
||||
```
|
||||
|
||||
### Any Questions or Suggestions?
|
||||
**_\[TODO - running the tests against what is expected in development. ]_**
|
||||
|
||||
After logging in at [GitHub.com](https://www.github.com), open or append to an issue [using the GitHub issue tracker of the mermaid-js repository](https://github.com/mermaid-js/mermaid/issues?q=is%3Aissue+is%3Aopen+label%3A%22Area%3A+Documentation%22).
|
||||
**_\[TODO - how to generate new screenshots]_**
|
||||
....
|
||||
|
||||
### How to Contribute a Suggestion
|
||||
### 3. Update Documentation
|
||||
|
||||
If the users have no way to know that things have changed, then you haven't really _fixed_ anything for the users; you've just added to making Mermaid feel broken.
|
||||
Likewise, if users don't know that there is a new feature that you've implemented, it will forever remain unknown and unused.
|
||||
|
||||
The documentation has to be updated to users know that things have changed and added!
|
||||
|
||||
We know it can sometimes be hard to code _and_ write user documentation.
|
||||
|
||||
Our documentation is managed in `packages/mermaid/src/docs`. Details on how to edit is in the [Contributing Documentation](#contributing-documentation) section.
|
||||
|
||||
Create another issue specifically for the documentation.\
|
||||
You will need to help with the PR, but definitely ask for help if you feel stuck.
|
||||
When it feels hard to write stuff out, explaining it to someone and having that person ask you clarifying questions can often be 80% of the work!
|
||||
|
||||
When in doubt, write up and submit what you can. It can be clarified and refined later. (With documentation, something is better than nothing!)
|
||||
|
||||
### 4. Submit your pull request
|
||||
|
||||
**\[TODO - PR titles should start with (fix | feat | ....)]**
|
||||
|
||||
We make all changes via Pull Requests (PRs). As we have many Pull Requests from developers new to Mermaid, we have put in place a process wherein _knsv, Knut Sveidqvist_ is in charge of the final release process and the active maintainers are in charge of reviewing and merging most PRs.
|
||||
|
||||
- PRs will be reviewed by active maintainers, who will provide feedback and request changes as needed.
|
||||
- The maintainers will request a review from knsv, if necessary.
|
||||
- Once the PR is approved, the maintainers will merge the PR into the `develop` branch.
|
||||
- When a release is ready, the `release/x.x.x` branch will be created, extensively tested and knsv will be in charge of the release process.
|
||||
|
||||
**Reminder: Pull Requests should be submitted to the develop branch.**
|
||||
|
||||
## Contributing Documentation
|
||||
|
||||
**_\[TODO: This section is still a WIP. It still needs MAJOR revision.]_**
|
||||
|
||||
If it is not in the documentation, it's like it never happened. Wouldn't that be sad? With all the effort that was put into the feature?
|
||||
|
||||
The docs are located in the `packages/mermaid/src/docs` folder and are written in Markdown. Just pick the right section and start typing.
|
||||
|
||||
The contents of [mermaid.js.org](https://mermaid.js.org/) are based on the docs from the `master` branch.
|
||||
Updates committed to the `master` branch are reflected in the [Mermaid Docs](https://mermaid.js.org/) once published.
|
||||
|
||||
### How to Contribute to Documentation
|
||||
|
||||
We are a little less strict here, it is OK to commit directly in the `develop` branch if you are a collaborator.
|
||||
|
||||
The documentation is located in the `packages/mermaid/src/docs` directory and organized according to relevant subfolder.
|
||||
|
||||
The `docs` folder will be automatically generated when committing to `packages/mermaid/src/docs` and **should not** be edited manually.
|
||||
|
||||
```mermaid-example
|
||||
flowchart LR
|
||||
classDef default fill:#fff,color:black,stroke:black
|
||||
|
||||
source["files in /packages/mermaid/src/docs\n(changes should be done here)"] -- automatic processing\nto generate the final documentation--> published["files in /docs\ndisplayed on the official documentation site"]
|
||||
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
classDef default fill:#fff,color:black,stroke:black
|
||||
|
||||
source["files in /packages/mermaid/src/docs\n(changes should be done here)"] -- automatic processing\nto generate the final documentation--> published["files in /docs\ndisplayed on the official documentation site"]
|
||||
|
||||
```
|
||||
|
||||
You can use `note`, `tip`, `warning` and `danger` in triple backticks to add a note, tip, warning or danger box.
|
||||
Do not use vitepress specific markdown syntax `::: warning` as it will not be processed correctly.
|
||||
|
||||
````
|
||||
```note
|
||||
Note content
|
||||
```
|
||||
|
||||
```tip
|
||||
Tip content
|
||||
```
|
||||
|
||||
```warning
|
||||
Warning content
|
||||
```
|
||||
|
||||
```danger
|
||||
Danger content
|
||||
```
|
||||
|
||||
````
|
||||
|
||||
> **Note**
|
||||
> If the change is _only_ to the documentation, you can get your changes published to the site quicker by making a PR to the `master` branch.
|
||||
|
||||
We encourage contributions to the documentation at [packages/mermaid/src/docs in the _develop_ branch](https://github.com/mermaid-js/mermaid/tree/develop/packages/mermaid/src/docs).
|
||||
|
||||
**_DO NOT CHANGE FILES IN `/docs`_**
|
||||
|
||||
### The official documentation site
|
||||
|
||||
**[The mermaid documentation site](https://mermaid.js.org/) is powered by [Vitepress](https://vitepress.vuejs.org/).**
|
||||
|
||||
To run the documentation site locally:
|
||||
|
||||
1. Run `pnpm --filter mermaid run docs:dev` to start the dev server. (Or `pnpm docs:dev` inside the `packages/mermaid` directory.)
|
||||
2. Open <http://localhost:3333/> in your browser.
|
||||
|
||||
Markdown is used to format the text, for more information about Markdown [see the GitHub Markdown help page](https://help.github.com/en/github/writing-on-github/basic-writing-and-formatting-syntax).
|
||||
|
||||
To edit Docs on your computer:
|
||||
|
||||
1. Find the Markdown file (.md) to edit in the [packages/mermaid/src/docs](https://github.com/mermaid-js/mermaid/tree/develop/packages/mermaid/src/docs) directory in the `develop` branch.
|
||||
2. Create a fork of the develop branch.
|
||||
_\[TODO: need to keep this in sync with [check out a git branch in Contributing Code above](#1-checkout-a-git-branch) ]_
|
||||
|
||||
1. Create a fork of the develop branch to work on.
|
||||
2. Find the Markdown file (.md) to edit in the `packages/mermaid/src/docs` directory.
|
||||
3. Make changes or add new documentation.
|
||||
4. Commit changes to your fork and push it to GitHub.
|
||||
4. Commit changes to your branch and push it to GitHub (which should create a new branch).
|
||||
5. Create a Pull Request of your fork.
|
||||
|
||||
To edit Docs on GitHub:
|
||||
|
||||
1. Login to [GitHub.com](https://www.github.com).
|
||||
2. Navigate to [packages/mermaid/src/docs](https://github.com/mermaid-js/mermaid/tree/develop/packages/mermaid/src/docs).
|
||||
2. Navigate to [packages/mermaid/src/docs](https://github.com/mermaid-js/mermaid/tree/develop/packages/mermaid/src/docs) in the mermaid-js repository.
|
||||
3. To edit a file, click the pencil icon at the top-right of the file contents panel.
|
||||
4. Describe what you changed in the **Propose file change** section, located at the bottom of the page.
|
||||
5. Submit your changes by clicking the button **Propose file change** at the bottom (by automatic creation of a fork and a new branch).
|
||||
6. Create a Pull Request of your newly forked branch by clicking the green **Create Pull Request** button.
|
||||
6. Visit the Actions tab in Github, `https://github.com/<Your Username>/mermaid/actions` and enable the actions for your fork. This will ensure that the documentation is built and updated in your fork.
|
||||
7. Create a Pull Request of your newly forked branch by clicking the green **Create Pull Request** button.
|
||||
|
||||
### Documentation organization: Sidebar navigation
|
||||
|
||||
If you want to propose changes to how the documentation is _organized_, such as adding a new section or re-arranging or renaming a section, you must update the **sidebar navigation.**
|
||||
|
||||
The sidebar navigation is defined in [the vitepress configuration file config.ts](../.vitepress/config.ts).
|
||||
|
||||
## Questions or Suggestions?
|
||||
|
||||
#### First search to see if someone has already asked (and hopefully been answered) or suggested the same thing.
|
||||
|
||||
- Search in Discussions
|
||||
- Search in open Issues
|
||||
- Search in closed Issues
|
||||
|
||||
If you find an open issue or discussion thread that is similar to your question but isn't answered, you can let us know that you are also interested in it.
|
||||
Use the GitHub reactions to add a thumbs-up to the issue or discussion thread.
|
||||
|
||||
This helps the team know the relative interest in something and helps them set priorities and assignments.
|
||||
|
||||
Feel free to add to the discussion on the issue or topic.
|
||||
|
||||
If you can't find anything that already addresses your question or suggestion, _open a new issue:_
|
||||
|
||||
Log in to [GitHub.com](https://www.github.com), open or append to an issue [using the GitHub issue tracker of the mermaid-js repository](https://github.com/mermaid-js/mermaid/issues?q=is%3Aissue+is%3Aopen+label%3A%22Area%3A+Documentation%22).
|
||||
|
||||
### How to Contribute a Suggestion
|
||||
|
||||
## Last Words
|
||||
|
||||
|
@ -69,6 +69,6 @@ In fact one can pick up the syntax for it quite easily from the examples given a
|
||||
|
||||
## Mermaid is for everyone.
|
||||
|
||||
Video [Tutorials](https://mermaid-js.github.io/mermaid/#/../config/Tutorials) are also available for the mermaid [live editor](https://mermaid.live/).
|
||||
Video [Tutorials](https://mermaid.js.org/config/Tutorials.html) are also available for the mermaid [live editor](https://mermaid.live/).
|
||||
|
||||
Alternatively you can use Mermaid [Plug-Ins](https://mermaid-js.github.io/mermaid/#/./integrations), with tools you already use, like Google Docs.
|
||||
|
@ -8,11 +8,11 @@
|
||||
|
||||
## Directives
|
||||
|
||||
Directives gives a diagram author the capability to alter the appearance of a diagram before rendering by changing the applied configuration.
|
||||
Directives give a diagram author the capability to alter the appearance of a diagram before rendering by changing the applied configuration.
|
||||
|
||||
The significance of having directives is that you have them available while writing the diagram, and can modify the default global and diagram specific configurations. So, directives are applied on top of the default configurations. The beauty of directives is that you can use them to alter configuration settings for a specific diagram, i.e. at an individual level.
|
||||
The significance of having directives is that you have them available while writing the diagram, and can modify the default global and diagram-specific configurations. So, directives are applied on top of the default configuration. The beauty of directives is that you can use them to alter configuration settings for a specific diagram, i.e. at an individual level.
|
||||
|
||||
While directives allow you to change most of the default configuration settings, there are some that are not available, that too for security reasons. Also, you do have the _option to define the set of configurations_ that you would allow to be available to the diagram author for overriding with help of directives.
|
||||
While directives allow you to change most of the default configuration settings, there are some that are not available, for security reasons. Also, you have the _option to define the set of configurations_ that you wish to allow diagram authors to override with directives.
|
||||
|
||||
## Types of Directives options
|
||||
|
||||
@ -20,29 +20,29 @@ Mermaid basically supports two types of configuration options to be overridden b
|
||||
|
||||
1. _General/Top Level configurations_ : These are the configurations that are available and applied to all the diagram. **Some of the most important top-level** configurations are:
|
||||
|
||||
- theme
|
||||
- fontFamily
|
||||
- logLevel
|
||||
- securityLevel
|
||||
- startOnLoad
|
||||
- secure
|
||||
- theme
|
||||
- fontFamily
|
||||
- logLevel
|
||||
- securityLevel
|
||||
- startOnLoad
|
||||
- secure
|
||||
|
||||
2. _Diagram specific configurations_ : These are the configurations that are available and applied to a specific diagram. For each diagram there are specific configuration that will alter how that particular diagram looks and behaves.
|
||||
For example, `mirrorActors` is a configuration that is specific to the `SequenceDiagram` and alter whether the actors are mirrored or not. So this config is available only for the `SequenceDiagram` type.
|
||||
2. _Diagram-specific configurations_ : These are the configurations that are available and applied to a specific diagram. For each diagram there are specific configuration that will alter how that particular diagram looks and behaves.
|
||||
For example, `mirrorActors` is a configuration that is specific to the `SequenceDiagram` and alters whether the actors are mirrored or not. So this config is available only for the `SequenceDiagram` type.
|
||||
|
||||
**NOTE:** These options listed here are not all the configuration options. To get hold of all the configuration options, please refer to the [defaultConfig.ts](https://github.com/mermaid-js/mermaid/blob/develop/packages/mermaid/src/defaultConfig.ts) in the source code.
|
||||
**NOTE:** Not all configuration options are listed here. To get hold of all the configuration options, please refer to the [defaultConfig.ts](https://github.com/mermaid-js/mermaid/blob/develop/packages/mermaid/src/defaultConfig.ts) in the source code.
|
||||
|
||||
> **Note**
|
||||
> We plan to publish a complete list of top-level configurations & all the diagram specific configurations, with their possible values in the docs soon.
|
||||
> We plan to publish a complete list of top-level configurations & diagram-specific configurations with their possible values in the docs soon.
|
||||
|
||||
## Declaring directives
|
||||
|
||||
Now that we have defined the types of configurations that are available, we can learn how to declare directives.
|
||||
A directive always starts and end `%%` sign with directive text in between, like `%% {directive_text} %%`.
|
||||
A directive always starts and ends with `%%` signs with directive text in between, like `%% {directive_text} %%`.
|
||||
|
||||
Here the structure of a directive text is like a nested key-value pair map or a JSON object with root being _init_. Where all the general configurations are defined in the top level, and all the diagram specific configurations are defined one level deeper with diagram type as key/root for that section.
|
||||
|
||||
Following code snippet shows the structure of a directive:
|
||||
The following code snippet shows the structure of a directive:
|
||||
|
||||
%%{
|
||||
init: {
|
||||
@ -61,14 +61,14 @@ Following code snippet shows the structure of a directive:
|
||||
|
||||
You can also define the directives in a single line, like this:
|
||||
|
||||
%%{init: { **insert argument here**}}%%
|
||||
%%{init: { **insert configuration options here** } }%%
|
||||
|
||||
For example, the following code snippet:
|
||||
|
||||
%%{init: { "sequence": { "mirrorActors":false }}}%%
|
||||
|
||||
**Notes:**
|
||||
The json object that is passed as {**argument** } must be valid key value pairs and encased in quotation marks or it will be ignored.
|
||||
The JSON object that is passed as {**argument**} must be valid key value pairs and encased in quotation marks or it will be ignored.
|
||||
Valid Key Value pairs can be found in config.
|
||||
|
||||
Example with a simple graph:
|
||||
@ -87,7 +87,7 @@ A-->B
|
||||
|
||||
Here the directive declaration will set the `logLevel` to `debug` and the `theme` to `dark` for a rendered mermaid diagram, changing the appearance of the diagram itself.
|
||||
|
||||
Note: You can use 'init' or 'initialize' as both acceptable as init directives. Also note that `%%init%%` and `%%initialize%%` directives will be grouped together after they are parsed. This means:
|
||||
Note: You can use 'init' or 'initialize' as both are acceptable as init directives. Also note that `%%init%%` and `%%initialize%%` directives will be grouped together after they are parsed.
|
||||
|
||||
```mermaid-example
|
||||
%%{init: { 'logLevel': 'debug', 'theme': 'forest' } }%%
|
||||
@ -101,7 +101,7 @@ Note: You can use 'init' or 'initialize' as both acceptable as init directives.
|
||||
...
|
||||
```
|
||||
|
||||
parsing the above generates a single `%%init%%` JSON object below, combining the two directives and carrying over the last value given for `loglevel`:
|
||||
For example, parsing the above generates a single `%%init%%` JSON object below, combining the two directives and carrying over the last value given for `loglevel`:
|
||||
|
||||
```json
|
||||
{
|
||||
@ -115,16 +115,15 @@ This will then be sent to `mermaid.initialize(...)` for rendering.
|
||||
|
||||
## Directive Examples
|
||||
|
||||
More directive examples for diagram specific configuration overrides
|
||||
Now that the concept of directives has been explained, Let us see some more examples for directives usage:
|
||||
Now that the concept of directives has been explained, let us see some more examples of directive usage:
|
||||
|
||||
### Changing Theme via directive
|
||||
### Changing theme via directive
|
||||
|
||||
The following code snippet changes theme to forest:
|
||||
The following code snippet changes `theme` to `forest`:
|
||||
|
||||
`%%{init: { "theme": "forest" } }%%`
|
||||
|
||||
Possible themes value are: `default`,`base`, `dark`, `forest` and `neutral`.
|
||||
Possible theme values are: `default`,`base`, `dark`, `forest` and `neutral`.
|
||||
Default Value is `default`.
|
||||
|
||||
Example:
|
||||
@ -155,7 +154,7 @@ A --> C[End]
|
||||
|
||||
### Changing fontFamily via directive
|
||||
|
||||
The following code snippet changes fontFamily to rebuchet MS, Verdana, Arial, Sans-Serif:
|
||||
The following code snippet changes fontFamily to Trebuchet MS, Verdana, Arial, Sans-Serif:
|
||||
|
||||
`%%{init: { "fontFamily": "Trebuchet MS, Verdana, Arial, Sans-Serif" } }%%`
|
||||
|
||||
@ -187,11 +186,11 @@ A --> C[End]
|
||||
|
||||
### Changing logLevel via directive
|
||||
|
||||
The following code snippet changes logLevel to 2:
|
||||
The following code snippet changes `logLevel` to `2`:
|
||||
|
||||
`%%{init: { "logLevel": 2 } }%%`
|
||||
|
||||
Possible logLevel values are:
|
||||
Possible `logLevel` values are:
|
||||
|
||||
- `1` for _debug_,
|
||||
- `2` for _info_
|
||||
@ -234,14 +233,14 @@ Some common flowchart configurations are:
|
||||
- _diagramPadding_: number
|
||||
- _useMaxWidth_: number
|
||||
|
||||
For complete list of flowchart configurations, see [defaultConfig.ts](https://github.com/mermaid-js/mermaid/blob/develop/packages/mermaid/src/defaultConfig.ts) in the source code.
|
||||
_Soon we plan to publish a complete list all diagram specific configurations updated in the docs_
|
||||
For a complete list of flowchart configurations, see [defaultConfig.ts](https://github.com/mermaid-js/mermaid/blob/develop/packages/mermaid/src/defaultConfig.ts) in the source code.
|
||||
_Soon we plan to publish a complete list of all diagram-specific configurations updated in the docs._
|
||||
|
||||
The following code snippet changes flowchart config:
|
||||
|
||||
`%%{init: { "flowchart": { "htmlLabels": true, "curve": "linear" } } }%%`
|
||||
|
||||
Here were are overriding only the flowchart config, and not the general config, where HtmlLabels is set to true and curve is set to linear.
|
||||
Here we are overriding only the flowchart config, and not the general config, setting `htmlLabels` to `true` and `curve` to `linear`.
|
||||
|
||||
```mermaid-example
|
||||
%%{init: { "flowchart": { "htmlLabels": true, "curve": "linear" } } }%%
|
||||
@ -267,7 +266,7 @@ A --> C[End]
|
||||
|
||||
### Changing Sequence diagram config via directive
|
||||
|
||||
Some common sequence configurations are:
|
||||
Some common sequence diagram configurations are:
|
||||
|
||||
- _width_: number
|
||||
- _height_: number
|
||||
@ -278,8 +277,8 @@ Some common sequence configurations are:
|
||||
- _showSequenceNumbers_: boolean
|
||||
- _wrap_: boolean
|
||||
|
||||
For complete list of sequence diagram configurations, see _defaultConfig.ts_ in the source code.
|
||||
_Soon we plan to publish a complete list all diagram specific configurations updated in the docs_
|
||||
For a complete list of sequence diagram configurations, see [defaultConfig.ts](https://github.com/mermaid-js/mermaid/blob/develop/packages/mermaid/src/defaultConfig.ts) in the source code.
|
||||
_Soon we plan to publish a complete list of all diagram-specific configurations updated in the docs._
|
||||
|
||||
So, `wrap` by default has a value of `false` for sequence diagrams.
|
||||
|
||||
@ -289,7 +288,7 @@ Let us see an example:
|
||||
sequenceDiagram
|
||||
|
||||
Alice->Bob: Hello Bob, how are you?
|
||||
Bob->Alice: Fine, How did you mother like the book I suggested? And did you catch with the new book about alien invasion?
|
||||
Bob->Alice: Fine, how did you mother like the book I suggested? And did you catch the new book about alien invasion?
|
||||
Alice->Bob: Good.
|
||||
Bob->Alice: Cool
|
||||
```
|
||||
@ -298,7 +297,7 @@ Bob->Alice: Cool
|
||||
sequenceDiagram
|
||||
|
||||
Alice->Bob: Hello Bob, how are you?
|
||||
Bob->Alice: Fine, How did you mother like the book I suggested? And did you catch with the new book about alien invasion?
|
||||
Bob->Alice: Fine, how did you mother like the book I suggested? And did you catch the new book about alien invasion?
|
||||
Alice->Bob: Good.
|
||||
Bob->Alice: Cool
|
||||
```
|
||||
@ -309,13 +308,13 @@ The following code snippet changes sequence diagram config for `wrap` to `true`:
|
||||
|
||||
`%%{init: { "sequence": { "wrap": true} } }%%`
|
||||
|
||||
Using in the diagram above, the wrap will be enabled.
|
||||
By applying that snippet to the diagram above, `wrap` will be enabled:
|
||||
|
||||
```mermaid-example
|
||||
%%{init: { "sequence": { "wrap": true, "width":300 } } }%%
|
||||
sequenceDiagram
|
||||
Alice->Bob: Hello Bob, how are you?
|
||||
Bob->Alice: Fine, How did you mother like the book I suggested? And did you catch with the new book about alien invasion?
|
||||
Bob->Alice: Fine, how did you mother like the book I suggested? And did you catch the new book about alien invasion?
|
||||
Alice->Bob: Good.
|
||||
Bob->Alice: Cool
|
||||
```
|
||||
@ -324,7 +323,7 @@ Bob->Alice: Cool
|
||||
%%{init: { "sequence": { "wrap": true, "width":300 } } }%%
|
||||
sequenceDiagram
|
||||
Alice->Bob: Hello Bob, how are you?
|
||||
Bob->Alice: Fine, How did you mother like the book I suggested? And did you catch with the new book about alien invasion?
|
||||
Bob->Alice: Fine, how did you mother like the book I suggested? And did you catch the new book about alien invasion?
|
||||
Alice->Bob: Good.
|
||||
Bob->Alice: Cool
|
||||
```
|
||||
|
@ -39,7 +39,7 @@ bindFunctions?.(div); // To call bindFunctions only if it's present.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:98](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L98)
|
||||
[mermaidAPI.ts:97](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L97)
|
||||
|
||||
---
|
||||
|
||||
@ -51,4 +51,4 @@ The svg code for the rendered graph.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:88](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L88)
|
||||
[mermaidAPI.ts:87](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L87)
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
#### Defined in
|
||||
|
||||
[defaultConfig.ts:2115](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L2115)
|
||||
[defaultConfig.ts:2293](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L2293)
|
||||
|
||||
---
|
||||
|
||||
|
@ -25,7 +25,7 @@ Renames and re-exports [mermaidAPI](mermaidAPI.md#mermaidapi)
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:82](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L82)
|
||||
[mermaidAPI.ts:81](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L81)
|
||||
|
||||
## Variables
|
||||
|
||||
@ -96,7 +96,7 @@ mermaid.initialize(config);
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:673](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L673)
|
||||
[mermaidAPI.ts:663](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L663)
|
||||
|
||||
## Functions
|
||||
|
||||
@ -127,7 +127,7 @@ Return the last node appended
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:312](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L312)
|
||||
[mermaidAPI.ts:308](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L308)
|
||||
|
||||
---
|
||||
|
||||
@ -153,7 +153,7 @@ the cleaned up svgCode
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:263](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L263)
|
||||
[mermaidAPI.ts:256](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L256)
|
||||
|
||||
---
|
||||
|
||||
@ -179,7 +179,7 @@ the string with all the user styles
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:192](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L192)
|
||||
[mermaidAPI.ts:185](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L185)
|
||||
|
||||
---
|
||||
|
||||
@ -202,7 +202,7 @@ the string with all the user styles
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:240](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L240)
|
||||
[mermaidAPI.ts:233](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L233)
|
||||
|
||||
---
|
||||
|
||||
@ -229,7 +229,7 @@ with an enclosing block that has each of the cssClasses followed by !important;
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:176](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L176)
|
||||
[mermaidAPI.ts:169](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L169)
|
||||
|
||||
---
|
||||
|
||||
@ -249,7 +249,7 @@ with an enclosing block that has each of the cssClasses followed by !important;
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:156](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L156)
|
||||
[mermaidAPI.ts:155](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L155)
|
||||
|
||||
---
|
||||
|
||||
@ -269,7 +269,7 @@ with an enclosing block that has each of the cssClasses followed by !important;
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:127](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L127)
|
||||
[mermaidAPI.ts:126](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L126)
|
||||
|
||||
---
|
||||
|
||||
@ -295,7 +295,7 @@ Put the svgCode into an iFrame. Return the iFrame code
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:291](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L291)
|
||||
[mermaidAPI.ts:287](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L287)
|
||||
|
||||
---
|
||||
|
||||
@ -320,4 +320,4 @@ Remove any existing elements from the given document
|
||||
|
||||
#### Defined in
|
||||
|
||||
[mermaidAPI.ts:362](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L362)
|
||||
[mermaidAPI.ts:358](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L358)
|
||||
|
@ -112,10 +112,10 @@ A `securityLevel` configuration has to first be cleared. `securityLevel` sets th
|
||||
|
||||
Values:
|
||||
|
||||
- **strict**: (**default**) tags in text are encoded, click functionality is disabled
|
||||
- **loose**: tags in text are allowed, click functionality is enabled
|
||||
- **antiscript**: html tags in text are allowed, (only script element is removed), click functionality is enabled
|
||||
- **sandbox**: With this security level all rendering takes place in a sandboxed iframe. This prevent any JavaScript running in the context. This may hinder interactive functionality of the diagram like scripts, popups in sequence diagram or links to other tabs/targets etc.
|
||||
- **strict**: (**default**) HTML tags in the text are encoded and click functionality is disabled.
|
||||
- **antiscript**: HTML tags in text are allowed (only script elements are removed) and click functionality is enabled.
|
||||
- **loose**: HTML tags in text are allowed and click functionality is enabled.
|
||||
- **sandbox**: With this security level, all rendering takes place in a sandboxed iframe. This prevent any JavaScript from running in the context. This may hinder interactive functionality of the diagram, like scripts, popups in the sequence diagram, links to other tabs or targets, etc.
|
||||
|
||||
> **Note**
|
||||
> This changes the default behaviour of mermaid so that after upgrade to 8.2, unless the `securityLevel` is not changed, tags in flowcharts are encoded as tags and clicking is disabled.
|
||||
@ -348,10 +348,10 @@ mermaid.parseError = function (err, hash) {
|
||||
displayErrorInGui(err);
|
||||
};
|
||||
|
||||
const textFieldUpdated = function () {
|
||||
const textFieldUpdated = async function () {
|
||||
const textStr = getTextFromFormField('code');
|
||||
|
||||
if (mermaid.parse(textStr)) {
|
||||
if (await mermaid.parse(textStr)) {
|
||||
reRender(textStr);
|
||||
}
|
||||
};
|
||||
|
@ -6,6 +6,20 @@
|
||||
|
||||
# Integrations
|
||||
|
||||
## Recommendations
|
||||
|
||||
### File Extension
|
||||
|
||||
Applications that support mermaid files [SHOULD](https://datatracker.ietf.org/doc/html/rfc2119#section-3) use `.mermaid` or `.mmd` file extensions.
|
||||
|
||||
### MIME Type
|
||||
|
||||
The recommended [MIME type](https://www.iana.org/assignments/media-types/media-types.xhtml) for mermaid media is `text/vnd.mermaid`.
|
||||
|
||||
[IANA](https://www.iana.org/) recognition pending.
|
||||
|
||||
---
|
||||
|
||||
The following list is a compilation of different integrations and plugins that allow the rendering of mermaid definitions within other applications.
|
||||
|
||||
They also serve as proof of concept, for the variety of things that can be built with mermaid.
|
||||
@ -16,6 +30,7 @@ They also serve as proof of concept, for the variety of things that can be built
|
||||
- [Using code blocks](https://github.blog/2022-02-14-include-diagrams-markdown-files-mermaid/) (**Native support**)
|
||||
- [GitHub action: Compile mermaid to image](https://github.com/neenjaw/compile-mermaid-markdown-action)
|
||||
- [svg-generator](https://github.com/SimonKenyonShepard/mermaidjs-github-svg-generator)
|
||||
- [GitHub Writer](https://github.com/ckeditor/github-writer)
|
||||
- [GitLab](https://docs.gitlab.com/ee/user/markdown.html#diagrams-and-flowcharts) (**Native support**)
|
||||
- [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**)
|
||||
@ -58,6 +73,8 @@ They also serve as proof of concept, for the variety of things that can be built
|
||||
- [hexo-filter-mermaid-diagrams](https://github.com/webappdevelp/hexo-filter-mermaid-diagrams)
|
||||
- [hexo-tag-mermaid](https://github.com/JameChou/hexo-tag-mermaid)
|
||||
- [hexo-mermaid-diagrams](https://github.com/mslxl/hexo-mermaid-diagrams)
|
||||
- [Nextra](https://nextra.site/)
|
||||
- [Mermaid](https://nextra.site/docs/guide/mermaid)
|
||||
|
||||
## CMS
|
||||
|
||||
@ -142,13 +159,19 @@ They also serve as proof of concept, for the variety of things that can be built
|
||||
- [Named block =Diagram](https://github.com/zag/podlite/tree/main/packages/podlite-diagrams)
|
||||
- [GNU Nano](https://www.nano-editor.org/)
|
||||
- [Nano Mermaid](https://github.com/Yash-Singh1/nano-mermaid)
|
||||
- [CKEditor](https://github.com/ckeditor/ckeditor5)
|
||||
- [CKEditor 5 Mermaid plugin](https://github.com/ckeditor/ckeditor5-mermaid)
|
||||
|
||||
## Document Generation
|
||||
|
||||
- [Sphinx](https://www.sphinx-doc.org/en/master/)
|
||||
- [sphinxcontrib-mermaid](https://github.com/mgaitan/sphinxcontrib-mermaid)
|
||||
- [remark.js](https://remark.js.org/)
|
||||
- [remark-mermaid](https://github.com/temando/remark-mermaid)
|
||||
- [remark](https://remark.js.org/)
|
||||
- [remark-mermaidjs](https://github.com/remcohaszing/remark-mermaidjs)
|
||||
- [rehype](https://github.com/rehypejs/rehype)
|
||||
- [rehype-mermaidjs](https://github.com/remcohaszing/rehype-mermaidjs)
|
||||
- [Gatsby](https://www.gatsbyjs.com/)
|
||||
- [gatsby-remark-mermaid](https://github.com/remcohaszing/gatsby-remark-mermaid)
|
||||
- [jSDoc](https://jsdoc.app/)
|
||||
- [jsdoc-mermaid](https://github.com/Jellyvision/jsdoc-mermaid)
|
||||
- [MkDocs](https://www.mkdocs.org)
|
||||
@ -189,6 +212,7 @@ They also serve as proof of concept, for the variety of things that can be built
|
||||
- [bisheng-plugin-mermaid](https://github.com/yct21/bisheng-plugin-mermaid)
|
||||
- [Reveal CK](https://github.com/jedcn/reveal-ck)
|
||||
- [reveal-ck-mermaid-plugin](https://github.com/tmtm/reveal-ck-mermaid-plugin)
|
||||
- [mermaid-isomorphic](https://github.com/remcohaszing/mermaid-isomorphic)
|
||||
- [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)
|
||||
|
@ -235,6 +235,42 @@ journey
|
||||
Sit down: 5: Me
|
||||
```
|
||||
|
||||
### [Quadrant Chart](../syntax/quadrantChart.md)
|
||||
|
||||
```mermaid-example
|
||||
quadrantChart
|
||||
title Reach and engagement of campaigns
|
||||
x-axis Low Reach --> High Reach
|
||||
y-axis Low Engagement --> High Engagement
|
||||
quadrant-1 We should expand
|
||||
quadrant-2 Need to promote
|
||||
quadrant-3 Re-evaluate
|
||||
quadrant-4 May be improved
|
||||
Campaign A: [0.3, 0.6]
|
||||
Campaign B: [0.45, 0.23]
|
||||
Campaign C: [0.57, 0.69]
|
||||
Campaign D: [0.78, 0.34]
|
||||
Campaign E: [0.40, 0.34]
|
||||
Campaign F: [0.35, 0.78]
|
||||
```
|
||||
|
||||
```mermaid
|
||||
quadrantChart
|
||||
title Reach and engagement of campaigns
|
||||
x-axis Low Reach --> High Reach
|
||||
y-axis Low Engagement --> High Engagement
|
||||
quadrant-1 We should expand
|
||||
quadrant-2 Need to promote
|
||||
quadrant-3 Re-evaluate
|
||||
quadrant-4 May be improved
|
||||
Campaign A: [0.3, 0.6]
|
||||
Campaign B: [0.45, 0.23]
|
||||
Campaign C: [0.57, 0.69]
|
||||
Campaign D: [0.78, 0.34]
|
||||
Campaign E: [0.40, 0.34]
|
||||
Campaign F: [0.35, 0.78]
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
**In depth guides and examples can be found at [Getting Started](./n00b-gettingStarted.md) and [Usage](../config/usage.md).**
|
||||
|
@ -6,8 +6,8 @@
|
||||
|
||||
# Announcements
|
||||
|
||||
## [Automatic text wrapping in flowcharts is here!](https://www.mermaidchart.com/blog/posts/automatic-text-wrapping-in-flowcharts-is-here)
|
||||
## [subhash-halder contributed quadrant charts so you can show your manager what to select - just like the strategy consultants at BCG do](https://www.mermaidchart.com/blog/posts/subhash-halder-contributed-quadrant-charts-so-you-can-show-your-manager-what-to-select-just-like-the-strategy-consultants-at-bcg-do/)
|
||||
|
||||
3 April 2023 · 3 mins
|
||||
8 June 2023 · 7 mins
|
||||
|
||||
Markdown Strings reduce the hassle # Starting from v10.
|
||||
A quadrant chart is a useful diagram that helps users visualize data and identify patterns in a data set.
|
||||
|
@ -6,6 +6,24 @@
|
||||
|
||||
# Blog
|
||||
|
||||
## [subhash-halder contributed quadrant charts so you can show your manager what to select - just like the strategy consultants at BCG do](https://www.mermaidchart.com/blog/posts/subhash-halder-contributed-quadrant-charts-so-you-can-show-your-manager-what-to-select-just-like-the-strategy-consultants-at-bcg-do/)
|
||||
|
||||
8 June 2023 · 7 mins
|
||||
|
||||
A quadrant chart is a useful diagram that helps users visualize data and identify patterns in a data set.
|
||||
|
||||
## [Bad documentation is bad for developers](https://www.mermaidchart.com/blog/posts/bad-documentation-is-bad-for-developers)
|
||||
|
||||
26 April 2023 · 11 mins
|
||||
|
||||
Documentation tends to be bad because companies and projects don’t fully realize the costs of bad documentation.
|
||||
|
||||
## [Automatic text wrapping in flowcharts is here!](https://www.mermaidchart.com/blog/posts/automatic-text-wrapping-in-flowcharts-is-here/)
|
||||
|
||||
3 April 2023 · 3 mins
|
||||
|
||||
Markdown Strings reduce the hassle # Starting from v10.
|
||||
|
||||
## [Mermaid Chart officially launched with sharable diagram links and presentation mode](https://www.mermaidchart.com/blog/posts/mermaid-chart-officially-launched-with-sharable-diagram-links-and-presentation-mode/)
|
||||
|
||||
27 March 2023 · 2 mins
|
||||
|
@ -421,6 +421,34 @@ And `Link` can be one of:
|
||||
| -- | Solid |
|
||||
| .. | Dashed |
|
||||
|
||||
## Define Namespace
|
||||
|
||||
A namespace groups classes.
|
||||
|
||||
Code:
|
||||
|
||||
```mermaid-example
|
||||
classDiagram
|
||||
namespace BaseShapes {
|
||||
class Triangle
|
||||
class Rectangle {
|
||||
double width
|
||||
double height
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
namespace BaseShapes {
|
||||
class Triangle
|
||||
class Rectangle {
|
||||
double width
|
||||
double height
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Cardinality / Multiplicity on relations
|
||||
|
||||
Multiplicity or cardinality in class diagrams indicates the number of instances of one class that can be linked to an instance of the other class. For example, each company will have one or more employees (not zero), and each employee currently works for zero or one companies.
|
||||
|
@ -6,11 +6,10 @@
|
||||
|
||||
# Flowcharts - Basic Syntax
|
||||
|
||||
All Flowcharts are composed of **nodes**, the geometric shapes and **edges**, the arrows or lines. The mermaid code defines the way that these **nodes** and **edges** are made and interact.
|
||||
Flowcharts are composed of **nodes** (geometric shapes) and **edges** (arrows or lines). The Mermaid code defines how nodes and edges are made and accommodates different arrow types, multi-directional arrows, and any linking to and from subgraphs.
|
||||
|
||||
It can also accommodate different arrow types, multi directional arrows, and linking to and from subgraphs.
|
||||
|
||||
> **Important note**: Do not type the word "end" as a Flowchart node. Capitalize all or any one the letters to keep the flowchart from breaking, i.e, "End" or "END". Or you can apply this [workaround](https://github.com/mermaid-js/mermaid/issues/1444#issuecomment-639528897).
|
||||
> **Warning**
|
||||
> If you are using the word "end" in a Flowchart node, capitalize the entire word or any of the letters (e.g., "End" or "END"), or apply this [workaround](https://github.com/mermaid-js/mermaid/issues/1444#issuecomment-639528897). Typing "end" in all lowercase letters will break the Flowchart.
|
||||
|
||||
### A node (default)
|
||||
|
||||
@ -33,6 +32,9 @@ flowchart LR
|
||||
> **Note**
|
||||
> The id is what is displayed in the box.
|
||||
|
||||
> **💡 Tip**
|
||||
> Instead of `flowchart` one can also use `graph`.
|
||||
|
||||
### A node with text
|
||||
|
||||
It is also possible to set text in the box that differs from the id. If this is done several times, it is the last text
|
||||
@ -55,7 +57,45 @@ flowchart LR
|
||||
id1[This is the text in the box]
|
||||
```
|
||||
|
||||
## Graph
|
||||
#### Unicode text
|
||||
|
||||
Use `"` to enclose the unicode text.
|
||||
|
||||
```mermaid-example
|
||||
flowchart LR
|
||||
id["This ❤ Unicode"]
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
id["This ❤ Unicode"]
|
||||
```
|
||||
|
||||
#### Markdown formatting
|
||||
|
||||
Use double quotes and backticks "\` text \`" to enclose the markdown text.
|
||||
|
||||
```mermaid-example
|
||||
%%{init: {"flowchart": {"htmlLabels": false}} }%%
|
||||
flowchart LR
|
||||
markdown["`This **is** _Markdown_`"]
|
||||
newLines["`Line1
|
||||
Line 2
|
||||
Line 3`"]
|
||||
markdown --> newLines
|
||||
```
|
||||
|
||||
```mermaid
|
||||
%%{init: {"flowchart": {"htmlLabels": false}} }%%
|
||||
flowchart LR
|
||||
markdown["`This **is** _Markdown_`"]
|
||||
newLines["`Line1
|
||||
Line 2
|
||||
Line 3`"]
|
||||
markdown --> newLines
|
||||
```
|
||||
|
||||
### Direction
|
||||
|
||||
This statement declares the direction of the Flowchart.
|
||||
|
||||
@ -83,15 +123,13 @@ flowchart LR
|
||||
Start --> Stop
|
||||
```
|
||||
|
||||
## Flowchart Orientation
|
||||
|
||||
Possible FlowChart orientations are:
|
||||
|
||||
- TB - top to bottom
|
||||
- TD - top-down/ same as top to bottom
|
||||
- BT - bottom to top
|
||||
- RL - right to left
|
||||
- LR - left to right
|
||||
- TB - Top to bottom
|
||||
- TD - Top-down/ same as top to bottom
|
||||
- BT - Bottom to top
|
||||
- RL - Right to left
|
||||
- LR - Left to right
|
||||
|
||||
## Node shapes
|
||||
|
||||
@ -634,7 +672,7 @@ flowchart TB
|
||||
end
|
||||
```
|
||||
|
||||
## flowcharts
|
||||
### flowcharts
|
||||
|
||||
With the graphtype flowchart it is also possible to set edges to and from subgraphs as in the flowchart below.
|
||||
|
||||
@ -672,7 +710,7 @@ flowchart TB
|
||||
two --> c2
|
||||
```
|
||||
|
||||
## Direction in subgraphs
|
||||
### Direction in subgraphs
|
||||
|
||||
With the graphtype flowcharts you can use the direction statement to set the direction which the subgraph will render like in this example.
|
||||
|
||||
@ -750,7 +788,10 @@ This feature is applicable to node labels, edge labels, and subgraph labels.
|
||||
|
||||
## Interaction
|
||||
|
||||
It is possible to bind a click event to a node, the click can lead to either a javascript callback or to a link which will be opened in a new browser tab. **Note**: This functionality is disabled when using `securityLevel='strict'` and enabled when using `securityLevel='loose'`.
|
||||
It is possible to bind a click event to a node, the click can lead to either a javascript callback or to a link which will be opened in a new browser tab.
|
||||
|
||||
> **Note**
|
||||
> This functionality is disabled when using `securityLevel='strict'` and enabled when using `securityLevel='loose'`.
|
||||
|
||||
click nodeId callback
|
||||
click nodeId call callback()
|
||||
@ -1042,7 +1083,8 @@ You can change the renderer to elk by adding this directive:
|
||||
|
||||
%%{init: {"flowchart": {"defaultRenderer": "elk"}} }%%
|
||||
|
||||
Note that the site needs to use mermaid version 9.4+ for this to work and have this featured enabled in the lazy-loading configuration.
|
||||
> **Note**
|
||||
> Note that the site needs to use mermaid version 9.4+ for this to work and have this featured enabled in the lazy-loading configuration.
|
||||
|
||||
### Width
|
||||
|
||||
|
BIN
docs/syntax/img/zenuml-participant-annotators.png
Normal file
BIN
docs/syntax/img/zenuml-participant-annotators.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 255 KiB |
168
docs/syntax/quadrantChart.md
Normal file
168
docs/syntax/quadrantChart.md
Normal file
@ -0,0 +1,168 @@
|
||||
> **Warning**
|
||||
>
|
||||
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
|
||||
>
|
||||
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/syntax/quadrantChart.md](../../packages/mermaid/src/docs/syntax/quadrantChart.md).
|
||||
|
||||
# Quadrant Chart
|
||||
|
||||
> A quadrant chart is a visual representation of data that is divided into four quadrants. It is used to plot data points on a two-dimensional grid, with one variable represented on the x-axis and another variable represented on the y-axis. The quadrants are determined by dividing the chart into four equal parts based on a set of criteria that is specific to the data being analyzed. Quadrant charts are often used to identify patterns and trends in data, and to prioritize actions based on the position of data points within the chart. They are commonly used in business, marketing, and risk management, among other fields.
|
||||
|
||||
## Example
|
||||
|
||||
```mermaid-example
|
||||
quadrantChart
|
||||
title Reach and engagement of campaigns
|
||||
x-axis Low Reach --> High Reach
|
||||
y-axis Low Engagement --> High Engagement
|
||||
quadrant-1 We should expand
|
||||
quadrant-2 Need to promote
|
||||
quadrant-3 Re-evaluate
|
||||
quadrant-4 May be improved
|
||||
Campaign A: [0.3, 0.6]
|
||||
Campaign B: [0.45, 0.23]
|
||||
Campaign C: [0.57, 0.69]
|
||||
Campaign D: [0.78, 0.34]
|
||||
Campaign E: [0.40, 0.34]
|
||||
Campaign F: [0.35, 0.78]
|
||||
```
|
||||
|
||||
```mermaid
|
||||
quadrantChart
|
||||
title Reach and engagement of campaigns
|
||||
x-axis Low Reach --> High Reach
|
||||
y-axis Low Engagement --> High Engagement
|
||||
quadrant-1 We should expand
|
||||
quadrant-2 Need to promote
|
||||
quadrant-3 Re-evaluate
|
||||
quadrant-4 May be improved
|
||||
Campaign A: [0.3, 0.6]
|
||||
Campaign B: [0.45, 0.23]
|
||||
Campaign C: [0.57, 0.69]
|
||||
Campaign D: [0.78, 0.34]
|
||||
Campaign E: [0.40, 0.34]
|
||||
Campaign F: [0.35, 0.78]
|
||||
```
|
||||
|
||||
## Syntax
|
||||
|
||||
> **Note**
|
||||
> If there is no points available in the chart both **axis** text and **quadrant** will be rendered in the center of the respective quadrant.
|
||||
> If there are points **x-axis** labels will rendered from left of the respective quadrant also they will be displayed in bottom of the chart, and **y-axis** lables will be rendered in bottom of the respective quadrant, the quadrant text will render at top of the respective quadrant.
|
||||
|
||||
> **Note**
|
||||
> For points x and y value min value is 0 and max value is 1.
|
||||
|
||||
### Title
|
||||
|
||||
The title is a short description of the chart and it will always render on top of the chart.
|
||||
|
||||
#### Example
|
||||
|
||||
quadrantChart
|
||||
title This is a sample example
|
||||
|
||||
### x-axis
|
||||
|
||||
The x-axis determine what text would be displayed in the x-axis. In x-axis there is two part **left** and **right** you can pass **both** or you can pass only **left**. The statement should start with `x-axis` then the `left axis text` followed by the delimiter `-->` then `right axis text`.
|
||||
|
||||
#### Example
|
||||
|
||||
1. `x-axis <text> --> <text>` both the left and right axis text will be rendered.
|
||||
2. `x-axis <text>` only the left axis text will be rendered.
|
||||
|
||||
### y-axis
|
||||
|
||||
The y-axis determine what text would be displayed in the y-axis. In y-axis there is two part **top** and **bottom** you can pass **both** or you can pass only **bottom**. The statement should start with `y-axis` then the `bottom axis text` followed by the delimiter `-->` then `top axis text`.
|
||||
|
||||
#### Example
|
||||
|
||||
1. `y-axis <text> --> <text>` both the bottom and top axis text will be rendered.
|
||||
2. `y-axis <text>` only the bottom axis text will be rendered.
|
||||
|
||||
### Quadrants text
|
||||
|
||||
The `quadrant-[1,2,3,4]` determine what text would be displayed inside the quadrants.
|
||||
|
||||
#### Example
|
||||
|
||||
1. `quadrant-1 <text>` determine what text will be rendered inside the top right quadrant.
|
||||
2. `quadrant-2 <text>` determine what text will be rendered inside the top left quadrant.
|
||||
3. `quadrant-3 <text>` determine what text will be rendered inside the bottom left quadrant.
|
||||
4. `quadrant-4 <text>` determine what text will be rendered inside the bottom right quadrant.
|
||||
|
||||
### Points
|
||||
|
||||
Points are used to plot a circle inside the quadrantChart. The syntax is `<text>: [x, y]` here x and y value is in the range 0 - 1.
|
||||
|
||||
#### Example
|
||||
|
||||
1. `Point 1: [0.75, 0.80]` here the Point 1 will be drawn in the top right quadrant.
|
||||
2. `Point 2: [0.35, 0.24]` here the Point 2 will be drawn in the bottom left quadrant.
|
||||
|
||||
## Chart Configurations
|
||||
|
||||
| Parameter | Description | Default value |
|
||||
| --------------------------------- | ------------------------------------------------------------------------------------------------- | :-----------: |
|
||||
| chartWidth | Width of the chart | 500 |
|
||||
| chartHeight | Height of the chart | 500 |
|
||||
| titlePadding | Top and Bottom padding of the title | 10 |
|
||||
| titleFontSize | Title font size | 20 |
|
||||
| quadrantPadding | Padding outside all the quadrants | 5 |
|
||||
| quadrantTextTopPadding | Quadrant text top padding when text is drawn on top ( not data points are there) | 5 |
|
||||
| quadrantLabelFontSize | Quadrant text font size | 16 |
|
||||
| quadrantInternalBorderStrokeWidth | Border stroke width inside the quadrants | 1 |
|
||||
| quadrantExternalBorderStrokeWidth | Quadrant external border stroke width | 2 |
|
||||
| xAxisLabelPadding | Top and bottom padding of x-axis text | 5 |
|
||||
| xAxisLabelFontSize | X-axis texts font size | 16 |
|
||||
| xAxisPosition | Position of x-axis (top , bottom) if there are points the x-axis will alway be rendered in bottom | 'top' |
|
||||
| yAxisLabelPadding | Left and Right padding of y-axis text | 5 |
|
||||
| yAxisLabelFontSize | Y-axis texts font size | 16 |
|
||||
| yAxisPosition | Position of y-axis (left , right) | 'left' |
|
||||
| pointTextPadding | Padding between point and the below text | 5 |
|
||||
| pointLabelFontSize | Point text font size | 12 |
|
||||
| pointRadius | Radius of the point to be drawn | 5 |
|
||||
|
||||
## Chart Theme Variables
|
||||
|
||||
| Parameter | Description |
|
||||
| -------------------------------- | --------------------------------------- |
|
||||
| quadrant1Fill | Fill color of the top right quadrant |
|
||||
| quadrant2Fill | Fill color of the top left quadrant |
|
||||
| quadrant3Fill | Fill color of the bottom left quadrant |
|
||||
| quadrant4Fill | Fill color of the bottom right quadrant |
|
||||
| quadrant1TextFill | Text color of the top right quadrant |
|
||||
| quadrant2TextFill | Text color of the top left quadrant |
|
||||
| quadrant3TextFill | Text color of the bottom left quadrant |
|
||||
| quadrant4TextFill | Text color of the bottom right quadrant |
|
||||
| quadrantPointFill | Points fill color |
|
||||
| quadrantPointTextFill | Points text color |
|
||||
| quadrantXAxisTextFill | X-axis text color |
|
||||
| quadrantYAxisTextFill | Y-axis text color |
|
||||
| quadrantInternalBorderStrokeFill | Quadrants inner border color |
|
||||
| quadrantExternalBorderStrokeFill | Quadrants outer border color |
|
||||
| quadrantTitleFill | Title color |
|
||||
|
||||
## Example on config and theme
|
||||
|
||||
```mermaid-example
|
||||
%%{init: {"quadrantChart": {"chartWidth": 400, "chartHeight": 400}, "themeVariables": {"quadrant1TextFill": "#ff0000"} }}%%
|
||||
quadrantChart
|
||||
x-axis Urgent --> Not Urgent
|
||||
y-axis Not Important --> "Important ❤"
|
||||
quadrant-1 Plan
|
||||
quadrant-2 Do
|
||||
quadrant-3 Deligate
|
||||
quadrant-4 Delete
|
||||
```
|
||||
|
||||
```mermaid
|
||||
%%{init: {"quadrantChart": {"chartWidth": 400, "chartHeight": 400}, "themeVariables": {"quadrant1TextFill": "#ff0000"} }}%%
|
||||
quadrantChart
|
||||
x-axis Urgent --> Not Urgent
|
||||
y-axis Not Important --> "Important ❤"
|
||||
quadrant-1 Plan
|
||||
quadrant-2 Do
|
||||
quadrant-3 Deligate
|
||||
quadrant-4 Delete
|
||||
```
|
@ -137,7 +137,7 @@ timeline
|
||||
section Stone Age
|
||||
7600 BC : Britain's oldest known house was built in Orkney, Scotland
|
||||
6000 BC : Sea levels rise and Britain becomes an island.<br> The people who live here are hunter-gatherers.
|
||||
section Broze Age
|
||||
section Bronze Age
|
||||
2300 BC : People arrive from Europe and settle in Britain. <br>They bring farming and metalworking.
|
||||
: New styles of pottery and ways of burying the dead appear.
|
||||
2200 BC : The last major building works are completed at Stonehenge.<br> People now bury their dead in stone circles.
|
||||
@ -151,7 +151,7 @@ timeline
|
||||
section Stone Age
|
||||
7600 BC : Britain's oldest known house was built in Orkney, Scotland
|
||||
6000 BC : Sea levels rise and Britain becomes an island.<br> The people who live here are hunter-gatherers.
|
||||
section Broze Age
|
||||
section Bronze Age
|
||||
2300 BC : People arrive from Europe and settle in Britain. <br>They bring farming and metalworking.
|
||||
: New styles of pottery and ways of burying the dead appear.
|
||||
2200 BC : The last major building works are completed at Stonehenge.<br> People now bury their dead in stone circles.
|
||||
|
472
docs/syntax/zenuml.md
Normal file
472
docs/syntax/zenuml.md
Normal file
@ -0,0 +1,472 @@
|
||||
> **Warning**
|
||||
>
|
||||
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
|
||||
>
|
||||
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/syntax/zenuml.md](../../packages/mermaid/src/docs/syntax/zenuml.md).
|
||||
|
||||
# ZenUML
|
||||
|
||||
> A Sequence diagram is an interaction diagram that shows how processes operate with one another and in what order.
|
||||
|
||||
Mermaid can render sequence diagrams with [ZenUML](https://zenuml.com). Note that ZenUML uses a different
|
||||
syntax than the original Sequence Diagram in mermaid.
|
||||
|
||||
```mermaid-example
|
||||
zenuml
|
||||
title Demo
|
||||
Alice->John: Hello John, how are you?
|
||||
John->Alice: Great!
|
||||
Alice->John: See you later!
|
||||
```
|
||||
|
||||
```mermaid
|
||||
zenuml
|
||||
title Demo
|
||||
Alice->John: Hello John, how are you?
|
||||
John->Alice: Great!
|
||||
Alice->John: See you later!
|
||||
```
|
||||
|
||||
## Syntax
|
||||
|
||||
### Participants
|
||||
|
||||
The participants can be defined implicitly as in the first example on this page. The participants or actors are
|
||||
rendered in order of appearance in the diagram source text. Sometimes you might want to show the participants in a
|
||||
different order than how they appear in the first message. It is possible to specify the actor's order of
|
||||
appearance by doing the following:
|
||||
|
||||
```mermaid-example
|
||||
zenuml
|
||||
title Declare participant (optional)
|
||||
Bob
|
||||
Alice
|
||||
Alice->Bob: Hi Bob
|
||||
Bob->Alice: Hi Alice
|
||||
```
|
||||
|
||||
```mermaid
|
||||
zenuml
|
||||
title Declare participant (optional)
|
||||
Bob
|
||||
Alice
|
||||
Alice->Bob: Hi Bob
|
||||
Bob->Alice: Hi Alice
|
||||
```
|
||||
|
||||
### Annotators
|
||||
|
||||
If you specifically want to use symbols instead of just rectangles with text you can do so by using the annotator syntax to declare participants as per below.
|
||||
|
||||
```mermaid-example
|
||||
zenuml
|
||||
title Annotators
|
||||
@Actor Alice
|
||||
@Database Bob
|
||||
Alice->Bob: Hi Bob
|
||||
Bob->Alice: Hi Alice
|
||||
```
|
||||
|
||||
```mermaid
|
||||
zenuml
|
||||
title Annotators
|
||||
@Actor Alice
|
||||
@Database Bob
|
||||
Alice->Bob: Hi Bob
|
||||
Bob->Alice: Hi Alice
|
||||
```
|
||||
|
||||
Here are the available annotators:
|
||||
![img.png](img/zenuml-participant-annotators.png)
|
||||
|
||||
### Aliases
|
||||
|
||||
The participants can have a convenient identifier and a descriptive label.
|
||||
|
||||
```mermaid-example
|
||||
zenuml
|
||||
title Aliases
|
||||
A as Alice
|
||||
J as John
|
||||
A->J: Hello John, how are you?
|
||||
J->A: Great!
|
||||
```
|
||||
|
||||
```mermaid
|
||||
zenuml
|
||||
title Aliases
|
||||
A as Alice
|
||||
J as John
|
||||
A->J: Hello John, how are you?
|
||||
J->A: Great!
|
||||
```
|
||||
|
||||
## Messages
|
||||
|
||||
Messages can be one of:
|
||||
|
||||
1. Sync message
|
||||
2. Async message
|
||||
3. Creation message
|
||||
4. Reply message
|
||||
|
||||
### Sync message
|
||||
|
||||
You can think of a sync (blocking) method in a programming language.
|
||||
|
||||
```mermaid-example
|
||||
zenuml
|
||||
title Sync message
|
||||
A.SyncMessage
|
||||
A.SyncMessage(with, parameters) {
|
||||
B.nestedSyncMessage()
|
||||
}
|
||||
```
|
||||
|
||||
```mermaid
|
||||
zenuml
|
||||
title Sync message
|
||||
A.SyncMessage
|
||||
A.SyncMessage(with, parameters) {
|
||||
B.nestedSyncMessage()
|
||||
}
|
||||
```
|
||||
|
||||
### Async message
|
||||
|
||||
You can think of an async (non-blocking) method in a programming language.
|
||||
Fire an event and forget about it.
|
||||
|
||||
```mermaid-example
|
||||
zenuml
|
||||
title Async message
|
||||
Alice->Bob: How are you?
|
||||
```
|
||||
|
||||
```mermaid
|
||||
zenuml
|
||||
title Async message
|
||||
Alice->Bob: How are you?
|
||||
```
|
||||
|
||||
### Creation message
|
||||
|
||||
We use `new` keyword to create an object.
|
||||
|
||||
```mermaid-example
|
||||
zenuml
|
||||
new A1
|
||||
new A2(with, parameters)
|
||||
```
|
||||
|
||||
```mermaid
|
||||
zenuml
|
||||
new A1
|
||||
new A2(with, parameters)
|
||||
```
|
||||
|
||||
### Reply message
|
||||
|
||||
There are three ways to express a reply message:
|
||||
|
||||
```mermaid-example
|
||||
zenuml
|
||||
// 1. assign a variable from a sync message.
|
||||
a = A.SyncMessage()
|
||||
|
||||
// 1.1. optionally give the variable a type
|
||||
SomeType a = A.SyncMessage()
|
||||
|
||||
// 2. use return keyword
|
||||
A.SyncMessage() {
|
||||
return result
|
||||
}
|
||||
|
||||
// 3. use @return or @reply annotator on an async message
|
||||
@return
|
||||
A->B: result
|
||||
```
|
||||
|
||||
```mermaid
|
||||
zenuml
|
||||
// 1. assign a variable from a sync message.
|
||||
a = A.SyncMessage()
|
||||
|
||||
// 1.1. optionally give the variable a type
|
||||
SomeType a = A.SyncMessage()
|
||||
|
||||
// 2. use return keyword
|
||||
A.SyncMessage() {
|
||||
return result
|
||||
}
|
||||
|
||||
// 3. use @return or @reply annotator on an async message
|
||||
@return
|
||||
A->B: result
|
||||
```
|
||||
|
||||
The third way `@return` is rarely used, but it is useful when you want to return to one level up.
|
||||
|
||||
```mermaid-example
|
||||
zenuml
|
||||
title Reply message
|
||||
Client->A.method() {
|
||||
B.method() {
|
||||
if(condition) {
|
||||
return x1
|
||||
// return early
|
||||
@return
|
||||
A->Client: x11
|
||||
}
|
||||
}
|
||||
return x2
|
||||
}
|
||||
```
|
||||
|
||||
```mermaid
|
||||
zenuml
|
||||
title Reply message
|
||||
Client->A.method() {
|
||||
B.method() {
|
||||
if(condition) {
|
||||
return x1
|
||||
// return early
|
||||
@return
|
||||
A->Client: x11
|
||||
}
|
||||
}
|
||||
return x2
|
||||
}
|
||||
```
|
||||
|
||||
## Nesting
|
||||
|
||||
Sync messages and Creation messages are naturally nestable with `{}`.
|
||||
|
||||
```mermaid-example
|
||||
zenuml
|
||||
A.method() {
|
||||
B.nested_sync_method()
|
||||
B->C: nested async message
|
||||
}
|
||||
```
|
||||
|
||||
```mermaid
|
||||
zenuml
|
||||
A.method() {
|
||||
B.nested_sync_method()
|
||||
B->C: nested async message
|
||||
}
|
||||
```
|
||||
|
||||
## Comments
|
||||
|
||||
It is possible to add comments to a sequence diagram with `// comment` syntax.
|
||||
Comments will be rendered above the messages or fragments. Comments on other places
|
||||
are ignored. Markdown is supported.
|
||||
|
||||
See the example below:
|
||||
|
||||
```mermaid-example
|
||||
zenuml
|
||||
// a comment on a participant will not be rendered
|
||||
BookService
|
||||
// a comment on a message.
|
||||
// **Markdown** is supported.
|
||||
BookService.getBook()
|
||||
```
|
||||
|
||||
```mermaid
|
||||
zenuml
|
||||
// a comment on a participant will not be rendered
|
||||
BookService
|
||||
// a comment on a message.
|
||||
// **Markdown** is supported.
|
||||
BookService.getBook()
|
||||
```
|
||||
|
||||
## Loops
|
||||
|
||||
It is possible to express loops in a ZenUML diagram. This is done by any of the
|
||||
following notations:
|
||||
|
||||
1. while
|
||||
2. for
|
||||
3. forEach, foreach
|
||||
4. loop
|
||||
|
||||
```zenuml
|
||||
while(condition) {
|
||||
...statements...
|
||||
}
|
||||
```
|
||||
|
||||
See the example below:
|
||||
|
||||
```mermaid-example
|
||||
zenuml
|
||||
Alice->John: Hello John, how are you?
|
||||
while(true) {
|
||||
John->Alice: Great!
|
||||
}
|
||||
```
|
||||
|
||||
```mermaid
|
||||
zenuml
|
||||
Alice->John: Hello John, how are you?
|
||||
while(true) {
|
||||
John->Alice: Great!
|
||||
}
|
||||
```
|
||||
|
||||
## Alt
|
||||
|
||||
It is possible to express alternative paths in a sequence diagram. This is done by the notation
|
||||
|
||||
```zenuml
|
||||
if(condition1) {
|
||||
...statements...
|
||||
} else if(condition2) {
|
||||
...statements...
|
||||
} else {
|
||||
...statements...
|
||||
}
|
||||
```
|
||||
|
||||
See the example below:
|
||||
|
||||
```mermaid-example
|
||||
zenuml
|
||||
Alice->Bob: Hello Bob, how are you?
|
||||
if(is_sick) {
|
||||
Bob->Alice: Not so good :(
|
||||
} else {
|
||||
Bob->Alice: Feeling fresh like a daisy
|
||||
}
|
||||
```
|
||||
|
||||
```mermaid
|
||||
zenuml
|
||||
Alice->Bob: Hello Bob, how are you?
|
||||
if(is_sick) {
|
||||
Bob->Alice: Not so good :(
|
||||
} else {
|
||||
Bob->Alice: Feeling fresh like a daisy
|
||||
}
|
||||
```
|
||||
|
||||
## Opt
|
||||
|
||||
It is possible to render an `opt` fragment. This is done by the notation
|
||||
|
||||
```zenuml
|
||||
opt {
|
||||
...statements...
|
||||
}
|
||||
```
|
||||
|
||||
See the example below:
|
||||
|
||||
```mermaid-example
|
||||
zenuml
|
||||
Alice->Bob: Hello Bob, how are you?
|
||||
Bob->Alice: Not so good :(
|
||||
opt {
|
||||
Bob->Alice: Thanks for asking
|
||||
}
|
||||
```
|
||||
|
||||
```mermaid
|
||||
zenuml
|
||||
Alice->Bob: Hello Bob, how are you?
|
||||
Bob->Alice: Not so good :(
|
||||
opt {
|
||||
Bob->Alice: Thanks for asking
|
||||
}
|
||||
```
|
||||
|
||||
## Parallel
|
||||
|
||||
It is possible to show actions that are happening in parallel.
|
||||
|
||||
This is done by the notation
|
||||
|
||||
```zenuml
|
||||
par {
|
||||
statement1
|
||||
statement2
|
||||
statement3
|
||||
}
|
||||
```
|
||||
|
||||
See the example below:
|
||||
|
||||
```mermaid-example
|
||||
zenuml
|
||||
par {
|
||||
Alice->Bob: Hello guys!
|
||||
Alice->John: Hello guys!
|
||||
}
|
||||
```
|
||||
|
||||
```mermaid
|
||||
zenuml
|
||||
par {
|
||||
Alice->Bob: Hello guys!
|
||||
Alice->John: Hello guys!
|
||||
}
|
||||
```
|
||||
|
||||
## Try/Catch/Finally (Break)
|
||||
|
||||
It is possible to indicate a stop of the sequence within the flow (usually used to model exceptions).
|
||||
|
||||
This is done by the notation
|
||||
|
||||
try {
|
||||
...statements...
|
||||
} catch {
|
||||
...statements...
|
||||
} finally {
|
||||
...statements...
|
||||
}
|
||||
|
||||
See the example below:
|
||||
|
||||
```mermaid-example
|
||||
zenuml
|
||||
try {
|
||||
Consumer->API: Book something
|
||||
API->BookingService: Start booking process
|
||||
} catch {
|
||||
API->Consumer: show failure
|
||||
} finally {
|
||||
API->BookingService: rollback status
|
||||
}
|
||||
```
|
||||
|
||||
```mermaid
|
||||
zenuml
|
||||
try {
|
||||
Consumer->API: Book something
|
||||
API->BookingService: Start booking process
|
||||
} catch {
|
||||
API->Consumer: show failure
|
||||
} finally {
|
||||
API->BookingService: rollback status
|
||||
}
|
||||
```
|
||||
|
||||
## Integrating with your library/website.
|
||||
|
||||
Zenuml uses the experimental lazy loading & async rendering features which could change in the future.
|
||||
|
||||
You can use this method to add mermaid including the zenuml diagram to a web page:
|
||||
|
||||
```html
|
||||
<script type="module">
|
||||
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
|
||||
import zenuml from 'https://cdn.jsdelivr.net/npm/@mermaid-js/mermaid-zenuml@0.1.0/dist/mermaid-zenuml.esm.min.mjs';
|
||||
await mermaid.registerExternalDiagrams([zenuml]);
|
||||
</script>
|
||||
```
|
37
package.json
37
package.json
@ -1,10 +1,10 @@
|
||||
{
|
||||
"name": "mermaid-monorepo",
|
||||
"private": true,
|
||||
"version": "10.1.0",
|
||||
"version": "10.2.3",
|
||||
"description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
|
||||
"type": "module",
|
||||
"packageManager": "pnpm@8.3.1",
|
||||
"packageManager": "pnpm@8.6.2",
|
||||
"keywords": [
|
||||
"diagram",
|
||||
"markdown",
|
||||
@ -18,17 +18,22 @@
|
||||
"build:vite": "ts-node-esm --transpileOnly .vite/build.ts",
|
||||
"build:mermaid": "pnpm build:vite --mermaid",
|
||||
"build:viz": "pnpm build:mermaid --visualize",
|
||||
"build:types": "tsc -p ./packages/mermaid/tsconfig.json --emitDeclarationOnly && tsc -p ./packages/mermaid-example-diagram/tsconfig.json --emitDeclarationOnly",
|
||||
"build:types": "tsc -p ./packages/mermaid/tsconfig.json --emitDeclarationOnly && tsc -p ./packages/mermaid-zenuml/tsconfig.json --emitDeclarationOnly && tsc -p ./packages/mermaid-example-diagram/tsconfig.json --emitDeclarationOnly",
|
||||
"build:watch": "pnpm build:vite --watch",
|
||||
"build": "pnpm run -r clean && pnpm build:types && pnpm build:vite",
|
||||
"dev": "concurrently \"pnpm build:vite --watch\" \"ts-node-esm .vite/server.ts\"",
|
||||
"dev:coverage": "VITE_COVERAGE=true pnpm dev",
|
||||
"release": "pnpm build",
|
||||
"lint": "eslint --cache --cache-strategy content --ignore-path .gitignore . && pnpm lint:jison && prettier --cache --check .",
|
||||
"lint:fix": "eslint --cache --cache-strategy content --fix --ignore-path .gitignore . && prettier --write . && ts-node-esm scripts/fixCSpell.ts",
|
||||
"lint:jison": "ts-node-esm ./scripts/jison/lint.mts",
|
||||
"contributors": "ts-node-esm scripts/updateContributors.ts",
|
||||
"cypress": "cypress run",
|
||||
"cypress:open": "cypress open",
|
||||
"e2e": "start-server-and-test dev http://localhost:9000/ cypress",
|
||||
"e2e:coverage": "VITE_COVERAGE=true pnpm e2e",
|
||||
"coverage:merge": "ts-node-esm scripts/coverage.ts",
|
||||
"coverage": "pnpm test:coverage --run && pnpm e2e:coverage && pnpm coverage:merge",
|
||||
"ci": "vitest run",
|
||||
"test": "pnpm lint && vitest run",
|
||||
"test:watch": "vitest --watch",
|
||||
@ -54,11 +59,12 @@
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@applitools/eyes-cypress": "^3.32.0",
|
||||
"@applitools/eyes-cypress": "^3.33.1",
|
||||
"@commitlint/cli": "^17.6.1",
|
||||
"@commitlint/config-conventional": "^17.6.1",
|
||||
"@cspell/eslint-plugin": "^6.31.1",
|
||||
"@rollup/plugin-typescript": "^11.1.0",
|
||||
"@cypress/code-coverage": "^3.10.7",
|
||||
"@rollup/plugin-typescript": "^11.1.1",
|
||||
"@types/cors": "^2.8.13",
|
||||
"@types/eslint": "^8.37.0",
|
||||
"@types/express": "^4.17.17",
|
||||
@ -71,15 +77,15 @@
|
||||
"@types/rollup-plugin-visualizer": "^4.2.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.59.0",
|
||||
"@typescript-eslint/parser": "^5.59.0",
|
||||
"@vitest/coverage-c8": "^0.30.1",
|
||||
"@vitest/spy": "^0.30.1",
|
||||
"@vitest/ui": "^0.30.1",
|
||||
"@vitest/coverage-istanbul": "^0.32.2",
|
||||
"@vitest/spy": "^0.32.2",
|
||||
"@vitest/ui": "^0.32.2",
|
||||
"concurrently": "^8.0.1",
|
||||
"cors": "^2.8.5",
|
||||
"coveralls": "^3.1.1",
|
||||
"cypress": "^12.10.0",
|
||||
"cypress-image-snapshot": "^4.0.1",
|
||||
"esbuild": "^0.17.18",
|
||||
"esbuild": "^0.18.0",
|
||||
"eslint": "^8.39.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-plugin-cypress": "^2.13.2",
|
||||
@ -100,19 +106,24 @@
|
||||
"js-yaml": "^4.1.0",
|
||||
"jsdom": "^21.1.1",
|
||||
"lint-staged": "^13.2.1",
|
||||
"nyc": "^15.1.0",
|
||||
"path-browserify": "^1.0.1",
|
||||
"pnpm": "^8.3.1",
|
||||
"prettier": "^2.8.8",
|
||||
"prettier-plugin-jsdoc": "^0.4.2",
|
||||
"rimraf": "^5.0.0",
|
||||
"rollup-plugin-visualizer": "^5.9.0",
|
||||
"rollup-plugin-visualizer": "^5.9.2",
|
||||
"start-server-and-test": "^2.0.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^5.0.4",
|
||||
"vite": "^4.3.1",
|
||||
"vitest": "^0.30.1"
|
||||
"typescript": "^5.1.3",
|
||||
"vite": "^4.3.9",
|
||||
"vite-plugin-istanbul": "^4.1.0",
|
||||
"vitest": "^0.32.2"
|
||||
},
|
||||
"volta": {
|
||||
"node": "18.16.0"
|
||||
},
|
||||
"nyc": {
|
||||
"report-dir": "coverage/cypress"
|
||||
}
|
||||
}
|
||||
|
@ -52,9 +52,6 @@
|
||||
"rimraf": "^5.0.0",
|
||||
"mermaid": "workspace:*"
|
||||
},
|
||||
"resolutions": {
|
||||
"d3": "^7.0.0"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
|
@ -3,7 +3,7 @@ import type { ExternalDiagramDefinition } from 'mermaid';
|
||||
const id = 'example-diagram';
|
||||
|
||||
const detector = (txt: string) => {
|
||||
return txt.match(/^\s*example-diagram/) !== null;
|
||||
return /^\s*example-diagram/.test(txt);
|
||||
};
|
||||
|
||||
const loader = async () => {
|
||||
|
1
packages/mermaid-zenuml/README.md
Symbolic link
1
packages/mermaid-zenuml/README.md
Symbolic link
@ -0,0 +1 @@
|
||||
../mermaid/src/docs/syntax/zenuml.md
|
47
packages/mermaid-zenuml/package.json
Normal file
47
packages/mermaid-zenuml/package.json
Normal file
@ -0,0 +1,47 @@
|
||||
{
|
||||
"name": "@mermaid-js/mermaid-zenuml",
|
||||
"version": "0.1.0",
|
||||
"description": "MermaidJS plugin for ZenUML integration",
|
||||
"module": "dist/mermaid-zenuml.core.mjs",
|
||||
"types": "dist/detector.d.ts",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/mermaid-zenuml.core.mjs",
|
||||
"types": "./dist/detector.d.ts"
|
||||
},
|
||||
"./*": "./*"
|
||||
},
|
||||
"keywords": [
|
||||
"diagram",
|
||||
"markdown",
|
||||
"zenuml",
|
||||
"mermaid"
|
||||
],
|
||||
"scripts": {
|
||||
"prepublishOnly": "pnpm -w run build"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mermaid-js/mermaid",
|
||||
"directory": "packages/mermaid-zenuml"
|
||||
},
|
||||
"contributors": [
|
||||
"Peng Xiao (https://github.com/MrCoder)",
|
||||
"Sidharth Vinod (https://sidharth.dev)",
|
||||
"Dong Cai (https://github.com/dontry)"
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@zenuml/core": "^3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mermaid": "workspace:^"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"mermaid": "workspace:>=10.0.0"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
]
|
||||
}
|
20
packages/mermaid-zenuml/src/detector.ts
Normal file
20
packages/mermaid-zenuml/src/detector.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import type { ExternalDiagramDefinition } from 'mermaid';
|
||||
|
||||
const id = 'zenuml';
|
||||
|
||||
const detector = (txt: string) => {
|
||||
return /^\s*zenuml/.test(txt);
|
||||
};
|
||||
|
||||
const loader = async () => {
|
||||
const { diagram } = await import('./zenuml-definition.js');
|
||||
return { id, diagram };
|
||||
};
|
||||
|
||||
const plugin: ExternalDiagramDefinition = {
|
||||
id,
|
||||
detector,
|
||||
loader,
|
||||
};
|
||||
|
||||
export default plugin;
|
58
packages/mermaid-zenuml/src/mermaidUtils.ts
Normal file
58
packages/mermaid-zenuml/src/mermaidUtils.ts
Normal file
@ -0,0 +1,58 @@
|
||||
import type { MermaidConfig } from 'mermaid';
|
||||
|
||||
const warning = (s: string) => {
|
||||
// Todo remove debug code
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('Log function was called before initialization', s);
|
||||
};
|
||||
|
||||
export type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';
|
||||
|
||||
export const LEVELS: Record<LogLevel, number> = {
|
||||
trace: 0,
|
||||
debug: 1,
|
||||
info: 2,
|
||||
warn: 3,
|
||||
error: 4,
|
||||
fatal: 5,
|
||||
};
|
||||
|
||||
export const log: Record<keyof typeof LEVELS, typeof console.log> = {
|
||||
trace: warning,
|
||||
debug: warning,
|
||||
info: warning,
|
||||
warn: warning,
|
||||
error: warning,
|
||||
fatal: warning,
|
||||
};
|
||||
|
||||
export let setLogLevel: (level: keyof typeof LEVELS | number | string) => void;
|
||||
export let getConfig: () => MermaidConfig;
|
||||
export let sanitizeText: (str: string) => string;
|
||||
// eslint-disable @typescript-eslint/no-explicit-any
|
||||
export let setupGraphViewbox: (
|
||||
graph: any,
|
||||
svgElem: any,
|
||||
padding: any,
|
||||
useMaxWidth: boolean
|
||||
) => void;
|
||||
|
||||
export const injectUtils = (
|
||||
_log: Record<keyof typeof LEVELS, typeof console.log>,
|
||||
_setLogLevel: any,
|
||||
_getConfig: any,
|
||||
_sanitizeText: any,
|
||||
_setupGraphViewbox: any
|
||||
) => {
|
||||
_log.info('Mermaid utils injected');
|
||||
log.trace = _log.trace;
|
||||
log.debug = _log.debug;
|
||||
log.info = _log.info;
|
||||
log.warn = _log.warn;
|
||||
log.error = _log.error;
|
||||
log.fatal = _log.fatal;
|
||||
setLogLevel = _setLogLevel;
|
||||
getConfig = _getConfig;
|
||||
sanitizeText = _sanitizeText;
|
||||
setupGraphViewbox = _setupGraphViewbox;
|
||||
};
|
12
packages/mermaid-zenuml/src/parser.ts
Normal file
12
packages/mermaid-zenuml/src/parser.ts
Normal file
@ -0,0 +1,12 @@
|
||||
/**
|
||||
* ZenUML manage parsing internally. It uses Antlr4 to parse the DSL.
|
||||
* The parser is defined in https://github.com/ZenUml/vue-sequence/blob/main/src/parser/index.js
|
||||
*
|
||||
* This is a dummy parser that satisfies the mermaid API logic.
|
||||
*/
|
||||
export default {
|
||||
parser: { yy: {} },
|
||||
parse: () => {
|
||||
// no op
|
||||
},
|
||||
};
|
17
packages/mermaid-zenuml/src/zenuml-definition.ts
Normal file
17
packages/mermaid-zenuml/src/zenuml-definition.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { injectUtils } from './mermaidUtils.js';
|
||||
import parser from './parser.js';
|
||||
import renderer from './zenumlRenderer.js';
|
||||
|
||||
export const diagram = {
|
||||
db: {
|
||||
clear: () => {
|
||||
// no-op
|
||||
},
|
||||
},
|
||||
renderer,
|
||||
parser,
|
||||
styles: () => {
|
||||
// no-op
|
||||
},
|
||||
injectUtils,
|
||||
};
|
68
packages/mermaid-zenuml/src/zenumlRenderer.ts
Normal file
68
packages/mermaid-zenuml/src/zenumlRenderer.ts
Normal file
@ -0,0 +1,68 @@
|
||||
import { getConfig, log } from './mermaidUtils.js';
|
||||
import ZenUml from '@zenuml/core';
|
||||
|
||||
const regexp = /^\s*zenuml/;
|
||||
|
||||
// Create a Zen UML container outside the svg first for rendering, otherwise the Zen UML diagram cannot be rendered properly
|
||||
function createTemporaryZenumlContainer(id: string) {
|
||||
const container = document.createElement('div');
|
||||
container.id = `container-${id}`;
|
||||
container.style.display = 'flex';
|
||||
container.innerHTML = `<div id="zenUMLApp-${id}"></div>`;
|
||||
const app = container.querySelector(`#zenUMLApp-${id}`) as HTMLElement;
|
||||
return { container, app };
|
||||
}
|
||||
|
||||
// Create a foreignObject to wrap the Zen UML container in the svg
|
||||
function createForeignObject(id: string) {
|
||||
const foreignObject = document.createElementNS('http://www.w3.org/2000/svg', 'foreignObject');
|
||||
foreignObject.setAttribute('x', '0');
|
||||
foreignObject.setAttribute('y', '0');
|
||||
foreignObject.setAttribute('width', '100%');
|
||||
foreignObject.setAttribute('height', '100%');
|
||||
const { container, app } = createTemporaryZenumlContainer(id);
|
||||
foreignObject.appendChild(container);
|
||||
return { foreignObject, container, app };
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a Zen UML in the tag with id: id based on the graph definition in text.
|
||||
*
|
||||
* @param text - The text of the diagram
|
||||
* @param id - The id of the diagram which will be used as a DOM element id¨
|
||||
*/
|
||||
export const draw = async function (text: string, id: string) {
|
||||
log.info('draw with Zen UML renderer', ZenUml);
|
||||
|
||||
text = text.replace(regexp, '');
|
||||
const { securityLevel } = getConfig();
|
||||
// Handle root and Document for when rendering in sandbox mode
|
||||
let sandboxElement: HTMLIFrameElement | null = null;
|
||||
if (securityLevel === 'sandbox') {
|
||||
sandboxElement = document.getElementById('i' + id) as HTMLIFrameElement;
|
||||
}
|
||||
|
||||
const root = securityLevel === 'sandbox' ? sandboxElement?.contentWindow?.document : document;
|
||||
|
||||
const svgContainer = root?.querySelector(`svg#${id}`);
|
||||
|
||||
if (!root || !svgContainer) {
|
||||
log.error('Cannot find root or svgContainer');
|
||||
return;
|
||||
}
|
||||
|
||||
const { foreignObject, container, app } = createForeignObject(id);
|
||||
svgContainer.appendChild(foreignObject);
|
||||
// @ts-expect-error @zenuml/core@3.0.0 exports the wrong type for ZenUml
|
||||
const zenuml = new ZenUml(app);
|
||||
// default is a theme name. More themes to be added and will be configurable in the future
|
||||
await zenuml.render(text, 'theme-mermaid');
|
||||
|
||||
const { width, height } = window.getComputedStyle(container);
|
||||
log.debug('zenuml diagram size', width, height);
|
||||
svgContainer.setAttribute('style', `width: ${width}; height: ${height};`);
|
||||
};
|
||||
|
||||
export default {
|
||||
draw,
|
||||
};
|
9
packages/mermaid-zenuml/tsconfig.json
Normal file
9
packages/mermaid-zenuml/tsconfig.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"outDir": "./dist"
|
||||
},
|
||||
"include": ["./src/**/*.ts"],
|
||||
"typeRoots": ["./src/types"]
|
||||
}
|
3
packages/mermaid/.gitignore
vendored
3
packages/mermaid/.gitignore
vendored
@ -1,3 +1,6 @@
|
||||
src/vitepress
|
||||
src/docs/config/setup
|
||||
README.*
|
||||
src/docs/public/user-avatars/
|
||||
src/docs/.vitepress/cache
|
||||
src/docs/.vitepress/components.d.ts
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mermaid",
|
||||
"version": "10.2.0-rc.2",
|
||||
"version": "10.2.3",
|
||||
"description": "Markdown-ish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
|
||||
"type": "module",
|
||||
"module": "./dist/mermaid.core.mjs",
|
||||
@ -28,8 +28,8 @@
|
||||
"docs:build": "rimraf ../../docs && pnpm docs:spellcheck && pnpm docs:code && ts-node-esm src/docs.mts",
|
||||
"docs:verify": "pnpm docs:spellcheck && pnpm docs:code && ts-node-esm src/docs.mts --verify",
|
||||
"docs:pre:vitepress": "rimraf src/vitepress && pnpm docs:code && ts-node-esm src/docs.mts --vitepress",
|
||||
"docs:build:vitepress": "pnpm docs:pre:vitepress && vitepress build src/vitepress && cpy --flat src/docs/landing/ ./src/vitepress/.vitepress/dist/landing",
|
||||
"docs:dev": "pnpm docs:pre:vitepress && concurrently \"vitepress dev src/vitepress\" \"ts-node-esm src/docs.mts --watch --vitepress\"",
|
||||
"docs:build:vitepress": "pnpm docs:pre:vitepress && (cd src/vitepress && pnpm --filter ./ install --no-frozen-lockfile --ignore-scripts && pnpm run build) && cpy --flat src/docs/landing/ ./src/vitepress/.vitepress/dist/landing",
|
||||
"docs:dev": "pnpm docs:pre:vitepress && concurrently \"pnpm --filter ./ src/vitepress dev\" \"ts-node-esm src/docs.mts --watch --vitepress\"",
|
||||
"docs:serve": "pnpm docs:build:vitepress && vitepress serve src/vitepress",
|
||||
"docs:spellcheck": "cspell --config ../../cSpell.json \"src/docs/**/*.md\"",
|
||||
"release": "pnpm build",
|
||||
@ -53,17 +53,17 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@braintree/sanitize-url": "^6.0.2",
|
||||
"@khanacademy/simple-markdown": "^0.9.0",
|
||||
"cytoscape": "^3.23.0",
|
||||
"cytoscape-cose-bilkent": "^4.1.0",
|
||||
"cytoscape-fcose": "^2.1.0",
|
||||
"d3": "^7.4.0",
|
||||
"dagre-d3-es": "7.0.10",
|
||||
"dayjs": "^1.11.7",
|
||||
"dompurify": "3.0.2",
|
||||
"dompurify": "3.0.3",
|
||||
"elkjs": "^0.8.2",
|
||||
"khroma": "^2.0.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"mdast-util-from-markdown": "^1.3.0",
|
||||
"non-layered-tidy-tree-layout": "^2.0.2",
|
||||
"stylis": "^4.1.3",
|
||||
"ts-dedent": "^2.2.0",
|
||||
@ -73,6 +73,7 @@
|
||||
"devDependencies": {
|
||||
"@types/cytoscape": "^3.19.9",
|
||||
"@types/d3": "^7.4.0",
|
||||
"@types/d3-selection": "^3.0.5",
|
||||
"@types/dompurify": "^3.0.2",
|
||||
"@types/jsdom": "^21.1.1",
|
||||
"@types/lodash-es": "^4.17.7",
|
||||
|
@ -51,7 +51,6 @@ describe('accessibility', () => {
|
||||
desc: string | null | undefined,
|
||||
givenId: string
|
||||
) {
|
||||
// @ts-ignore Required to easily handle the d3 select types
|
||||
const svgAttrSpy = vi.spyOn(svgD3Node, 'attr').mockReturnValue(svgD3Node);
|
||||
addSVGa11yTitleDescription(svgD3Node, title, desc, givenId);
|
||||
expect(svgAttrSpy).toHaveBeenCalledWith('aria-labelledby', `chart-title-${givenId}`);
|
||||
@ -63,7 +62,6 @@ describe('accessibility', () => {
|
||||
desc: string | null | undefined,
|
||||
givenId: string
|
||||
) {
|
||||
// @ts-ignore Required to easily handle the d3 select types
|
||||
const svgAttrSpy = vi.spyOn(svgD3Node, 'attr').mockReturnValue(svgD3Node);
|
||||
addSVGa11yTitleDescription(svgD3Node, title, desc, givenId);
|
||||
expect(svgAttrSpy).toHaveBeenCalledWith('aria-describedby', `chart-desc-${givenId}`);
|
||||
|
@ -27,6 +27,7 @@ export interface MermaidConfig {
|
||||
state?: StateDiagramConfig;
|
||||
er?: ErDiagramConfig;
|
||||
pie?: PieDiagramConfig;
|
||||
quadrantChart?: QuadrantChartConfig;
|
||||
requirement?: RequirementDiagramConfig;
|
||||
mindmap?: MindmapDiagramConfig;
|
||||
gitGraph?: GitGraphDiagramConfig;
|
||||
@ -227,6 +228,27 @@ export interface PieDiagramConfig extends BaseDiagramConfig {
|
||||
textPosition?: number;
|
||||
}
|
||||
|
||||
export interface QuadrantChartConfig extends BaseDiagramConfig {
|
||||
chartWidth: number;
|
||||
chartHeight: number;
|
||||
titleFontSize: number;
|
||||
titlePadding: number;
|
||||
quadrantPadding: number;
|
||||
xAxisLabelPadding: number;
|
||||
yAxisLabelPadding: number;
|
||||
xAxisLabelFontSize: number;
|
||||
yAxisLabelFontSize: number;
|
||||
quadrantLabelFontSize: number;
|
||||
quadrantTextTopPadding: number;
|
||||
pointTextPadding: number;
|
||||
pointLabelFontSize: number;
|
||||
pointRadius: number;
|
||||
xAxisPosition: 'top' | 'bottom';
|
||||
yAxisPosition: 'left' | 'right';
|
||||
quadrantInternalBorderStrokeWidth: number;
|
||||
quadrantExternalBorderStrokeWidth: number;
|
||||
}
|
||||
|
||||
export interface ErDiagramConfig extends BaseDiagramConfig {
|
||||
titleTopMargin?: number;
|
||||
diagramPadding?: number;
|
||||
|
@ -88,13 +88,13 @@ const config: Partial<MermaidConfig> = {
|
||||
*
|
||||
* **Notes**:
|
||||
*
|
||||
* - **strict**: (**default**) tags in text are encoded, click functionality is disabled
|
||||
* - **loose**: tags in text are allowed, click functionality is enabled
|
||||
* - **antiscript**: html tags in text are allowed, (only script element is removed), click
|
||||
* functionality is enabled
|
||||
* - **sandbox**: With this security level all rendering takes place in a sandboxed iframe. This
|
||||
* - **strict**: (**default**) HTML tags in the text are encoded and click functionality is disabled.
|
||||
* - **antiscript**: HTML tags in text are allowed (only script elements are removed), and click
|
||||
* functionality is enabled.
|
||||
* - **loose**: HTML tags in text are allowed and click functionality is enabled.
|
||||
* - **sandbox**: With this security level, all rendering takes place in a sandboxed iframe. This
|
||||
* prevent any JavaScript from running in the context. This may hinder interactive functionality
|
||||
* of the diagram like scripts, popups in sequence diagram or links to other tabs/targets etc.
|
||||
* of the diagram, like scripts, popups in the sequence diagram, links to other tabs or targets, etc.
|
||||
*/
|
||||
securityLevel: 'strict',
|
||||
|
||||
@ -1288,6 +1288,184 @@ const config: Partial<MermaidConfig> = {
|
||||
textPosition: 0.75,
|
||||
},
|
||||
|
||||
quadrantChart: {
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | --------------- | ---------------------------------- | ------- | -------- | ------------------- |
|
||||
* | chartWidth | Width of the chart | number | Optional | Any positive number |
|
||||
*
|
||||
* **Notes:**
|
||||
* Default value: 500
|
||||
*/
|
||||
chartWidth: 500,
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | --------------- | ---------------------------------- | ------- | -------- | ------------------- |
|
||||
* | chartHeight | Height of the chart | number | Optional | Any positive number |
|
||||
*
|
||||
* **Notes:**
|
||||
* Default value: 500
|
||||
*/
|
||||
chartHeight: 500,
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | ------------------ | ---------------------------------- | ------- | -------- | ------------------- |
|
||||
* | titlePadding | Chart title top and bottom padding | number | Optional | Any positive number |
|
||||
*
|
||||
* **Notes:**
|
||||
* Default value: 10
|
||||
*/
|
||||
titlePadding: 10,
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | ------------------ | ---------------------------------- | ------- | -------- | ------------------- |
|
||||
* | titleFontSize | Chart title font size | number | Optional | Any positive number |
|
||||
*
|
||||
* **Notes:**
|
||||
* Default value: 20
|
||||
*/
|
||||
titleFontSize: 20,
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | --------------- | ---------------------------------- | ------- | -------- | ------------------- |
|
||||
* | quadrantPadding | Padding around the quadrant square | number | Optional | Any positive number |
|
||||
*
|
||||
* **Notes:**
|
||||
* Default value: 5
|
||||
*/
|
||||
quadrantPadding: 5,
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | ---------------------- | -------------------------------------------------------------------------- | ------- | -------- | ------------------- |
|
||||
* | quadrantTextTopPadding | quadrant title padding from top if the quadrant is rendered on top | number | Optional | Any positive number |
|
||||
*
|
||||
* **Notes:**
|
||||
* Default value: 5
|
||||
*/
|
||||
quadrantTextTopPadding: 5,
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | ------------------ | ---------------------------------- | ------- | -------- | ------------------- |
|
||||
* | quadrantLabelFontSize | quadrant title font size | number | Optional | Any positive number |
|
||||
*
|
||||
* **Notes:**
|
||||
* Default value: 16
|
||||
*/
|
||||
quadrantLabelFontSize: 16,
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | --------------------------------- | ------------------------------------------------------------- | ------- | -------- | ------------------- |
|
||||
* | quadrantInternalBorderStrokeWidth | stroke width of edges of the box that are inside the quadrant | number | Optional | Any positive number |
|
||||
*
|
||||
* **Notes:**
|
||||
* Default value: 1
|
||||
*/
|
||||
quadrantInternalBorderStrokeWidth: 1,
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | --------------------------------- | -------------------------------------------------------------- | ------- | -------- | ------------------- |
|
||||
* | quadrantExternalBorderStrokeWidth | stroke width of edges of the box that are outside the quadrant | number | Optional | Any positive number |
|
||||
*
|
||||
* **Notes:**
|
||||
* Default value: 2
|
||||
*/
|
||||
quadrantExternalBorderStrokeWidth: 2,
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | --------------- | ---------------------------------- | ------- | -------- | ------------------- |
|
||||
* | xAxisLabelPadding | Padding around x-axis labels | number | Optional | Any positive number |
|
||||
*
|
||||
* **Notes:**
|
||||
* Default value: 5
|
||||
*/
|
||||
xAxisLabelPadding: 5,
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | ------------------ | ---------------------------------- | ------- | -------- | ------------------- |
|
||||
* | xAxisLabelFontSize | x-axis label font size | number | Optional | Any positive number |
|
||||
*
|
||||
* **Notes:**
|
||||
* Default value: 16
|
||||
*/
|
||||
xAxisLabelFontSize: 16,
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | ------------- | ------------------------------- | ------- | -------- | ------------------- |
|
||||
* | xAxisPosition | position of x-axis labels | string | Optional | 'top' or 'bottom' |
|
||||
*
|
||||
* **Notes:**
|
||||
* Default value: top
|
||||
*/
|
||||
xAxisPosition: 'top',
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | --------------- | ---------------------------------- | ------- | -------- | ------------------- |
|
||||
* | yAxisLabelPadding | Padding around y-axis labels | number | Optional | Any positive number |
|
||||
*
|
||||
* **Notes:**
|
||||
* Default value: 5
|
||||
*/
|
||||
yAxisLabelPadding: 5,
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | ------------------ | ---------------------------------- | ------- | -------- | ------------------- |
|
||||
* | yAxisLabelFontSize | y-axis label font size | number | Optional | Any positive number |
|
||||
*
|
||||
* **Notes:**
|
||||
* Default value: 16
|
||||
*/
|
||||
yAxisLabelFontSize: 16,
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | ------------- | ------------------------------- | ------- | -------- | ------------------- |
|
||||
* | yAxisPosition | position of y-axis labels | string | Optional | 'left' or 'right' |
|
||||
*
|
||||
* **Notes:**
|
||||
* Default value: left
|
||||
*/
|
||||
yAxisPosition: 'left',
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | ---------------------- | -------------------------------------- | ------- | -------- | ------------------- |
|
||||
* | pointTextPadding | padding between point and point label | number | Optional | Any positive number |
|
||||
*
|
||||
* **Notes:**
|
||||
* Default value: 5
|
||||
*/
|
||||
pointTextPadding: 5,
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | ---------------------- | ---------------------- | ------- | -------- | ------------------- |
|
||||
* | pointTextPadding | point title font size | number | Optional | Any positive number |
|
||||
*
|
||||
* **Notes:**
|
||||
* Default value: 12
|
||||
*/
|
||||
pointLabelFontSize: 12,
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | ------------- | ------------------------------- | ------- | -------- | ------------------- |
|
||||
* | pointRadius | radius of the point to be drawn | number | Optional | Any positive number |
|
||||
*
|
||||
* **Notes:**
|
||||
* Default value: 5
|
||||
*/
|
||||
pointRadius: 5,
|
||||
/**
|
||||
* | Parameter | Description | Type | Required | Values |
|
||||
* | ----------- | ----------- | ------- | -------- | ----------- |
|
||||
* | useMaxWidth | See Notes | boolean | Required | true, false |
|
||||
*
|
||||
* **Notes:**
|
||||
*
|
||||
* When this flag is set to true, the diagram width is locked to 100% and scaled based on
|
||||
* available space. If set to false, the diagram reserves its absolute width.
|
||||
*
|
||||
* Default value: true
|
||||
*/
|
||||
useMaxWidth: true,
|
||||
},
|
||||
|
||||
/** The object containing configurations specific for req diagrams */
|
||||
requirement: {
|
||||
useWidth: undefined,
|
||||
|
@ -4,8 +4,9 @@ import flowchartV2 from '../diagrams/flowchart/flowDetector-v2.js';
|
||||
import er from '../diagrams/er/erDetector.js';
|
||||
import git from '../diagrams/git/gitGraphDetector.js';
|
||||
import gantt from '../diagrams/gantt/ganttDetector.js';
|
||||
import info from '../diagrams/info/infoDetector.js';
|
||||
import { info } from '../diagrams/info/infoDetector.js';
|
||||
import pie from '../diagrams/pie/pieDetector.js';
|
||||
import quadrantChart from '../diagrams/quadrant-chart/quadrantDetector.js';
|
||||
import requirement from '../diagrams/requirement/requirementDetector.js';
|
||||
import sequence from '../diagrams/sequence/sequenceDetector.js';
|
||||
import classDiagram from '../diagrams/class/classDetector.js';
|
||||
@ -77,6 +78,7 @@ export const addDiagrams = () => {
|
||||
git,
|
||||
stateV2,
|
||||
state,
|
||||
journey
|
||||
journey,
|
||||
quadrantChart
|
||||
);
|
||||
};
|
||||
|
@ -7,6 +7,7 @@ import { addStylesForDiagram } from '../styles.js';
|
||||
import { DiagramDefinition, DiagramDetector } from './types.js';
|
||||
import * as _commonDb from '../commonDb.js';
|
||||
import { parseDirective as _parseDirective } from '../directiveUtils.js';
|
||||
import isEmpty from 'lodash-es/isEmpty.js';
|
||||
|
||||
/*
|
||||
Packaging and exposing resources for external diagrams so that they can import
|
||||
@ -50,7 +51,9 @@ export const registerDiagram = (
|
||||
if (detector) {
|
||||
addDetector(id, detector);
|
||||
}
|
||||
addStylesForDiagram(id, diagram.styles);
|
||||
if (!isEmpty(diagram.styles)) {
|
||||
addStylesForDiagram(id, diagram.styles);
|
||||
}
|
||||
|
||||
if (diagram.injectUtils) {
|
||||
diagram.injectUtils(
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { DiagramDb } from './types.js';
|
||||
import { DiagramDB } from './types.js';
|
||||
// The "* as yaml" part is necessary for tree-shaking
|
||||
import * as yaml from 'js-yaml';
|
||||
|
||||
@ -22,7 +22,7 @@ type FrontMatterMetadata = {
|
||||
* @param db - Diagram database, could be of any diagram.
|
||||
* @returns text with frontmatter stripped out
|
||||
*/
|
||||
export function extractFrontMatter(text: string, db: DiagramDb): string {
|
||||
export function extractFrontMatter(text: string, db: DiagramDB): string {
|
||||
const matches = text.match(frontMatterRegex);
|
||||
if (matches) {
|
||||
const parsed: FrontMatterMetadata = yaml.load(matches[1], {
|
||||
|
@ -1,4 +1,6 @@
|
||||
import { Diagram } from '../Diagram.js';
|
||||
import { MermaidConfig } from '../config.type.js';
|
||||
import type * as d3 from 'd3';
|
||||
|
||||
export interface InjectUtils {
|
||||
_log: any;
|
||||
@ -13,7 +15,7 @@ export interface InjectUtils {
|
||||
/**
|
||||
* Generic Diagram DB that may apply to any diagram type.
|
||||
*/
|
||||
export interface DiagramDb {
|
||||
export interface DiagramDB {
|
||||
clear?: () => void;
|
||||
setDiagramTitle?: (title: string) => void;
|
||||
setDisplayMode?: (title: string) => void;
|
||||
@ -23,10 +25,10 @@ export interface DiagramDb {
|
||||
}
|
||||
|
||||
export interface DiagramDefinition {
|
||||
db: DiagramDb;
|
||||
db: DiagramDB;
|
||||
renderer: any;
|
||||
parser: any;
|
||||
styles: any;
|
||||
styles?: any;
|
||||
init?: (config: MermaidConfig) => void;
|
||||
injectUtils?: (
|
||||
_log: InjectUtils['_log'],
|
||||
@ -52,3 +54,31 @@ export interface ExternalDiagramDefinition {
|
||||
|
||||
export type DiagramDetector = (text: string, config?: MermaidConfig) => boolean;
|
||||
export type DiagramLoader = () => Promise<{ id: string; diagram: DiagramDefinition }>;
|
||||
|
||||
/**
|
||||
* Type for function draws diagram in the tag with id: id based on the graph definition in text.
|
||||
*
|
||||
* @param text - The text of the diagram.
|
||||
* @param id - The id of the diagram which will be used as a DOM element id.
|
||||
* @param version - MermaidJS version from package.json.
|
||||
* @param diagramObject - A standard diagram containing the DB and the text and type etc of the diagram.
|
||||
*/
|
||||
export type DrawDefinition = (
|
||||
text: string,
|
||||
id: string,
|
||||
version: string,
|
||||
diagramObject: Diagram
|
||||
) => void;
|
||||
|
||||
/**
|
||||
* Type for function parse directive from diagram code.
|
||||
*
|
||||
* @param statement -
|
||||
* @param context -
|
||||
* @param type -
|
||||
*/
|
||||
export type ParseDirectiveDefinition = (statement: string, context: string, type: string) => void;
|
||||
|
||||
export type HTML = d3.Selection<HTMLIFrameElement, unknown, Element, unknown>;
|
||||
|
||||
export type SVG = d3.Selection<SVGSVGElement, unknown, Element, unknown>;
|
||||
|
@ -1,12 +1,16 @@
|
||||
import type { ExternalDiagramDefinition } from '../../diagram-api/types.js';
|
||||
import type {
|
||||
DiagramDetector,
|
||||
DiagramLoader,
|
||||
ExternalDiagramDefinition,
|
||||
} from '../../diagram-api/types.js';
|
||||
|
||||
const id = 'c4';
|
||||
|
||||
const detector = (txt: string) => {
|
||||
return txt.match(/^\s*C4Context|C4Container|C4Component|C4Dynamic|C4Deployment/) !== null;
|
||||
const detector: DiagramDetector = (txt) => {
|
||||
return /^\s*C4Context|C4Container|C4Component|C4Dynamic|C4Deployment/.test(txt);
|
||||
};
|
||||
|
||||
const loader = async () => {
|
||||
const loader: DiagramLoader = async () => {
|
||||
const { diagram } = await import('./c4Diagram.js');
|
||||
return { id, diagram };
|
||||
};
|
||||
|
@ -220,7 +220,7 @@ export const drawC4ShapeArray = function (currentBounds, diagram, c4ShapeArray,
|
||||
let c4ShapeTypeConf = c4ShapeFont(conf, c4Shape.typeC4Shape.text);
|
||||
c4ShapeTypeConf.fontSize = c4ShapeTypeConf.fontSize - 2;
|
||||
c4Shape.typeC4Shape.width = calculateTextWidth(
|
||||
'<<' + c4Shape.typeC4Shape.text + '>>',
|
||||
'«' + c4Shape.typeC4Shape.text + '»',
|
||||
c4ShapeTypeConf
|
||||
);
|
||||
c4Shape.typeC4Shape.height = c4ShapeTypeConf.fontSize + 2;
|
||||
|
@ -1,28 +1,9 @@
|
||||
import common from '../common/common.js';
|
||||
import * as svgDrawCommon from '../common/svgDrawCommon';
|
||||
import { sanitizeUrl } from '@braintree/sanitize-url';
|
||||
|
||||
export const drawRect = function (elem, rectData) {
|
||||
const rectElem = elem.append('rect');
|
||||
rectElem.attr('x', rectData.x);
|
||||
rectElem.attr('y', rectData.y);
|
||||
rectElem.attr('fill', rectData.fill);
|
||||
rectElem.attr('stroke', rectData.stroke);
|
||||
rectElem.attr('width', rectData.width);
|
||||
rectElem.attr('height', rectData.height);
|
||||
rectElem.attr('rx', rectData.rx);
|
||||
rectElem.attr('ry', rectData.ry);
|
||||
|
||||
if (rectData.attrs !== 'undefined' && rectData.attrs !== null) {
|
||||
for (let attrKey in rectData.attrs) {
|
||||
rectElem.attr(attrKey, rectData.attrs[attrKey]);
|
||||
}
|
||||
}
|
||||
|
||||
if (rectData.class !== 'undefined') {
|
||||
rectElem.attr('class', rectData.class);
|
||||
}
|
||||
|
||||
return rectElem;
|
||||
return svgDrawCommon.drawRect(elem, rectData);
|
||||
};
|
||||
|
||||
export const drawImage = function (elem, width, height, x, y, link) {
|
||||
@ -236,7 +217,8 @@ export const drawC4Shape = function (elem, c4Shape, conf) {
|
||||
|
||||
// <rect fill="#08427B" height="119.2188" rx="2.5" ry="2.5" stroke="#073B6F" stroke-width="0.5" width="110" x="120" y="7"/>
|
||||
// draw rect of c4Shape
|
||||
const rect = getNoteRect();
|
||||
const rect = svgDrawCommon.getNoteRect();
|
||||
|
||||
switch (c4Shape.typeC4Shape.text) {
|
||||
case 'person':
|
||||
case 'external_person':
|
||||
@ -479,6 +461,7 @@ export const insertArrowHead = function (elem) {
|
||||
.append('path')
|
||||
.attr('d', 'M 0 0 L 10 5 L 0 10 z'); // this is actual shape for arrowhead
|
||||
};
|
||||
|
||||
export const insertArrowEnd = function (elem) {
|
||||
elem
|
||||
.append('defs')
|
||||
@ -493,6 +476,7 @@ export const insertArrowEnd = function (elem) {
|
||||
.append('path')
|
||||
.attr('d', 'M 10 0 L 0 5 L 10 10 z'); // this is actual shape for arrowhead
|
||||
};
|
||||
|
||||
/**
|
||||
* Setup arrow head and define the marker. The result is appended to the svg.
|
||||
*
|
||||
@ -511,6 +495,7 @@ export const insertArrowFilledHead = function (elem) {
|
||||
.append('path')
|
||||
.attr('d', 'M 18,7 L9,13 L14,7 L9,1 Z');
|
||||
};
|
||||
|
||||
/**
|
||||
* Setup node number. The result is appended to the svg.
|
||||
*
|
||||
@ -532,6 +517,7 @@ export const insertDynamicNumber = function (elem) {
|
||||
.attr('r', 6);
|
||||
// .style("fill", '#f00');
|
||||
};
|
||||
|
||||
/**
|
||||
* Setup arrow head and define the marker. The result is appended to the svg.
|
||||
*
|
||||
@ -568,20 +554,6 @@ export const insertArrowCrossHead = function (elem) {
|
||||
// this is actual shape for arrowhead
|
||||
};
|
||||
|
||||
export const getNoteRect = function () {
|
||||
return {
|
||||
x: 0,
|
||||
y: 0,
|
||||
fill: '#EDF2AE',
|
||||
stroke: '#666',
|
||||
width: 100,
|
||||
anchor: 'start',
|
||||
height: 100,
|
||||
rx: 0,
|
||||
ry: 0,
|
||||
};
|
||||
};
|
||||
|
||||
const getC4ShapeFont = (cnf, typeC4Shape) => {
|
||||
return {
|
||||
fontFamily: cnf[typeC4Shape + 'FontFamily'],
|
||||
@ -714,6 +686,4 @@ export default {
|
||||
insertDatabaseIcon,
|
||||
insertComputerIcon,
|
||||
insertClockIcon,
|
||||
getNoteRect,
|
||||
sanitizeUrl, // TODO why is this exported?
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
// @ts-expect-error - d3 types issue
|
||||
// @ts-nocheck - don't check until handle it
|
||||
import { select, Selection } from 'd3';
|
||||
import { log } from '../../logger.js';
|
||||
import * as configApi from '../../config.js';
|
||||
@ -14,7 +14,14 @@ import {
|
||||
setDiagramTitle,
|
||||
getDiagramTitle,
|
||||
} from '../../commonDb.js';
|
||||
import { ClassRelation, ClassNode, ClassNote, ClassMap } from './classTypes.js';
|
||||
import {
|
||||
ClassRelation,
|
||||
ClassNode,
|
||||
ClassNote,
|
||||
ClassMap,
|
||||
NamespaceMap,
|
||||
NamespaceNode,
|
||||
} from './classTypes.js';
|
||||
|
||||
const MERMAID_DOM_ID_PREFIX = 'classId-';
|
||||
|
||||
@ -22,6 +29,8 @@ let relations: ClassRelation[] = [];
|
||||
let classes: ClassMap = {};
|
||||
let notes: ClassNote[] = [];
|
||||
let classCounter = 0;
|
||||
let namespaces: NamespaceMap = {};
|
||||
let namespaceCounter = 0;
|
||||
|
||||
let functions: any[] = [];
|
||||
|
||||
@ -100,6 +109,8 @@ export const clear = function () {
|
||||
notes = [];
|
||||
functions = [];
|
||||
functions.push(setupToolTips);
|
||||
namespaces = {};
|
||||
namespaceCounter = 0;
|
||||
commonClear();
|
||||
};
|
||||
|
||||
@ -237,7 +248,11 @@ const setTooltip = function (ids: string, tooltip?: string) {
|
||||
});
|
||||
};
|
||||
|
||||
export const getTooltip = function (id: string) {
|
||||
export const getTooltip = function (id: string, namespace?: string) {
|
||||
if (namespace) {
|
||||
return namespaces[namespace].classes[id].tooltip;
|
||||
}
|
||||
|
||||
return classes[id].tooltip;
|
||||
};
|
||||
/**
|
||||
@ -352,7 +367,6 @@ export const relationType = {
|
||||
const setupToolTips = function (element: Element) {
|
||||
let tooltipElem: Selection<HTMLDivElement, unknown, HTMLElement, unknown> =
|
||||
select('.mermaidTooltip');
|
||||
// @ts-ignore - _groups is a dynamic property
|
||||
if ((tooltipElem._groups || tooltipElem)[0][0] === null) {
|
||||
tooltipElem = select('body').append('div').attr('class', 'mermaidTooltip').style('opacity', 0);
|
||||
}
|
||||
@ -395,6 +409,52 @@ const setDirection = (dir: string) => {
|
||||
direction = dir;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function called by parser when a namespace definition has been found.
|
||||
*
|
||||
* @param id - Id of the namespace to add
|
||||
* @public
|
||||
*/
|
||||
export const addNamespace = function (id: string) {
|
||||
if (namespaces[id] !== undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
namespaces[id] = {
|
||||
id: id,
|
||||
classes: {},
|
||||
children: {},
|
||||
domId: MERMAID_DOM_ID_PREFIX + id + '-' + namespaceCounter,
|
||||
} as NamespaceNode;
|
||||
|
||||
namespaceCounter++;
|
||||
};
|
||||
|
||||
const getNamespace = function (name: string): NamespaceNode {
|
||||
return namespaces[name];
|
||||
};
|
||||
|
||||
const getNamespaces = function (): NamespaceMap {
|
||||
return namespaces;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function called by parser when a namespace definition has been found.
|
||||
*
|
||||
* @param id - Id of the namespace to add
|
||||
* @param classNames - Ids of the class to add
|
||||
* @public
|
||||
*/
|
||||
export const addClassesToNamespace = function (id: string, classNames: string[]) {
|
||||
if (namespaces[id] !== undefined) {
|
||||
classNames.map((className) => {
|
||||
namespaces[id].classes[className] = classes[className];
|
||||
delete classes[className];
|
||||
classCounter--;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default {
|
||||
parseDirective,
|
||||
setAccTitle,
|
||||
@ -428,4 +488,8 @@ export default {
|
||||
setDiagramTitle,
|
||||
getDiagramTitle,
|
||||
setClassLabel,
|
||||
addNamespace,
|
||||
addClassesToNamespace,
|
||||
getNamespace,
|
||||
getNamespaces,
|
||||
};
|
||||
|
@ -1,20 +1,21 @@
|
||||
import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types.js';
|
||||
import type {
|
||||
DiagramDetector,
|
||||
DiagramLoader,
|
||||
ExternalDiagramDefinition,
|
||||
} from '../../diagram-api/types.js';
|
||||
|
||||
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 &&
|
||||
config?.class?.defaultRenderer === 'dagre-wrapper'
|
||||
) {
|
||||
if (/^\s*classDiagram/.test(txt) && config?.class?.defaultRenderer === 'dagre-wrapper') {
|
||||
return true;
|
||||
}
|
||||
// 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;
|
||||
return /^\s*classDiagram-v2/.test(txt);
|
||||
};
|
||||
|
||||
const loader = async () => {
|
||||
const loader: DiagramLoader = async () => {
|
||||
const { diagram } = await import('./classDiagram-v2.js');
|
||||
return { id, diagram };
|
||||
};
|
||||
|
@ -1,4 +1,8 @@
|
||||
import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types.js';
|
||||
import type {
|
||||
DiagramDetector,
|
||||
DiagramLoader,
|
||||
ExternalDiagramDefinition,
|
||||
} from '../../diagram-api/types.js';
|
||||
|
||||
const id = 'class';
|
||||
|
||||
@ -8,10 +12,10 @@ const detector: DiagramDetector = (txt, config) => {
|
||||
return false;
|
||||
}
|
||||
// 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;
|
||||
return /^\s*classDiagram/.test(txt);
|
||||
};
|
||||
|
||||
const loader = async () => {
|
||||
const loader: DiagramLoader = async () => {
|
||||
const { diagram } = await import('./classDiagram.js');
|
||||
return { id, diagram };
|
||||
};
|
||||
|
@ -816,6 +816,37 @@ describe('given a class diagram with generics, ', function () {
|
||||
|
||||
parser.parse(str);
|
||||
});
|
||||
|
||||
it('should handle "namespace"', function () {
|
||||
const str = `classDiagram
|
||||
namespace Namespace1 { class Class1 }
|
||||
namespace Namespace2 { class Class1
|
||||
}
|
||||
namespace Namespace3 {
|
||||
class Class1 {
|
||||
int : test
|
||||
string : foo
|
||||
test()
|
||||
foo()
|
||||
}
|
||||
}
|
||||
namespace Namespace4 {
|
||||
class Class1 {
|
||||
int : test
|
||||
string : foo
|
||||
test()
|
||||
foo()
|
||||
}
|
||||
class Class2 {
|
||||
int : test
|
||||
string : foo
|
||||
test()
|
||||
foo()
|
||||
}
|
||||
}
|
||||
`;
|
||||
parser.parse(str);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when parsing invalid generic classes', function () {
|
||||
@ -1051,5 +1082,487 @@ describe('given a class diagram with relationships, ', function () {
|
||||
expect(relations[3].relation.type2).toBe('none');
|
||||
expect(relations[3].relation.lineType).toBe(classDb.lineType.DOTTED_LINE);
|
||||
});
|
||||
|
||||
it('should handle generic class with relation definitions', function () {
|
||||
const str = 'classDiagram\n' + 'Class01~T~ <|-- Class02';
|
||||
|
||||
parser.parse(str);
|
||||
|
||||
const relations = parser.yy.getRelations();
|
||||
|
||||
expect(parser.yy.getClass('Class01').id).toBe('Class01');
|
||||
expect(parser.yy.getClass('Class01').type).toBe('T');
|
||||
expect(parser.yy.getClass('Class02').id).toBe('Class02');
|
||||
expect(relations[0].relation.type1).toBe(classDb.relationType.EXTENSION);
|
||||
expect(relations[0].relation.type2).toBe('none');
|
||||
expect(relations[0].relation.lineType).toBe(classDb.lineType.LINE);
|
||||
});
|
||||
|
||||
it('should handle class annotations', function () {
|
||||
const str = 'classDiagram\n' + 'class Class1\n' + '<<interface>> Class1';
|
||||
parser.parse(str);
|
||||
|
||||
const testClass = parser.yy.getClass('Class1');
|
||||
expect(testClass.annotations.length).toBe(1);
|
||||
expect(testClass.members.length).toBe(0);
|
||||
expect(testClass.methods.length).toBe(0);
|
||||
expect(testClass.annotations[0]).toBe('interface');
|
||||
});
|
||||
|
||||
it('should handle class annotations with members and methods', function () {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Class1\n' +
|
||||
'Class1 : int test\n' +
|
||||
'Class1 : test()\n' +
|
||||
'<<interface>> Class1';
|
||||
parser.parse(str);
|
||||
|
||||
const testClass = parser.yy.getClass('Class1');
|
||||
expect(testClass.annotations.length).toBe(1);
|
||||
expect(testClass.members.length).toBe(1);
|
||||
expect(testClass.methods.length).toBe(1);
|
||||
expect(testClass.annotations[0]).toBe('interface');
|
||||
});
|
||||
|
||||
it('should handle class annotations in brackets', function () {
|
||||
const str = 'classDiagram\n' + 'class Class1 {\n' + '<<interface>>\n' + '}';
|
||||
parser.parse(str);
|
||||
|
||||
const testClass = parser.yy.getClass('Class1');
|
||||
expect(testClass.annotations.length).toBe(1);
|
||||
expect(testClass.members.length).toBe(0);
|
||||
expect(testClass.methods.length).toBe(0);
|
||||
expect(testClass.annotations[0]).toBe('interface');
|
||||
});
|
||||
|
||||
it('should handle class annotations in brackets with members and methods', function () {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Class1 {\n' +
|
||||
'<<interface>>\n' +
|
||||
'int : test\n' +
|
||||
'test()\n' +
|
||||
'}';
|
||||
parser.parse(str);
|
||||
|
||||
const testClass = parser.yy.getClass('Class1');
|
||||
expect(testClass.annotations.length).toBe(1);
|
||||
expect(testClass.members.length).toBe(1);
|
||||
expect(testClass.methods.length).toBe(1);
|
||||
expect(testClass.annotations[0]).toBe('interface');
|
||||
});
|
||||
|
||||
it('should add bracket members in right order', function () {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Class1 {\n' +
|
||||
'int : test\n' +
|
||||
'string : foo\n' +
|
||||
'test()\n' +
|
||||
'foo()\n' +
|
||||
'}';
|
||||
parser.parse(str);
|
||||
|
||||
const testClass = parser.yy.getClass('Class1');
|
||||
expect(testClass.members.length).toBe(2);
|
||||
expect(testClass.methods.length).toBe(2);
|
||||
expect(testClass.members[0]).toBe('int : test');
|
||||
expect(testClass.members[1]).toBe('string : foo');
|
||||
expect(testClass.methods[0]).toBe('test()');
|
||||
expect(testClass.methods[1]).toBe('foo()');
|
||||
});
|
||||
|
||||
it('should handle abstract methods', function () {
|
||||
const str = 'classDiagram\n' + 'class Class1\n' + 'Class1 : someMethod()*';
|
||||
parser.parse(str);
|
||||
|
||||
const testClass = parser.yy.getClass('Class1');
|
||||
expect(testClass.annotations.length).toBe(0);
|
||||
expect(testClass.members.length).toBe(0);
|
||||
expect(testClass.methods.length).toBe(1);
|
||||
expect(testClass.methods[0]).toBe('someMethod()*');
|
||||
});
|
||||
|
||||
it('should handle static methods', function () {
|
||||
const str = 'classDiagram\n' + 'class Class1\n' + 'Class1 : someMethod()$';
|
||||
parser.parse(str);
|
||||
|
||||
const testClass = parser.yy.getClass('Class1');
|
||||
expect(testClass.annotations.length).toBe(0);
|
||||
expect(testClass.members.length).toBe(0);
|
||||
expect(testClass.methods.length).toBe(1);
|
||||
expect(testClass.methods[0]).toBe('someMethod()$');
|
||||
});
|
||||
|
||||
it('should associate link and css appropriately', function () {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Class1\n' +
|
||||
'Class1 : someMethod()\n' +
|
||||
'link Class1 "google.com"';
|
||||
parser.parse(str);
|
||||
|
||||
const testClass = parser.yy.getClass('Class1');
|
||||
expect(testClass.link).toBe('google.com');
|
||||
expect(testClass.cssClasses.length).toBe(1);
|
||||
expect(testClass.cssClasses[0]).toBe('clickable');
|
||||
});
|
||||
|
||||
it('should associate click and href link and css appropriately', function () {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Class1\n' +
|
||||
'Class1 : someMethod()\n' +
|
||||
'click Class1 href "google.com"';
|
||||
parser.parse(str);
|
||||
|
||||
const testClass = parser.yy.getClass('Class1');
|
||||
expect(testClass.link).toBe('google.com');
|
||||
expect(testClass.cssClasses.length).toBe(1);
|
||||
expect(testClass.cssClasses[0]).toBe('clickable');
|
||||
});
|
||||
|
||||
it('should associate link with tooltip', function () {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Class1\n' +
|
||||
'Class1 : someMethod()\n' +
|
||||
'link Class1 "google.com" "A tooltip"';
|
||||
parser.parse(str);
|
||||
|
||||
const testClass = parser.yy.getClass('Class1');
|
||||
expect(testClass.link).toBe('google.com');
|
||||
expect(testClass.tooltip).toBe('A tooltip');
|
||||
expect(testClass.cssClasses.length).toBe(1);
|
||||
expect(testClass.cssClasses[0]).toBe('clickable');
|
||||
});
|
||||
|
||||
it('should associate click and href link with tooltip', function () {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Class1\n' +
|
||||
'Class1 : someMethod()\n' +
|
||||
'click Class1 href "google.com" "A tooltip"';
|
||||
parser.parse(str);
|
||||
|
||||
const testClass = parser.yy.getClass('Class1');
|
||||
expect(testClass.link).toBe('google.com');
|
||||
expect(testClass.tooltip).toBe('A tooltip');
|
||||
expect(testClass.cssClasses.length).toBe(1);
|
||||
expect(testClass.cssClasses[0]).toBe('clickable');
|
||||
});
|
||||
|
||||
it('should associate click and href link with tooltip and target appropriately', function () {
|
||||
spyOn(classDb, 'setLink');
|
||||
spyOn(classDb, 'setTooltip');
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Class1\n' +
|
||||
'Class1 : someMethod()\n' +
|
||||
'click Class1 href "google.com" "A tooltip" _self';
|
||||
parser.parse(str);
|
||||
|
||||
expect(classDb.setLink).toHaveBeenCalledWith('Class1', 'google.com', '_self');
|
||||
expect(classDb.setTooltip).toHaveBeenCalledWith('Class1', 'A tooltip');
|
||||
});
|
||||
|
||||
it('should associate click and href link appropriately', function () {
|
||||
spyOn(classDb, 'setLink');
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Class1\n' +
|
||||
'Class1 : someMethod()\n' +
|
||||
'click Class1 href "google.com"';
|
||||
parser.parse(str);
|
||||
|
||||
expect(classDb.setLink).toHaveBeenCalledWith('Class1', 'google.com');
|
||||
});
|
||||
|
||||
it('should associate click and href link with target appropriately', function () {
|
||||
spyOn(classDb, 'setLink');
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Class1\n' +
|
||||
'Class1 : someMethod()\n' +
|
||||
'click Class1 href "google.com" _self';
|
||||
parser.parse(str);
|
||||
|
||||
expect(classDb.setLink).toHaveBeenCalledWith('Class1', 'google.com', '_self');
|
||||
});
|
||||
|
||||
it('should associate link appropriately', function () {
|
||||
spyOn(classDb, 'setLink');
|
||||
spyOn(classDb, 'setTooltip');
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Class1\n' +
|
||||
'Class1 : someMethod()\n' +
|
||||
'link Class1 "google.com" "A tooltip" _self';
|
||||
parser.parse(str);
|
||||
|
||||
expect(classDb.setLink).toHaveBeenCalledWith('Class1', 'google.com', '_self');
|
||||
expect(classDb.setTooltip).toHaveBeenCalledWith('Class1', 'A tooltip');
|
||||
});
|
||||
|
||||
it('should associate callback appropriately', function () {
|
||||
spyOn(classDb, 'setClickEvent');
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Class1\n' +
|
||||
'Class1 : someMethod()\n' +
|
||||
'callback Class1 "functionCall"';
|
||||
parser.parse(str);
|
||||
|
||||
expect(classDb.setClickEvent).toHaveBeenCalledWith('Class1', 'functionCall');
|
||||
});
|
||||
|
||||
it('should associate click and call callback appropriately', function () {
|
||||
spyOn(classDb, 'setClickEvent');
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Class1\n' +
|
||||
'Class1 : someMethod()\n' +
|
||||
'click Class1 call functionCall()';
|
||||
parser.parse(str);
|
||||
|
||||
expect(classDb.setClickEvent).toHaveBeenCalledWith('Class1', 'functionCall');
|
||||
});
|
||||
|
||||
it('should associate callback appropriately with an arbitrary number of args', function () {
|
||||
spyOn(classDb, 'setClickEvent');
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Class1\n' +
|
||||
'Class1 : someMethod()\n' +
|
||||
'click Class1 call functionCall("test0", test1, test2)';
|
||||
parser.parse(str);
|
||||
|
||||
expect(classDb.setClickEvent).toHaveBeenCalledWith(
|
||||
'Class1',
|
||||
'functionCall',
|
||||
'"test0", test1, test2'
|
||||
);
|
||||
});
|
||||
|
||||
it('should associate callback with tooltip', function () {
|
||||
spyOn(classDb, 'setClickEvent');
|
||||
spyOn(classDb, 'setTooltip');
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Class1\n' +
|
||||
'Class1 : someMethod()\n' +
|
||||
'click Class1 call functionCall() "A tooltip"';
|
||||
parser.parse(str);
|
||||
|
||||
expect(classDb.setClickEvent).toHaveBeenCalledWith('Class1', 'functionCall');
|
||||
expect(classDb.setTooltip).toHaveBeenCalledWith('Class1', 'A tooltip');
|
||||
});
|
||||
|
||||
it('should add classes namespaces', function () {
|
||||
const str = `classDiagram
|
||||
namespace Namespace1 {
|
||||
class Class1 {
|
||||
int : test
|
||||
string : foo
|
||||
test()
|
||||
foo()
|
||||
}
|
||||
class Class2
|
||||
}`;
|
||||
parser.parse(str);
|
||||
|
||||
const testNamespace = parser.yy.getNamespace('Namespace1');
|
||||
expect(Object.keys(testNamespace.classes).length).toBe(2);
|
||||
expect(Object.keys(testNamespace.children).length).toBe(0);
|
||||
expect(testNamespace.classes['Class1'].id).toBe('Class1');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when parsing classDiagram with text labels', () => {
|
||||
beforeEach(function () {
|
||||
parser.yy = classDb;
|
||||
parser.yy.clear();
|
||||
});
|
||||
|
||||
it('should parse a class with a text label', () => {
|
||||
parser.parse(`classDiagram
|
||||
class C1["Class 1 with text label"]
|
||||
C1 --> C2
|
||||
`);
|
||||
const c1 = classDb.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
const c2 = classDb.getClass('C2');
|
||||
expect(c2.label).toBe('C2');
|
||||
});
|
||||
|
||||
it('should parse two classes with text labels', () => {
|
||||
parser.parse(`classDiagram
|
||||
class C1["Class 1 with text label"]
|
||||
class C2["Class 2 with chars @?"]
|
||||
C1 --> C2
|
||||
`);
|
||||
const c1 = classDb.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
const c2 = classDb.getClass('C2');
|
||||
expect(c2.label).toBe('Class 2 with chars @?');
|
||||
});
|
||||
|
||||
it('should parse a class with a text label and members', () => {
|
||||
parser.parse(`classDiagram
|
||||
class C1["Class 1 with text label"] {
|
||||
+member1
|
||||
}
|
||||
C1 --> C2
|
||||
`);
|
||||
const c1 = classDb.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
expect(c1.members.length).toBe(1);
|
||||
expect(c1.members[0]).toBe('+member1');
|
||||
|
||||
const c2 = classDb.getClass('C2');
|
||||
expect(c2.label).toBe('C2');
|
||||
});
|
||||
|
||||
it('should parse a class with a text label, members and annotation', () => {
|
||||
parser.parse(`classDiagram
|
||||
class C1["Class 1 with text label"] {
|
||||
<<interface>>
|
||||
+member1
|
||||
}
|
||||
C1 --> C2
|
||||
`);
|
||||
const c1 = classDb.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
expect(c1.members.length).toBe(1);
|
||||
expect(c1.members[0]).toBe('+member1');
|
||||
expect(c1.annotations.length).toBe(1);
|
||||
expect(c1.annotations[0]).toBe('interface');
|
||||
|
||||
const c2 = classDb.getClass('C2');
|
||||
expect(c2.label).toBe('C2');
|
||||
});
|
||||
|
||||
it('should parse a class with text label and css class shorthand', () => {
|
||||
parser.parse(`classDiagram
|
||||
class C1["Class 1 with text label"]:::styleClass {
|
||||
+member1
|
||||
}
|
||||
C1 --> C2
|
||||
`);
|
||||
|
||||
const c1 = classDb.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
expect(c1.cssClasses.length).toBe(1);
|
||||
expect(c1.members[0]).toBe('+member1');
|
||||
expect(c1.cssClasses[0]).toBe('styleClass');
|
||||
});
|
||||
|
||||
it('should parse a class with text label and css class', () => {
|
||||
parser.parse(`classDiagram
|
||||
class C1["Class 1 with text label"] {
|
||||
+member1
|
||||
}
|
||||
C1 --> C2
|
||||
cssClass "C1" styleClass
|
||||
`);
|
||||
|
||||
const c1 = classDb.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
expect(c1.cssClasses.length).toBe(1);
|
||||
expect(c1.members[0]).toBe('+member1');
|
||||
expect(c1.cssClasses[0]).toBe('styleClass');
|
||||
});
|
||||
|
||||
it('should parse two classes with text labels and css classes', () => {
|
||||
parser.parse(`classDiagram
|
||||
class C1["Class 1 with text label"] {
|
||||
+member1
|
||||
}
|
||||
class C2["Long long long long long long long long long long label"]
|
||||
C1 --> C2
|
||||
cssClass "C1,C2" styleClass
|
||||
`);
|
||||
|
||||
const c1 = classDb.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
expect(c1.cssClasses.length).toBe(1);
|
||||
expect(c1.cssClasses[0]).toBe('styleClass');
|
||||
|
||||
const c2 = classDb.getClass('C2');
|
||||
expect(c2.label).toBe('Long long long long long long long long long long label');
|
||||
expect(c2.cssClasses.length).toBe(1);
|
||||
expect(c2.cssClasses[0]).toBe('styleClass');
|
||||
});
|
||||
|
||||
it('should parse two classes with text labels and css class shorthands', () => {
|
||||
parser.parse(`classDiagram
|
||||
class C1["Class 1 with text label"]:::styleClass1 {
|
||||
+member1
|
||||
}
|
||||
class C2["Class 2 !@#$%^&*() label"]:::styleClass2
|
||||
C1 --> C2
|
||||
`);
|
||||
|
||||
const c1 = classDb.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
expect(c1.cssClasses.length).toBe(1);
|
||||
expect(c1.cssClasses[0]).toBe('styleClass1');
|
||||
|
||||
const c2 = classDb.getClass('C2');
|
||||
expect(c2.label).toBe('Class 2 !@#$%^&*() label');
|
||||
expect(c2.cssClasses.length).toBe(1);
|
||||
expect(c2.cssClasses[0]).toBe('styleClass2');
|
||||
});
|
||||
|
||||
it('should parse multiple classes with same text labels', () => {
|
||||
parser.parse(`classDiagram
|
||||
class C1["Class with text label"]
|
||||
class C2["Class with text label"]
|
||||
class C3["Class with text label"]
|
||||
C1 --> C2
|
||||
C3 ..> C2
|
||||
`);
|
||||
|
||||
const c1 = classDb.getClass('C1');
|
||||
expect(c1.label).toBe('Class with text label');
|
||||
|
||||
const c2 = classDb.getClass('C2');
|
||||
expect(c2.label).toBe('Class with text label');
|
||||
|
||||
const c3 = classDb.getClass('C3');
|
||||
expect(c3.label).toBe('Class with text label');
|
||||
});
|
||||
|
||||
it('should parse classes with different text labels', () => {
|
||||
parser.parse(`classDiagram
|
||||
class C1["OneWord"]
|
||||
class C2["With, Comma"]
|
||||
class C3["With (Brackets)"]
|
||||
class C4["With [Brackets]"]
|
||||
class C5["With {Brackets}"]
|
||||
class C6[" "]
|
||||
class C7["With 1 number"]
|
||||
class C8["With . period..."]
|
||||
class C9["With - dash"]
|
||||
class C10["With _ underscore"]
|
||||
class C11["With ' single quote"]
|
||||
class C12["With ~!@#$%^&*()_+=-/?"]
|
||||
class C13["With Città foreign language"]
|
||||
`);
|
||||
expect(classDb.getClass('C1').label).toBe('OneWord');
|
||||
expect(classDb.getClass('C2').label).toBe('With, Comma');
|
||||
expect(classDb.getClass('C3').label).toBe('With (Brackets)');
|
||||
expect(classDb.getClass('C4').label).toBe('With [Brackets]');
|
||||
expect(classDb.getClass('C5').label).toBe('With {Brackets}');
|
||||
expect(classDb.getClass('C6').label).toBe(' ');
|
||||
expect(classDb.getClass('C7').label).toBe('With 1 number');
|
||||
expect(classDb.getClass('C8').label).toBe('With . period...');
|
||||
expect(classDb.getClass('C9').label).toBe('With - dash');
|
||||
expect(classDb.getClass('C10').label).toBe('With _ underscore');
|
||||
expect(classDb.getClass('C11').label).toBe("With ' single quote");
|
||||
expect(classDb.getClass('C12').label).toBe('With ~!@#$%^&*()_+=-/?');
|
||||
expect(classDb.getClass('C13').label).toBe('With Città foreign language');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
// @ts-ignore - no types
|
||||
import { LALRGenerator } from 'jison';
|
||||
import path from 'path';
|
||||
|
||||
const getAbsolutePath = (relativePath: string) => {
|
||||
return new URL(path.join(path.dirname(import.meta.url), relativePath)).pathname;
|
||||
return fileURLToPath(new URL(relativePath, import.meta.url));
|
||||
};
|
||||
|
||||
describe('class diagram grammar', function () {
|
||||
|
@ -1,4 +1,4 @@
|
||||
// @ts-ignore d3 types are not available
|
||||
// @ts-nocheck - don't check until handle it
|
||||
import { select, curveLinear } from 'd3';
|
||||
import * as graphlib from 'dagre-d3-es/src/graphlib/index.js';
|
||||
import { log } from '../../logger.js';
|
||||
@ -8,7 +8,7 @@ import utils from '../../utils.js';
|
||||
import { interpolateToCurve, getStylesFromArray } from '../../utils.js';
|
||||
import { setupGraphViewbox } from '../../setupGraphViewbox.js';
|
||||
import common from '../common/common.js';
|
||||
import { ClassRelation, ClassNote, ClassMap, EdgeData } from './classTypes.js';
|
||||
import { ClassRelation, ClassNote, ClassMap, EdgeData, NamespaceMap } from './classTypes.js';
|
||||
|
||||
const sanitizeText = (txt: string) => common.sanitizeText(txt, getConfig());
|
||||
|
||||
@ -19,6 +19,59 @@ let conf = {
|
||||
curve: undefined,
|
||||
};
|
||||
|
||||
interface RectParameters {
|
||||
id: string;
|
||||
shape: 'rect';
|
||||
labelStyle: string;
|
||||
domId: string;
|
||||
labelText: string;
|
||||
padding: number | undefined;
|
||||
style?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that adds the vertices found during parsing to the graph to be rendered.
|
||||
*
|
||||
* @param namespaces - Object containing the vertices.
|
||||
* @param g - The graph that is to be drawn.
|
||||
* @param _id - id of the graph
|
||||
* @param diagObj - The diagram object
|
||||
*/
|
||||
export const addNamespaces = function (
|
||||
namespaces: NamespaceMap,
|
||||
g: graphlib.Graph,
|
||||
_id: string,
|
||||
diagObj: any
|
||||
) {
|
||||
const keys = Object.keys(namespaces);
|
||||
log.info('keys:', keys);
|
||||
log.info(namespaces);
|
||||
|
||||
// Iterate through each item in the vertex object (containing all the vertices found) in the graph definition
|
||||
keys.forEach(function (id) {
|
||||
const vertex = namespaces[id];
|
||||
|
||||
// parent node must be one of [rect, roundedWithTitle, noteGroup, divider]
|
||||
const shape = 'rect';
|
||||
|
||||
const node: RectParameters = {
|
||||
shape: shape,
|
||||
id: vertex.id,
|
||||
domId: vertex.domId,
|
||||
labelText: sanitizeText(vertex.id),
|
||||
labelStyle: '',
|
||||
style: 'fill: none; stroke: black',
|
||||
// TODO V10: Flowchart ? Keeping flowchart for backwards compatibility. Remove in next major release
|
||||
padding: getConfig().flowchart?.padding ?? getConfig().class?.padding,
|
||||
};
|
||||
|
||||
g.setNode(vertex.id, node);
|
||||
addClasses(vertex.classes, g, _id, diagObj, vertex.id);
|
||||
|
||||
log.info('setNode', node);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Function that adds the vertices found during parsing to the graph to be rendered.
|
||||
*
|
||||
@ -26,12 +79,14 @@ let conf = {
|
||||
* @param g - The graph that is to be drawn.
|
||||
* @param _id - id of the graph
|
||||
* @param diagObj - The diagram object
|
||||
* @param parent - id of the parent namespace, if it exists
|
||||
*/
|
||||
export const addClasses = function (
|
||||
classes: ClassMap,
|
||||
g: graphlib.Graph,
|
||||
_id: string,
|
||||
diagObj: any
|
||||
diagObj: any,
|
||||
parent?: string
|
||||
) {
|
||||
const keys = Object.keys(classes);
|
||||
log.info('keys:', keys);
|
||||
@ -55,6 +110,7 @@ export const addClasses = function (
|
||||
const vertexText = vertex.label ?? vertex.id;
|
||||
const radius = 0;
|
||||
const shape = 'class_box';
|
||||
|
||||
// Add the node
|
||||
const node = {
|
||||
labelStyle: styles.labelStyle,
|
||||
@ -67,7 +123,7 @@ export const addClasses = function (
|
||||
style: styles.style,
|
||||
id: vertex.id,
|
||||
domId: vertex.domId,
|
||||
tooltip: diagObj.db.getTooltip(vertex.id) || '',
|
||||
tooltip: diagObj.db.getTooltip(vertex.id, parent) || '',
|
||||
haveCallback: vertex.haveCallback,
|
||||
link: vertex.link,
|
||||
width: vertex.type === 'group' ? 500 : undefined,
|
||||
@ -76,6 +132,11 @@ export const addClasses = function (
|
||||
padding: getConfig().flowchart?.padding ?? getConfig().class?.padding,
|
||||
};
|
||||
g.setNode(vertex.id, node);
|
||||
|
||||
if (parent) {
|
||||
g.setParent(vertex.id, parent);
|
||||
}
|
||||
|
||||
log.info('setNode', node);
|
||||
});
|
||||
};
|
||||
@ -275,10 +336,12 @@ export const draw = async function (text: string, id: string, _version: string,
|
||||
});
|
||||
|
||||
// Fetch the vertices/nodes and edges/links from the parsed graph definition
|
||||
const namespaces: NamespaceMap = diagObj.db.getNamespaces();
|
||||
const classes: ClassMap = diagObj.db.getClasses();
|
||||
const relations: ClassRelation[] = diagObj.db.getRelations();
|
||||
const notes: ClassNote[] = diagObj.db.getNotes();
|
||||
log.info(relations);
|
||||
addNamespaces(namespaces, g, id, diagObj);
|
||||
addClasses(classes, g, id, diagObj);
|
||||
addRelations(relations, g);
|
||||
addNotes(notes, g, relations.length + 1, classes);
|
||||
@ -290,15 +353,11 @@ export const draw = async function (text: string, id: string, _version: string,
|
||||
}
|
||||
const root =
|
||||
securityLevel === 'sandbox'
|
||||
? // @ts-ignore Ignore type error for now
|
||||
|
||||
select(sandboxElement.nodes()[0].contentDocument.body)
|
||||
? select(sandboxElement.nodes()[0].contentDocument.body)
|
||||
: select('body');
|
||||
// @ts-ignore Ignore type error for now
|
||||
const svg = root.select(`[id="${id}"]`);
|
||||
|
||||
// Run the renderer. This is what draws the final graph.
|
||||
// @ts-ignore Ignore type error for now
|
||||
const element = root.select('#' + id + ' g');
|
||||
await render(
|
||||
element,
|
||||
@ -314,7 +373,6 @@ export const draw = async function (text: string, id: string, _version: string,
|
||||
|
||||
// Add label rects for non html labels
|
||||
if (!conf?.htmlLabels) {
|
||||
// @ts-ignore Ignore type error for now
|
||||
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
|
||||
const labels = doc.querySelectorAll('[id="' + id + '"] .edgeLabel .label');
|
||||
for (const label of labels) {
|
||||
|
@ -52,4 +52,13 @@ export type ClassRelation = {
|
||||
lineType: number;
|
||||
};
|
||||
};
|
||||
|
||||
export interface NamespaceNode {
|
||||
id: string;
|
||||
domId: string;
|
||||
classes: ClassMap;
|
||||
children: NamespaceMap;
|
||||
}
|
||||
|
||||
export type ClassMap = Record<string, ClassNode>;
|
||||
export type NamespaceMap = Record<string, NamespaceNode>;
|
||||
|
@ -19,6 +19,10 @@
|
||||
%x acc_title
|
||||
%x acc_descr
|
||||
%x acc_descr_multiline
|
||||
%x class
|
||||
%x class-body
|
||||
%x namespace
|
||||
%x namespace-body
|
||||
%%
|
||||
\%\%\{ { this.begin('open_directive'); return 'open_directive'; }
|
||||
.*direction\s+TB[^\n]* return 'direction_tb';
|
||||
@ -41,35 +45,41 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili
|
||||
|
||||
\s*(\r?\n)+ return 'NEWLINE';
|
||||
\s+ /* skip whitespace */
|
||||
|
||||
"classDiagram-v2" return 'CLASS_DIAGRAM';
|
||||
"classDiagram" return 'CLASS_DIAGRAM';
|
||||
[{] { this.begin("struct"); /*console.log('Starting struct');*/ return 'STRUCT_START';}
|
||||
<INITIAL,struct>"[*]" { /*console.log('EDGE_STATE=',yytext);*/ return 'EDGE_STATE';}
|
||||
<struct><<EOF>> return "EOF_IN_STRUCT";
|
||||
<struct>[{] return "OPEN_IN_STRUCT";
|
||||
<struct>[}] { /*console.log('Ending struct');*/this.popState(); return 'STRUCT_STOP';}}
|
||||
<struct>[\n] /* nothing */
|
||||
<struct>[^{}\n]* { /*console.log('lex-member: ' + yytext);*/ return "MEMBER";}
|
||||
"[*]" return 'EDGE_STATE';
|
||||
|
||||
"class" return 'CLASS';
|
||||
"cssClass" return 'CSSCLASS';
|
||||
"callback" return 'CALLBACK';
|
||||
"link" return 'LINK';
|
||||
"click" return 'CLICK';
|
||||
"note for" return 'NOTE_FOR';
|
||||
"note" return 'NOTE';
|
||||
"<<" return 'ANNOTATION_START';
|
||||
">>" return 'ANNOTATION_END';
|
||||
[~] this.begin("generic");
|
||||
<generic>[~] this.popState();
|
||||
<generic>[^~]* return "GENERICTYPE";
|
||||
["] this.begin("string");
|
||||
<string>["] this.popState();
|
||||
<string>[^"]* return "STR";
|
||||
<INITIAL,namespace>"namespace" { this.begin('namespace'); return 'NAMESPACE'; }
|
||||
<namespace>\s*(\r?\n)+ { this.popState(); return 'NEWLINE'; }
|
||||
<namespace>\s+ /* skip whitespace */
|
||||
<namespace>[{] { this.begin("namespace-body"); return 'STRUCT_START';}
|
||||
<namespace-body>[}] { this.popState(); return 'STRUCT_STOP'; }
|
||||
<namespace-body><<EOF>> return "EOF_IN_STRUCT";
|
||||
<namespace-body>\s*(\r?\n)+ return 'NEWLINE';
|
||||
<namespace-body>\s+ /* skip whitespace */
|
||||
<namespace-body>"[*]" return 'EDGE_STATE';
|
||||
|
||||
[`] this.begin("bqstring");
|
||||
<bqstring>[`] this.popState();
|
||||
<bqstring>[^`]+ return "BQUOTE_STR";
|
||||
<INITIAL,namespace-body>"class" { this.begin('class'); return 'CLASS';}
|
||||
<class>\s*(\r?\n)+ { this.popState(); return 'NEWLINE'; }
|
||||
<class>\s+ /* skip whitespace */
|
||||
<class>[}] { this.popState(); this.popState(); return 'STRUCT_STOP';}
|
||||
<class>[{] { this.begin("class-body"); return 'STRUCT_START';}
|
||||
<class-body>[}] { this.popState(); return 'STRUCT_STOP'; }
|
||||
<class-body><<EOF>> return "EOF_IN_STRUCT";
|
||||
<class-body>"[*]" { return 'EDGE_STATE';}
|
||||
<class-body>[{] return "OPEN_IN_STRUCT";
|
||||
<class-body>[\n] /* nothing */
|
||||
<class-body>[^{}\n]* { return "MEMBER";}
|
||||
|
||||
<*>"cssClass" return 'CSSCLASS';
|
||||
<*>"callback" return 'CALLBACK';
|
||||
<*>"link" return 'LINK';
|
||||
<*>"click" return 'CLICK';
|
||||
<*>"note for" return 'NOTE_FOR';
|
||||
<*>"note" return 'NOTE';
|
||||
<*>"<<" return 'ANNOTATION_START';
|
||||
<*>">>" return 'ANNOTATION_END';
|
||||
|
||||
/*
|
||||
---interactivity command---
|
||||
@ -77,7 +87,7 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili
|
||||
line was introduced with 'click'.
|
||||
'href "<link>"' attaches the specified link to the node that was specified by 'click'.
|
||||
*/
|
||||
"href"[\s]+["] this.begin("href");
|
||||
<*>"href"[\s]+["] this.begin("href");
|
||||
<href>["] this.popState();
|
||||
<href>[^"]* return 'HREF';
|
||||
|
||||
@ -89,41 +99,53 @@ the line was introduced with 'click'.
|
||||
arguments to the node that was specified by 'click'.
|
||||
Function arguments are optional: 'call <callback_name>()' simply executes 'callback_name' without any arguments.
|
||||
*/
|
||||
"call"[\s]+ this.begin("callback_name");
|
||||
<*>"call"[\s]+ this.begin("callback_name");
|
||||
<callback_name>\([\s]*\) this.popState();
|
||||
<callback_name>\( this.popState(); this.begin("callback_args");
|
||||
<callback_name>[^(]* return 'CALLBACK_NAME';
|
||||
<callback_args>\) this.popState();
|
||||
<callback_args>[^)]* return 'CALLBACK_ARGS';
|
||||
|
||||
"_self" return 'LINK_TARGET';
|
||||
"_blank" return 'LINK_TARGET';
|
||||
"_parent" return 'LINK_TARGET';
|
||||
"_top" return 'LINK_TARGET';
|
||||
<generic>[~] this.popState();
|
||||
<generic>[^~]* return "GENERICTYPE";
|
||||
<*>[~] this.begin("generic");
|
||||
|
||||
\s*\<\| return 'EXTENSION';
|
||||
\s*\|\> return 'EXTENSION';
|
||||
\s*\> return 'DEPENDENCY';
|
||||
\s*\< return 'DEPENDENCY';
|
||||
\s*\* return 'COMPOSITION';
|
||||
\s*o return 'AGGREGATION';
|
||||
\s*\(\) return 'LOLLIPOP';
|
||||
\-\- return 'LINE';
|
||||
\.\. return 'DOTTED_LINE';
|
||||
":"{1}[^:\n;]+ return 'LABEL';
|
||||
":"{3} return 'STYLE_SEPARATOR';
|
||||
\- return 'MINUS';
|
||||
"." return 'DOT';
|
||||
\+ return 'PLUS';
|
||||
\% return 'PCT';
|
||||
"=" return 'EQUALS';
|
||||
\= return 'EQUALS';
|
||||
\w+ return 'ALPHA';
|
||||
"[" return 'SQS';
|
||||
"]" return 'SQE';
|
||||
[!"#$%&'*+,-.`?\\/] return 'PUNCTUATION';
|
||||
[0-9]+ return 'NUM';
|
||||
[\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6]|
|
||||
<string>["] this.popState();
|
||||
<string>[^"]* return "STR";
|
||||
<*>["] this.begin("string");
|
||||
|
||||
<bqstring>[`] this.popState();
|
||||
<bqstring>[^`]+ return "BQUOTE_STR";
|
||||
<*>[`] this.begin("bqstring");
|
||||
|
||||
<*>"_self" return 'LINK_TARGET';
|
||||
<*>"_blank" return 'LINK_TARGET';
|
||||
<*>"_parent" return 'LINK_TARGET';
|
||||
<*>"_top" return 'LINK_TARGET';
|
||||
|
||||
<*>\s*\<\| return 'EXTENSION';
|
||||
<*>\s*\|\> return 'EXTENSION';
|
||||
<*>\s*\> return 'DEPENDENCY';
|
||||
<*>\s*\< return 'DEPENDENCY';
|
||||
<*>\s*\* return 'COMPOSITION';
|
||||
<*>\s*o return 'AGGREGATION';
|
||||
<*>\s*\(\) return 'LOLLIPOP';
|
||||
<*>\-\- return 'LINE';
|
||||
<*>\.\. return 'DOTTED_LINE';
|
||||
<*>":"{1}[^:\n;]+ return 'LABEL';
|
||||
<*>":"{3} return 'STYLE_SEPARATOR';
|
||||
<*>\- return 'MINUS';
|
||||
<*>"." return 'DOT';
|
||||
<*>\+ return 'PLUS';
|
||||
<*>\% return 'PCT';
|
||||
<*>"=" return 'EQUALS';
|
||||
<*>\= return 'EQUALS';
|
||||
<*>\w+ return 'ALPHA';
|
||||
<*>"[" return 'SQS';
|
||||
<*>"]" return 'SQE';
|
||||
<*>[!"#$%&'*+,-.`?\\/] return 'PUNCTUATION';
|
||||
<*>[0-9]+ return 'NUM';
|
||||
<*>[\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6]|
|
||||
[\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377]|
|
||||
[\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5]|
|
||||
[\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA]|
|
||||
@ -184,9 +206,9 @@ Function arguments are optional: 'call <callback_name>()' simply executes 'callb
|
||||
[\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC]|
|
||||
[\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF]|
|
||||
[\uFFD2-\uFFD7\uFFDA-\uFFDC]
|
||||
return 'UNICODE_TEXT';
|
||||
\s return 'SPACE';
|
||||
<<EOF>> return 'EOF';
|
||||
return 'UNICODE_TEXT';
|
||||
<*>\s return 'SPACE';
|
||||
<*><<EOF>> return 'EOF';
|
||||
|
||||
/lex
|
||||
|
||||
@ -254,6 +276,11 @@ classLabel
|
||||
: SQS STR SQE { $$=$2; }
|
||||
;
|
||||
|
||||
namespaceName
|
||||
: alphaNumToken { $$=$1; }
|
||||
| alphaNumToken namespaceName { $$=$1+$2; }
|
||||
;
|
||||
|
||||
className
|
||||
: alphaNumToken { $$=$1; }
|
||||
| classLiteralName { $$=$1; }
|
||||
@ -265,6 +292,7 @@ className
|
||||
statement
|
||||
: relationStatement { yy.addRelation($1); }
|
||||
| relationStatement LABEL { $1.title = yy.cleanupLabel($2); yy.addRelation($1); }
|
||||
| namespaceStatement
|
||||
| classStatement
|
||||
| methodStatement
|
||||
| annotationStatement
|
||||
@ -277,6 +305,21 @@ statement
|
||||
| acc_descr_multiline_value { $$=$1.trim();yy.setAccDescription($$); }
|
||||
;
|
||||
|
||||
namespaceStatement
|
||||
: namespaceIdentifier STRUCT_START classStatements STRUCT_STOP {yy.addClassesToNamespace($1, $3);}
|
||||
| namespaceIdentifier STRUCT_START NEWLINE classStatements STRUCT_STOP {yy.addClassesToNamespace($1, $4);}
|
||||
;
|
||||
|
||||
namespaceIdentifier
|
||||
: NAMESPACE namespaceName {$$=$2; yy.addNamespace($2);}
|
||||
;
|
||||
|
||||
classStatements
|
||||
: classStatement {$$=[$1]}
|
||||
| classStatement NEWLINE {$$=[$1]}
|
||||
| classStatement NEWLINE classStatements {$3.unshift($1); $$=$3}
|
||||
;
|
||||
|
||||
classStatement
|
||||
: classIdentifier
|
||||
| classIdentifier STYLE_SEPARATOR alphaNumToken {yy.setCssClass($1, $3);}
|
||||
|
@ -361,72 +361,6 @@ export const drawNote = function (elem, note, conf, diagObj) {
|
||||
};
|
||||
|
||||
export const parseMember = function (text) {
|
||||
// Note: these two regular expressions don't parse the official UML syntax for attributes
|
||||
// and methods. They parse a Java-style syntax of the form
|
||||
// "String name" (for attributes) and "String name(int x)" for methods
|
||||
const fieldRegEx = /^([#+~-])?(\w+)(~\w+~|\[])?\s+(\w+) *([$*])?$/;
|
||||
const methodRegEx = /^([#+|~-])?(\w+) *\( *(.*)\) *([$*])? *(\w*[[\]|~]*\s*\w*~?)$/;
|
||||
|
||||
let fieldMatch = text.match(fieldRegEx);
|
||||
let methodMatch = text.match(methodRegEx);
|
||||
|
||||
if (fieldMatch && !methodMatch) {
|
||||
return buildFieldDisplay(fieldMatch);
|
||||
} else if (methodMatch) {
|
||||
return buildMethodDisplay(methodMatch);
|
||||
} else {
|
||||
return buildLegacyDisplay(text);
|
||||
}
|
||||
};
|
||||
|
||||
const buildFieldDisplay = function (parsedText) {
|
||||
let cssStyle = '';
|
||||
let displayText = '';
|
||||
|
||||
try {
|
||||
let visibility = parsedText[1] ? parsedText[1].trim() : '';
|
||||
let fieldType = parsedText[2] ? parsedText[2].trim() : '';
|
||||
let genericType = parsedText[3] ? parseGenericTypes(parsedText[3].trim()) : '';
|
||||
let fieldName = parsedText[4] ? parsedText[4].trim() : '';
|
||||
let classifier = parsedText[5] ? parsedText[5].trim() : '';
|
||||
|
||||
displayText = visibility + fieldType + genericType + ' ' + fieldName;
|
||||
cssStyle = parseClassifier(classifier);
|
||||
} catch (err) {
|
||||
displayText = parsedText;
|
||||
}
|
||||
|
||||
return {
|
||||
displayText: displayText,
|
||||
cssStyle: cssStyle,
|
||||
};
|
||||
};
|
||||
|
||||
const buildMethodDisplay = function (parsedText) {
|
||||
let cssStyle = '';
|
||||
let displayText = '';
|
||||
|
||||
try {
|
||||
let visibility = parsedText[1] ? parsedText[1].trim() : '';
|
||||
let methodName = parsedText[2] ? parsedText[2].trim() : '';
|
||||
let parameters = parsedText[3] ? parseGenericTypes(parsedText[3].trim()) : '';
|
||||
let classifier = parsedText[4] ? parsedText[4].trim() : '';
|
||||
let returnType = parsedText[5] ? ' : ' + parseGenericTypes(parsedText[5]).trim() : '';
|
||||
|
||||
displayText = visibility + methodName + '(' + parameters + ')' + returnType;
|
||||
cssStyle = parseClassifier(classifier);
|
||||
} catch (err) {
|
||||
displayText = parsedText;
|
||||
}
|
||||
|
||||
return {
|
||||
displayText: displayText,
|
||||
cssStyle: cssStyle,
|
||||
};
|
||||
};
|
||||
|
||||
const buildLegacyDisplay = function (text) {
|
||||
// if for some reason we don't have any match, use old format to parse text
|
||||
let displayText = '';
|
||||
let cssStyle = '';
|
||||
let returnType = '';
|
||||
@ -444,14 +378,15 @@ const buildLegacyDisplay = function (text) {
|
||||
cssStyle = parseClassifier(lastChar);
|
||||
}
|
||||
|
||||
let startIndex = visibility === '' ? 0 : 1;
|
||||
const startIndex = visibility === '' ? 0 : 1;
|
||||
let endIndex = cssStyle === '' ? text.length : text.length - 1;
|
||||
text = text.substring(startIndex, endIndex);
|
||||
|
||||
let methodStart = text.indexOf('(');
|
||||
let methodEnd = text.indexOf(')');
|
||||
const methodStart = text.indexOf('(');
|
||||
const methodEnd = text.indexOf(')');
|
||||
const isMethod = methodStart > 1 && methodEnd > methodStart && methodEnd <= text.length;
|
||||
|
||||
if (methodStart > 1 && methodEnd > methodStart && methodEnd <= text.length) {
|
||||
if (isMethod) {
|
||||
let methodName = text.substring(0, methodStart).trim();
|
||||
|
||||
const parameters = text.substring(methodStart + 1, methodEnd);
|
||||
@ -478,7 +413,7 @@ const buildLegacyDisplay = function (text) {
|
||||
}
|
||||
} else {
|
||||
// finally - if all else fails, just send the text back as written (other than parsing for generic types)
|
||||
displayText = parseGenericTypes(text);
|
||||
displayText = visibility + parseGenericTypes(text);
|
||||
}
|
||||
|
||||
return {
|
||||
@ -486,6 +421,7 @@ const buildLegacyDisplay = function (text) {
|
||||
cssStyle,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a <tspan> for a member in a diagram
|
||||
*
|
||||
|
@ -138,6 +138,32 @@ const getUrl = (useAbsolute: boolean): string => {
|
||||
export const evaluate = (val?: string | boolean): boolean =>
|
||||
val === false || ['false', 'null', '0'].includes(String(val).trim().toLowerCase()) ? false : true;
|
||||
|
||||
/**
|
||||
* Wrapper around Math.max which removes non-numeric values
|
||||
* Returns the larger of a set of supplied numeric expressions.
|
||||
* @param values - Numeric expressions to be evaluated
|
||||
* @returns The smaller value
|
||||
*/
|
||||
export const getMax = function (...values: number[]): number {
|
||||
const newValues: number[] = values.filter((value) => {
|
||||
return !isNaN(value);
|
||||
});
|
||||
return Math.max(...newValues);
|
||||
};
|
||||
|
||||
/**
|
||||
* Wrapper around Math.min which removes non-numeric values
|
||||
* Returns the smaller of a set of supplied numeric expressions.
|
||||
* @param values - Numeric expressions to be evaluated
|
||||
* @returns The smaller value
|
||||
*/
|
||||
export const getMin = function (...values: number[]): number {
|
||||
const newValues: number[] = values.filter((value) => {
|
||||
return !isNaN(value);
|
||||
});
|
||||
return Math.min(...newValues);
|
||||
};
|
||||
|
||||
/**
|
||||
* Makes generics in typescript syntax
|
||||
*
|
||||
@ -180,4 +206,6 @@ export default {
|
||||
removeScript,
|
||||
getUrl,
|
||||
evaluate,
|
||||
getMax,
|
||||
getMin,
|
||||
};
|
||||
|
114
packages/mermaid/src/diagrams/common/svgDrawCommon.js
Normal file
114
packages/mermaid/src/diagrams/common/svgDrawCommon.js
Normal file
@ -0,0 +1,114 @@
|
||||
import { sanitizeUrl } from '@braintree/sanitize-url';
|
||||
|
||||
export const drawRect = function (elem, rectData) {
|
||||
const rectElem = elem.append('rect');
|
||||
rectElem.attr('x', rectData.x);
|
||||
rectElem.attr('y', rectData.y);
|
||||
rectElem.attr('fill', rectData.fill);
|
||||
rectElem.attr('stroke', rectData.stroke);
|
||||
rectElem.attr('width', rectData.width);
|
||||
rectElem.attr('height', rectData.height);
|
||||
rectElem.attr('rx', rectData.rx);
|
||||
rectElem.attr('ry', rectData.ry);
|
||||
|
||||
if (rectData.attrs !== 'undefined' && rectData.attrs !== null) {
|
||||
for (let attrKey in rectData.attrs) {
|
||||
rectElem.attr(attrKey, rectData.attrs[attrKey]);
|
||||
}
|
||||
}
|
||||
|
||||
if (rectData.class !== 'undefined') {
|
||||
rectElem.attr('class', rectData.class);
|
||||
}
|
||||
|
||||
return rectElem;
|
||||
};
|
||||
|
||||
/**
|
||||
* Draws a background rectangle
|
||||
*
|
||||
* @param {any} elem Diagram (reference for bounds)
|
||||
* @param {any} bounds Shape of the rectangle
|
||||
*/
|
||||
export const drawBackgroundRect = function (elem, bounds) {
|
||||
const rectElem = drawRect(elem, {
|
||||
x: bounds.startx,
|
||||
y: bounds.starty,
|
||||
width: bounds.stopx - bounds.startx,
|
||||
height: bounds.stopy - bounds.starty,
|
||||
fill: bounds.fill,
|
||||
stroke: bounds.stroke,
|
||||
class: 'rect',
|
||||
});
|
||||
rectElem.lower();
|
||||
};
|
||||
|
||||
export const drawText = function (elem, textData) {
|
||||
// Remove and ignore br:s
|
||||
const nText = textData.text.replace(/<br\s*\/?>/gi, ' ');
|
||||
|
||||
const textElem = elem.append('text');
|
||||
textElem.attr('x', textData.x);
|
||||
textElem.attr('y', textData.y);
|
||||
textElem.attr('class', 'legend');
|
||||
|
||||
textElem.style('text-anchor', textData.anchor);
|
||||
|
||||
if (textData.class !== undefined) {
|
||||
textElem.attr('class', textData.class);
|
||||
}
|
||||
|
||||
const span = textElem.append('tspan');
|
||||
span.attr('x', textData.x + textData.textMargin * 2);
|
||||
span.text(nText);
|
||||
|
||||
return textElem;
|
||||
};
|
||||
|
||||
export const drawImage = function (elem, x, y, link) {
|
||||
const imageElem = elem.append('image');
|
||||
imageElem.attr('x', x);
|
||||
imageElem.attr('y', y);
|
||||
var sanitizedLink = sanitizeUrl(link);
|
||||
imageElem.attr('xlink:href', sanitizedLink);
|
||||
};
|
||||
|
||||
export const drawEmbeddedImage = function (elem, x, y, link) {
|
||||
const imageElem = elem.append('use');
|
||||
imageElem.attr('x', x);
|
||||
imageElem.attr('y', y);
|
||||
const sanitizedLink = sanitizeUrl(link);
|
||||
imageElem.attr('xlink:href', '#' + sanitizedLink);
|
||||
};
|
||||
|
||||
export const getNoteRect = function () {
|
||||
return {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 100,
|
||||
fill: '#EDF2AE',
|
||||
stroke: '#666',
|
||||
anchor: 'start',
|
||||
rx: 0,
|
||||
ry: 0,
|
||||
};
|
||||
};
|
||||
|
||||
export const getTextObj = function () {
|
||||
return {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 100,
|
||||
fill: undefined,
|
||||
anchor: undefined,
|
||||
'text-anchor': 'start',
|
||||
style: '#666',
|
||||
textMargin: 0,
|
||||
rx: 0,
|
||||
ry: 0,
|
||||
tspan: true,
|
||||
valign: undefined,
|
||||
};
|
||||
};
|
@ -20,6 +20,7 @@ const Cardinality = {
|
||||
ZERO_OR_MORE: 'ZERO_OR_MORE',
|
||||
ONE_OR_MORE: 'ONE_OR_MORE',
|
||||
ONLY_ONE: 'ONLY_ONE',
|
||||
MD_PARENT: 'MD_PARENT',
|
||||
};
|
||||
|
||||
const Identification = {
|
||||
|
@ -1,12 +1,16 @@
|
||||
import type { DiagramDetector, ExternalDiagramDefinition } from '../../diagram-api/types.js';
|
||||
import type {
|
||||
DiagramDetector,
|
||||
DiagramLoader,
|
||||
ExternalDiagramDefinition,
|
||||
} from '../../diagram-api/types.js';
|
||||
|
||||
const id = 'er';
|
||||
|
||||
const detector: DiagramDetector = (txt) => {
|
||||
return txt.match(/^\s*erDiagram/) !== null;
|
||||
return /^\s*erDiagram/.test(txt);
|
||||
};
|
||||
|
||||
const loader = async () => {
|
||||
const loader: DiagramLoader = async () => {
|
||||
const { diagram } = await import('./erDiagram.js');
|
||||
return { id, diagram };
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
// @ts-ignore: TODO Fix ts errors
|
||||
// @ts-ignore: TODO: Fix ts errors
|
||||
import erParser from './parser/erDiagram.jison';
|
||||
import erDb from './erDb.js';
|
||||
import erRenderer from './erRenderer.js';
|
||||
|
@ -7,6 +7,8 @@ const ERMarkers = {
|
||||
ONE_OR_MORE_END: 'ONE_OR_MORE_END',
|
||||
ZERO_OR_MORE_START: 'ZERO_OR_MORE_START',
|
||||
ZERO_OR_MORE_END: 'ZERO_OR_MORE_END',
|
||||
MD_PARENT_END: 'MD_PARENT_END',
|
||||
MD_PARENT_START: 'MD_PARENT_START',
|
||||
};
|
||||
|
||||
/**
|
||||
@ -18,6 +20,30 @@ const ERMarkers = {
|
||||
const insertMarkers = function (elem, conf) {
|
||||
let marker;
|
||||
|
||||
elem
|
||||
.append('defs')
|
||||
.append('marker')
|
||||
.attr('id', ERMarkers.MD_PARENT_START)
|
||||
.attr('refX', 0)
|
||||
.attr('refY', 7)
|
||||
.attr('markerWidth', 190)
|
||||
.attr('markerHeight', 240)
|
||||
.attr('orient', 'auto')
|
||||
.append('path')
|
||||
.attr('d', 'M 18,7 L9,13 L1,7 L9,1 Z');
|
||||
|
||||
elem
|
||||
.append('defs')
|
||||
.append('marker')
|
||||
.attr('id', ERMarkers.MD_PARENT_END)
|
||||
.attr('refX', 19)
|
||||
.attr('refY', 7)
|
||||
.attr('markerWidth', 20)
|
||||
.attr('markerHeight', 28)
|
||||
.attr('orient', 'auto')
|
||||
.append('path')
|
||||
.attr('d', 'M 18,7 L9,13 L1,7 L9,1 Z');
|
||||
|
||||
elem
|
||||
.append('defs')
|
||||
.append('marker')
|
||||
|
@ -478,6 +478,9 @@ const drawRelationshipFromLayout = function (svg, rel, g, insert, diagObj) {
|
||||
case diagObj.db.Cardinality.ONLY_ONE:
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ONLY_ONE_END + ')');
|
||||
break;
|
||||
case diagObj.db.Cardinality.MD_PARENT:
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.MD_PARENT_END + ')');
|
||||
break;
|
||||
}
|
||||
|
||||
switch (rel.relSpec.cardB) {
|
||||
@ -502,6 +505,9 @@ const drawRelationshipFromLayout = function (svg, rel, g, insert, diagObj) {
|
||||
case diagObj.db.Cardinality.ONLY_ONE:
|
||||
svgPath.attr('marker-start', 'url(' + url + '#' + erMarkers.ERMarkers.ONLY_ONE_START + ')');
|
||||
break;
|
||||
case diagObj.db.Cardinality.MD_PARENT:
|
||||
svgPath.attr('marker-start', 'url(' + url + '#' + erMarkers.ERMarkers.MD_PARENT_START + ')');
|
||||
break;
|
||||
}
|
||||
|
||||
// Now label the relationship
|
||||
|
@ -57,6 +57,7 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili
|
||||
o\| return 'ZERO_OR_ONE';
|
||||
o\{ return 'ZERO_OR_MORE';
|
||||
\|\{ return 'ONE_OR_MORE';
|
||||
\s*u return 'MD_PARENT';
|
||||
\.\. return 'NON_IDENTIFYING';
|
||||
\-\- return 'IDENTIFYING';
|
||||
"to" return 'IDENTIFYING';
|
||||
@ -170,6 +171,7 @@ cardinality
|
||||
| 'ZERO_OR_MORE' { $$ = yy.Cardinality.ZERO_OR_MORE; }
|
||||
| 'ONE_OR_MORE' { $$ = yy.Cardinality.ONE_OR_MORE; }
|
||||
| 'ONLY_ONE' { $$ = yy.Cardinality.ONLY_ONE; }
|
||||
| 'MD_PARENT' { $$ = yy.Cardinality.MD_PARENT; }
|
||||
;
|
||||
|
||||
relType
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user