Merge branch 'mermaid-js:develop' into develop

This commit is contained in:
Cory Gwin
2022-04-06 08:59:15 -04:00
committed by GitHub
118 changed files with 168763 additions and 4251 deletions

8
.ackrc
View File

@@ -1,4 +1,4 @@
--ignore-dir=dist
--ignore-file=match:/^yarn\.lock$/
--ignore-file=match:/^yarn-error\.log$/
--ignore-dir=coverage
--ignore-dir=dist
--ignore-file=match:/^yarn\.lock$/
--ignore-file=match:/^yarn-error\.log$/
--ignore-dir=coverage

View File

@@ -1,11 +1,11 @@
root = true
[*]
indent_style = space
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
indent_size = 4
root = true
[*]
indent_style = space
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
indent_size = 4

24
.github/FUNDING.yml vendored
View File

@@ -1,12 +1,12 @@
# These are supported funding model platforms
github: [knsv]
#patreon: # Replace with a single Patreon username
#open_collective: # Replace with a single Open Collective username
#ko_fi: # Replace with a single Ko-fi username
#tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
#community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
#liberapay: # Replace with a single Liberapay username
#issuehunt: # Replace with a single IssueHunt username
#otechie: # Replace with a single Otechie username
#custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
# These are supported funding model platforms
github: [knsv]
#patreon: # Replace with a single Patreon username
#open_collective: # Replace with a single Open Collective username
#ko_fi: # Replace with a single Ko-fi username
#tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
#community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
#liberapay: # Replace with a single Liberapay username
#issuehunt: # Replace with a single IssueHunt username
#otechie: # Replace with a single Otechie username
#custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View File

@@ -1,20 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: 'Status: Triage, Type: Enhancement'
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: 'Status: Triage, Type: Enhancement'
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@@ -1,15 +1,15 @@
---
name: Question
about: Get some help from the community.
title: ''
labels: 'Help wanted!, Type: Other'
assignees: ''
---
## Help us help you!
You want an answer. Here are some ways to get it quicker:
* Use a clear and concise title.
* Try to pose a clear and concise question.
* Include as much, or as little, code as necessary.
* Don't be shy to give us some screenshots, if it helps!
---
name: Question
about: Get some help from the community.
title: ''
labels: 'Help wanted!, Type: Other'
assignees: ''
---
## Help us help you!
You want an answer. Here are some ways to get it quicker:
* Use a clear and concise title.
* Try to pose a clear and concise question.
* Include as much, or as little, code as necessary.
* Don't be shy to give us some screenshots, if it helps!

View File

@@ -1,13 +1,13 @@
## :bookmark_tabs: Summary
Brief description about the content of your PR.
Resolves #<your issue id here>
## :straight_ruler: Design Decisions
Describe the way your implementation works or what design decisions you made if applicable.
### :clipboard: Tasks
Make sure you
- [ ] :book: have read the [contribution guidelines](https://github.com/mermaid-js/mermaid/blob/develop/CONTRIBUTING.md)
- [ ] :computer: have added unit/e2e tests (if appropriate)
- [ ] :bookmark: targeted `develop` branch
## :bookmark_tabs: Summary
Brief description about the content of your PR.
Resolves #<your issue id here>
## :straight_ruler: Design Decisions
Describe the way your implementation works or what design decisions you made if applicable.
### :clipboard: Tasks
Make sure you
- [ ] :book: have read the [contribution guidelines](https://github.com/mermaid-js/mermaid/blob/develop/CONTRIBUTING.md)
- [ ] :computer: have added unit/e2e tests (if appropriate)
- [ ] :bookmark: targeted `develop` branch

View File

@@ -1,25 +1,25 @@
name-template: '$NEXT_PATCH_VERSION'
tag-template: '$NEXT_PATCH_VERSION'
categories:
- title: '🚀 Features'
labels:
- 'Type: Enhancement'
- title: '🐛 Bug Fixes'
labels:
- 'Type: Bug / Error'
- title: '🧰 Maintenance'
label: 'Type: Other'
change-template: '- $TITLE (#$NUMBER) @$AUTHOR'
sort-by: title
sort-direction: ascending
branches:
- develop
exclude-labels:
- 'Skip changelog'
no-changes-template: 'This release contains minor changes and bugfixes.'
template: |
# Release Notes
$CHANGES
🎉 **Thanks to all contributors helping with this release!** 🎉
name-template: '$NEXT_PATCH_VERSION'
tag-template: '$NEXT_PATCH_VERSION'
categories:
- title: '🚀 Features'
labels:
- 'Type: Enhancement'
- title: '🐛 Bug Fixes'
labels:
- 'Type: Bug / Error'
- title: '🧰 Maintenance'
label: 'Type: Other'
change-template: '- $TITLE (#$NUMBER) @$AUTHOR'
sort-by: title
sort-direction: ascending
branches:
- develop
exclude-labels:
- 'Skip changelog'
no-changes-template: 'This release contains minor changes and bugfixes.'
template: |
# Release Notes
$CHANGES
🎉 **Thanks to all contributors helping with this release!** 🎉

38
.github/stale.yml vendored
View File

@@ -1,19 +1,19 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 60
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 14
# Issues with these labels will never be considered stale
exemptLabels:
- Retained
# Label to use when marking an issue as stale
staleLabel: Inactive
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
If you are still interested in this issue and it is still relevant you can comment to revive it.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: >
This issue has been been automatically closed due to a lack of activity.
This is done to maintain a clean list of issues that the community is interested in developing.
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 60
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 14
# Issues with these labels will never be considered stale
exemptLabels:
- Retained
# Label to use when marking an issue as stale
staleLabel: Inactive
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
If you are still interested in this issue and it is still relevant you can comment to revive it.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: >
This issue has been been automatically closed due to a lack of activity.
This is done to maintain a clean list of issues that the community is interested in developing.

View File

@@ -5,12 +5,10 @@ name: Check if README and docs/README are in sync
on:
push:
branches:
- master
- develop
- gh-pages
pull_request:
branches:
- master
- develop
- gh-pages
jobs:
check:

View File

@@ -1,19 +1,19 @@
on: [push]
name: Static analysis
jobs:
test:
runs-on: ubuntu-latest
name: check tests
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- uses: testomatio/check-tests@stable
with:
framework: cypress
tests: "./cypress/integration/**/**.spec.js"
token: ${{ secrets.GITHUB_TOKEN }}
has-tests-label: true
on: [push]
name: Static analysis
jobs:
test:
runs-on: ubuntu-latest
name: check tests
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- uses: testomatio/check-tests@stable
with:
framework: cypress
tests: "./cypress/integration/**/**.spec.js"
token: ${{ secrets.GITHUB_TOKEN }}
has-tests-label: true

View File

@@ -1,13 +1,13 @@
name: Unlock reopened issue
on:
issues:
types: [reopened]
jobs:
triage:
runs-on: ubuntu-latest
steps:
- uses: Dunning-Kruger/unlock-issues@v1
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
name: Unlock reopened issue
on:
issues:
types: [reopened]
jobs:
triage:
runs-on: ubuntu-latest
steps:
- uses: Dunning-Kruger/unlock-issues@v1
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"

View File

@@ -11,7 +11,7 @@ jobs:
- uses: actions/checkout@v3
- run: npx browserslist@latest --update-db
- name: Commit changes
uses: EndBug/add-and-commit@v8.0.2
uses: EndBug/add-and-commit@v9
with:
author_name: ${{ github.actor }}
author_email: ${{ github.actor }}@users.noreply.github.com

3
.gitignore vendored
View File

@@ -20,3 +20,6 @@ local/
_site
Gemfile.lock
/.vs
cypress/screenshots/
cypress/snapshots/

4
.husky/commit-msg Executable file → Normal file
View File

@@ -1,4 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
# . "$(dirname "$0")/_/husky.sh"
npx --no-install commitlint --edit $1
# npx --no-install commitlint --edit $1

0
.husky/pre-commit Executable file → Normal file
View File

View File

@@ -1,22 +1,22 @@
{
"ecmaVersion": 6,
"libs": [
"browser"
],
"loadEagerly": [
"path/to/your/js/**/*.js"
],
"dontLoad": [
"node_modules/**",
"path/to/your/js/**/*.js"
],
"plugins": {
"modules": {},
"es_modules": {},
"node": {},
"doc_comment": {
"fullDocs": true,
"strong": true
}
}
{
"ecmaVersion": 6,
"libs": [
"browser"
],
"loadEagerly": [
"path/to/your/js/**/*.js"
],
"dontLoad": [
"node_modules/**",
"path/to/your/js/**/*.js"
],
"plugins": {
"modules": {},
"es_modules": {},
"node": {},
"doc_comment": {
"fullDocs": true,
"strong": true
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
# mermaid [![Build Status](https://travis-ci.org/mermaid-js/mermaid.svg?branch=master)](https://travis-ci.org/mermaid-js/mermaid) [![NPM](https://img.shields.io/npm/v/mermaid)](https://www.npmjs.com/package/mermaid) [![Coverage Status](https://coveralls.io/repos/github/mermaid-js/mermaid/badge.svg?branch=master)](https://coveralls.io/github/mermaid-js/mermaid?branch=master) [![Join our Slack!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=slack&label=slack)](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE) [![This project is using Percy.io for visual regression testing.](https://percy.io/static/images/percy-badge.svg)](https://percy.io/Mermaid/mermaid)
# mermaid [![Build Status](https://travis-ci.org/mermaid-js/mermaid.svg?branch=master)](https://travis-ci.org/mermaid-js/mermaid) [![NPM](https://img.shields.io/npm/v/mermaid)](https://www.npmjs.com/package/mermaid) [![Coverage Status](https://coveralls.io/repos/github/mermaid-js/mermaid/badge.svg?branch=master)](https://coveralls.io/github/mermaid-js/mermaid?branch=master) [![Join our Slack!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=slack&label=slack)](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE)
English | [简体中文](./README.zh-CN.md)

View File

@@ -1,4 +1,4 @@
# mermaid [![Build Status](https://travis-ci.org/mermaid-js/mermaid.svg?branch=master)](https://travis-ci.org/mermaid-js/mermaid) [![NPM](https://img.shields.io/npm/v/mermaid)](https://www.npmjs.com/package/mermaid) [![Coverage Status](https://coveralls.io/repos/github/mermaid-js/mermaid/badge.svg?branch=master)](https://coveralls.io/github/mermaid-js/mermaid?branch=master) [![Join our Slack!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=slack&label=slack)](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE) [![This project is using Percy.io for visual regression testing.](https://percy.io/static/images/percy-badge.svg)](https://percy.io/Mermaid/mermaid)
# mermaid [![Build Status](https://travis-ci.org/mermaid-js/mermaid.svg?branch=master)](https://travis-ci.org/mermaid-js/mermaid) [![NPM](https://img.shields.io/npm/v/mermaid)](https://www.npmjs.com/package/mermaid) [![Coverage Status](https://coveralls.io/repos/github/mermaid-js/mermaid/badge.svg?branch=master)](https://coveralls.io/github/mermaid-js/mermaid?branch=master) [![Join our Slack!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=slack&label=slack)](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE)
[English](./README.md) | 简体中文

View File

@@ -1,5 +1,5 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}

View File

@@ -47,7 +47,11 @@ export const imgSnapshotTest = (graphStr, _options, api) => {
cy.visit(url);
cy.get('svg');
cy.percySnapshot();
// cy.percySnapshot();
// Default name to test title
const name = (options.name || cy.state('runnable').fullTitle()).replace(/\s+/g, '-');
cy.matchImageSnapshot(name);
};
export const renderGraph = (graphStr, options, api) => {

View File

@@ -111,7 +111,9 @@ describe('Configuration', () => {
cy.visit(url);
cy.get('svg');
cy.percySnapshot();
cy.matchImageSnapshot(
'configuration.spec-should-not-taint-initial-configuration-when-using-multiple-directives'
);
});
});
});

View File

@@ -134,7 +134,7 @@ graph TD
const url = 'http://localhost:9000/theme-directives.html';
cy.visit(url);
cy.get('svg');
cy.percySnapshot();
cy.matchImageSnapshot('conf-and-directives.spec-when-rendering-several-diagrams-diagram-1');
});
});
});

View File

@@ -1,20 +1,105 @@
import { imgSnapshotTest } from '../../helpers/util.js';
describe('Sequencediagram', () => {
// it('should render a simple git graph', () => {
// imgSnapshotTest(
// `
// gitGraph:
// commit
// branch newbranch
// checkout newbranch
// commit
// commit
// checkout master
// commit
// commit
// merge newbranch`,
// { logLevel: 0 }
// );
// });
describe('Git Graph diagram', () => {
it('1: should render a simple gitgraph with commit on main branch', () => {
imgSnapshotTest(
`gitGraph
commit id: "1"
commit id: "2"
commit id: "3"
`,
{}
);
});
it('2: should render a simple gitgraph with commit on main branch with Id', () => {
imgSnapshotTest(
`gitGraph
commit id: "One"
commit id: "Two"
commit id: "Three"
`,
{}
);
});
it('3: should render a simple gitgraph with different commitTypes on main branch ', () => {
imgSnapshotTest(
`gitGraph
commit id: "Normal Commit"
commit id: "Reverse Commit" type: REVERSE
commit id: "Hightlight Commit" type: HIGHLIGHT
`,
{}
);
});
it('4: should render a simple gitgraph with tags commitTypes on main branch ', () => {
imgSnapshotTest(
`gitGraph
commit id: "Normal Commit with tag" tag: "v1.0.0"
commit id: "Reverse Commit with tag" type: REVERSE tag: "RC_1"
commit id: "Hightlight Commit" type: HIGHLIGHT tag: "8.8.4"
`,
{}
);
});
it('5: should render a simple gitgraph with two branches', () => {
imgSnapshotTest(
`gitGraph
commit id: "1"
commit id: "2"
branch develop
checkout develop
commit id: "3"
commit id: "4"
checkout main
commit id: "5"
commit id: "6"
`,
{}
);
});
it('6: should render a simple gitgraph with two branches and merge commit', () => {
imgSnapshotTest(
`gitGraph
commit id: "1"
commit id: "2"
branch develop
checkout develop
commit id: "3"
commit id: "4"
checkout main
merge develop
commit id: "5"
commit id: "6"
`,
{}
);
});
it('7: should render a simple gitgraph with three branches and merge commit', () => {
imgSnapshotTest(
`gitGraph
commit id: "1"
commit id: "2"
branch nice_feature
checkout nice_feature
commit id: "3"
checkout main
commit id: "4"
checkout nice_feature
branch very_nice_feature
checkout very_nice_feature
commit id: "5"
checkout main
commit id: "6"
checkout nice_feature
commit id: "7"
checkout main
merge nice_feature
checkout very_nice_feature
commit id: "8"
checkout main
commit id: "9"
`,
{}
);
});
});

View File

@@ -552,7 +552,7 @@ context('Sequence diagram', () => {
}
);
});
it('should override config with directive settings', () => {
it('should override config with directive settings 2', () => {
imgSnapshotTest(
`
%%{init: { "config": { "mirrorActors": false, "wrap": true }}}%%

View File

@@ -158,7 +158,7 @@ describe('State diagram', () => {
);
cy.get('svg');
});
it('v2 should render a simple state diagrams', () => {
it('v2 should render a simple state diagrams 2', () => {
imgSnapshotTest(
`
stateDiagram-v2

View File

@@ -148,7 +148,7 @@ describe('State diagram', () => {
);
cy.get('svg');
});
it('should render a simple state diagrams', () => {
it('should render a simple state diagrams 2', () => {
imgSnapshotTest(
`
stateDiagram

View File

@@ -1,52 +1,52 @@
<html>
<head>
<meta charset="utf-8"/>
<!-- <meta charset="iso-8859-15"/> -->
<script src="/e2e.js"></script>
<!-- <link href="https://fonts.googleapis.com/css?family=Mansalva&display=swap" rel="stylesheet" /> -->
<link href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap" rel="stylesheet">
<style>
body {
/* font-family: 'Mansalva', cursive;*/
/* font-family: 'Mansalva', cursive; */
/* font-family: 'arial'; */
/* font-family: "trebuchet ms", verdana, arial; */
}
/* div {
font-family: 'arial';
} */
/* .mermaid-main-font {
font-family: "trebuchet ms", verdana, arial;
font-family: var(--mermaid-font-family);
} */
/* :root {
--mermaid-font-family: '"trebuchet ms", verdana, arial';
--mermaid-font-family: "Comic Sans MS", "Comic Sans", cursive;
--mermaid-font-family: '"Lucida Console", Monaco, monospace';
} */
svg {
border: 2px solid darkred;
}
.exClass2 > rect, .exClass {
fill: greenyellow !important;
}
</style>
</head>
<body>
<script src="./mermaid.js"></script>
<script>
// Notice startOnLoad=false
// This prevents default handling in mermaid from render before the e2e logic is applied
// mermaid.initialize({
// startOnLoad: false,
// useMaxWidth: true,
// // "themeCSS": ":root { --mermaid-font-family: \"trebuchet ms\", verdana, arial;}",
// // fontFamily: '\"trebuchet ms\", verdana, arial;'
// // fontFamily: '"Comic Sans MS", "Comic Sans", cursive'
// // fontFamily: '"Mansalva", cursive',
// // fontFamily: '"Noto Sans SC", sans-serif'
// fontFamily: '"Noto Sans SC", sans-serif'
// });
</script>
</body>
</html>
<html>
<head>
<meta charset="utf-8"/>
<!-- <meta charset="iso-8859-15"/> -->
<script src="/e2e.js"></script>
<!-- <link href="https://fonts.googleapis.com/css?family=Mansalva&display=swap" rel="stylesheet" /> -->
<link href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap" rel="stylesheet">
<style>
body {
/* font-family: 'Mansalva', cursive;*/
/* font-family: 'Mansalva', cursive; */
/* font-family: 'arial'; */
/* font-family: "trebuchet ms", verdana, arial; */
}
/* div {
font-family: 'arial';
} */
/* .mermaid-main-font {
font-family: "trebuchet ms", verdana, arial;
font-family: var(--mermaid-font-family);
} */
/* :root {
--mermaid-font-family: '"trebuchet ms", verdana, arial';
--mermaid-font-family: "Comic Sans MS", "Comic Sans", cursive;
--mermaid-font-family: '"Lucida Console", Monaco, monospace';
} */
svg {
border: 2px solid darkred;
}
.exClass2 > rect, .exClass {
fill: greenyellow !important;
}
</style>
</head>
<body>
<script src="./mermaid.js"></script>
<script>
// Notice startOnLoad=false
// This prevents default handling in mermaid from render before the e2e logic is applied
// mermaid.initialize({
// startOnLoad: false,
// useMaxWidth: true,
// // "themeCSS": ":root { --mermaid-font-family: \"trebuchet ms\", verdana, arial;}",
// // fontFamily: '\"trebuchet ms\", verdana, arial;'
// // fontFamily: '"Comic Sans MS", "Comic Sans", cursive'
// // fontFamily: '"Mansalva", cursive',
// // fontFamily: '"Noto Sans SC", sans-serif'
// fontFamily: '"Noto Sans SC", sans-serif'
// });
</script>
</body>
</html>

View File

@@ -1,46 +1,46 @@
<html>
<head>
<link
href="https://fonts.googleapis.com/css?family=Montserrat&display=swap"
rel="stylesheet"
/>
<style>body {
font-family: 'trebuchet ms', verdana, arial;
}</style>
</head>
<body>
<div class="mermaid">
graph TB
subgraph One
a1-->a2-->a3
end
</div>
<div class="mermaid">
graph TB
a_a --> b_b:::apa --> c_c:::apa
classDef apa fill:#f9f,stroke:#333,stroke-width:4px;
class a_a apa;
</div>
<div class="mermaid">
graph TB
a_a(Aftonbladet) --> b_b[gorilla]:::apa --> c_c{chimp}:::apa -->a_a
a_a --> c --> d_d --> c_c
classDef apa fill:#f9f,stroke:#333,stroke-width:4px;
class a_a apa;
click a_a "http://www.aftonbladet.se" "apa"
</div>
<script src="./mermaid.js"></script>
<script>
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>
</script>
</body>
</html>
<html>
<head>
<link
href="https://fonts.googleapis.com/css?family=Montserrat&display=swap"
rel="stylesheet"
/>
<style>body {
font-family: 'trebuchet ms', verdana, arial;
}</style>
</head>
<body>
<div class="mermaid">
graph TB
subgraph One
a1-->a2-->a3
end
</div>
<div class="mermaid">
graph TB
a_a --> b_b:::apa --> c_c:::apa
classDef apa fill:#f9f,stroke:#333,stroke-width:4px;
class a_a apa;
</div>
<div class="mermaid">
graph TB
a_a(Aftonbladet) --> b_b[gorilla]:::apa --> c_c{chimp}:::apa -->a_a
a_a --> c --> d_d --> c_c
classDef apa fill:#f9f,stroke:#333,stroke-width:4px;
class a_a apa;
click a_a "http://www.aftonbladet.se" "apa"
</div>
<script src="./mermaid.js"></script>
<script>
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>
</script>
</body>
</html>

View File

@@ -0,0 +1,67 @@
<html>
<head>
<link
href="https://fonts.googleapis.com/css?family=Montserrat&display=swap"
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';
}
h1 { color: white;}
.mermaid2 {
display: none;
}
.customCss > rect, .customCss{
fill:#FF0000 !important;
stroke:#FFFF00 !important;
stroke-width:4px !important;
}
</style>
</head>
<body>
<h1>info below</h1>
<div class="mermaid" style="width: 100%; height: 20%;">
gitGraph
class BankAccount{
+String owner
+BigDecimal balance
+deposit(amount) bool
+withdrawl(amount) int
}
cssClass "BankAccount" customCss
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.parseError = function (err, hash) {
// console.error('Mermaid error: ', err);
};
mermaid.initialize({
theme: 'default',
// arrowMarkerAbsolute: true,
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
logLevel: 0,
flowchart: { curve: 'linear', htmlLabels: true },
// gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorMargin: 50, showSequenceNumbers: true },
// sequenceDiagram: { actorMargin: 300 } // deprecated
// fontFamily: '"arial", sans-serif',
// themeVariables: {
// fontFamily: '"arial", sans-serif',
// },
curve: 'linear',
securityLevel: 'loose',
});
function callback() {
alert('It worked');
}
</script>
</body>
</html>

View File

@@ -0,0 +1,138 @@
<html>
<head>
<link
href="https://fonts.googleapis.com/css?family=Montserrat&display=swap"
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:#111;
/* background:#333; */
font-family: 'Arial';
}
/* h1 { color: white;} */
.mermaid2 {
display: none;
}
.customCss > rect, .customCss{
fill:#FF0000 !important;
stroke:#FFFF00 !important;
stroke-width:4px !important;
}
</style>
</head>
<body>
<h1>info below</h1>
<div class="mermaid2" style="width: 100%; height: 20%;">
%%{init: { 'logLevel': 'debug', 'theme': 'neutral' } }%%
gitGraph
commit "Ashish"
branch newbranch
checkout newbranch
commit id:"1111"
commit tag:"test"
checkout main
commit type: HIGHLIGHT
commit
merge newbranch
commit
branch b2
commit
</div>
<div class="mermaid" style="width: 100%; height: 20%;">
gitGraph
commit type:HIGHLIGHT
branch hotfix
checkout hotfix
commit type:HIGHLIGHT
branch develop
checkout develop
commit id:"ash" tag:"abc" type:HIGHLIGHT
branch featureB
checkout featureB
commit type:HIGHLIGHT
checkout main
checkout hotfix
commit type:HIGHLIGHT
checkout develop
commit type:REVERSE
checkout featureB
commit type:HIGHLIGHT
checkout main
merge hotfix
checkout featureB
commit type:HIGHLIGHT
checkout develop
branch featureA
commit type:HIGHLIGHT
checkout develop
checkout featureA
commit
checkout featureB
commit
checkout develop
merge featureA
branch release
checkout release
commit type:HIGHLIGHT
checkout main
commit
checkout release
merge main
checkout develop
merge release
</div>
<div class="mermaid2" style="width: 100%; height: 20%;">
gitGraph:
commit
commit
branch newbranch
commit
merge main
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.parseError = function (err, hash) {
// console.error('Mermaid error: ', err);
};
mermaid.initialize({
theme: 'dark',
// themeVariables: {
// primaryColor: '#9400D3',
// darkMode: true,
// background: '#222',
// // textColor: 'white',
// // primaryTextColor: '#f4f4f4',
// // // nodeBkg: '#ff0000',
// // // mainBkg: '#0000ff',
// // // tertiaryColor: '#ffffcc',
// },
// theme: 'forest',
// theme: 'neutral',
// theme: 'dark',
// arrowMarkerAbsolute: true,
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
logLevel: 1,
flowchart: { curve: 'linear', htmlLabels: true },
// gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorMargin: 50, showSequenceNumbers: true },
// sequenceDiagram: { actorMargin: 300 } // deprecated
// fontFamily: '"arial", sans-serif',
// themeVariables: {
// fontFamily: '"arial", sans-serif',
// },
curve: 'linear',
securityLevel: 'loose',
});
function callback() {
alert('It worked');
}
</script>
</body>
</html>

View File

@@ -0,0 +1,137 @@
<html>
<head>
<link
href="https://fonts.googleapis.com/css?family=Montserrat&display=swap"
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:#111;
/* background:#333; */
font-family: 'Arial';
}
/* h1 { color: white;} */
.mermaid2 {
display: none;
}
.customCss > rect, .customCss{
fill:#FF0000 !important;
stroke:#FFFF00 !important;
stroke-width:4px !important;
}
</style>
</head>
<body>
<h1>info below</h1>
<div class="mermaid2" style="width: 100%; height: 20%;">
gitGraph:
commit "Ashish"
branch newbranch
checkout newbranch
commit id:"1111"
commit tag:"test"
checkout main
commit type: HIGHLIGHT
commit
merge newbranch
commit
branch b2
commit
</div>
<div class="mermaid" style="width: 100%; height: 20%;">
gitGraph
commit
branch hotfix
checkout hotfix
commit
branch develop
checkout develop
commit id:"An id" tag:"A tag"
branch featureB
checkout featureB
commit type:HIGHLIGHT
checkout main
checkout hotfix
commit type:NORMAL
checkout develop
commit type:REVERSE
checkout featureB
commit
checkout main
merge hotfix
checkout featureB
commit
checkout develop
branch featureA
commit
checkout develop
merge hotfix
checkout featureA
commit
checkout featureB
commit
checkout develop
merge featureA
branch release
checkout release
commit
checkout main
commit
checkout release
merge main
checkout develop
merge release
</div>
<div class="mermaid2" style="width: 100%; height: 20%;">
gitGraph:
commit
commit
branch newbranch
commit
merge main
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.parseError = function (err, hash) {
// console.error('Mermaid error: ', err);
};
mermaid.initialize({
theme: 'dark',
themeVariables: {
// primaryColor: '#9400D3',
// darkMode: false,
// background: '#222',
// textColor: 'white',
// primaryTextColor: '#f4f4f4',
// nodeBkg: '#ff0000',
// mainBkg: '#0000ff',
// tertiaryColor: '#ffffcc',
},
// theme: 'forest',
// theme: 'neutral',
// theme: 'dark',
// arrowMarkerAbsolute: true,
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
logLevel: 1,
flowchart: { curve: 'linear', htmlLabels: true },
// gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorMargin: 50, showSequenceNumbers: true },
// sequenceDiagram: { actorMargin: 300 } // deprecated
// fontFamily: '"arial", sans-serif',
// themeVariables: {
// fontFamily: '"arial", sans-serif',
// },
curve: 'linear',
securityLevel: 'loose',
});
function callback() {
alert('It worked');
}
</script>
</body>
</html>

View File

@@ -1,26 +1,26 @@
<html>
<head>
<link
href="https://fonts.googleapis.com/css?family=Montserrat&display=swap"
rel="stylesheet"
/>
</head>
<body>
<h1>info below</h1>
<div class="mermaid">info</div>
<script src="./mermaid.js"></script>
<script>
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>
</script>
</body>
</html>
<html>
<head>
<link
href="https://fonts.googleapis.com/css?family=Montserrat&display=swap"
rel="stylesheet"
/>
</head>
<body>
<h1>info below</h1>
<div class="mermaid">info</div>
<script src="./mermaid.js"></script>
<script>
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>
</script>
</body>
</html>

View File

@@ -66,6 +66,7 @@ merge newbranch
</div>
<div class="mermaid" style="width: 50%;">
sequenceDiagram
title: with colon:
participant a as Alice
participant j as John
note right of a: Hello world!

View File

@@ -264,6 +264,50 @@ requirementDiagram
test_req - contains -> test_req3
test_req <- copies - test_entity2
</div>
<div class="mermaid" style="width: 100%; height: 20%;">
gitGraph:
commit
branch hotfix
checkout hotfix
commit
branch develop
checkout develop
commit id:"An id" tag:"A tag"
branch featureB
checkout featureB
commit type:HIGHLIGHT
checkout main
checkout hotfix
commit type:NORMAL
checkout develop
commit type:REVERSE
checkout featureB
commit
checkout main
merge hotfix
checkout featureB
commit
checkout develop
branch featureA
commit
checkout develop
merge hotfix
checkout featureA
commit
checkout featureB
commit
checkout develop
merge featureA
branch release
checkout release
commit
checkout main
commit
checkout release
merge main
checkout develop
merge release
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.parseError = function (err, hash) {

View File

@@ -258,8 +258,51 @@ requirementDiagram
test_req - contains -> test_req3
test_req <- copies - test_entity2
</div>
<script src="./mermaid.js"></script>
<div class="mermaid" class="width height">
gitGraph
commit
branch hotfix
checkout hotfix
commit
branch develop
checkout develop
commit id:"An id" tag:"A tag"
branch featureB
checkout featureB
commit type:HIGHLIGHT
checkout main
checkout hotfix
commit type:NORMAL
checkout develop
commit type:REVERSE
checkout featureB
commit
checkout main
merge hotfix
checkout featureB
commit
checkout develop
branch featureA
commit
checkout develop
merge hotfix
checkout featureA
commit
checkout featureB
commit
checkout develop
merge featureA
branch release
checkout release
commit
checkout main
commit
checkout release
merge main
checkout develop
merge release
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.parseError = function (err, hash) {
// console.error('Mermaid error: ', err);
@@ -267,15 +310,15 @@ requirementDiagram
mermaid.initialize({
theme: 'base',
themeVariables: {
primaryColor: '#9400D3',
darkMode: true,
background: '#222',
textColor: 'white',
primaryTextColor: '#f4f4f4',
nodeBkg: '#ff0000',
mainBkg: '#0000ff',
tertiaryColor: '#ffffcc',
},
primaryColor: '#9400D3',
darkMode: true,
background: '#222',
textColor: 'white',
primaryTextColor: '#f4f4f4',
nodeBkg: '#ff0000',
mainBkg: '#0000ff',
tertiaryColor: '#ffffcc',
},
// arrowMarkerAbsolute: true,
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
logLevel: 0,

View File

@@ -256,6 +256,50 @@ requirementDiagram
test_req - contains -> test_req3
test_req <- copies - test_entity2
</div>
<div class="mermaid" class="width height">
gitGraph
commit
branch hotfix
checkout hotfix
commit
branch develop
checkout develop
commit id:"An id" tag:"A tag"
branch featureB
checkout featureB
commit type:HIGHLIGHT
checkout main
checkout hotfix
commit type:NORMAL
checkout develop
commit type:REVERSE
checkout featureB
commit
checkout main
merge hotfix
checkout featureB
commit
checkout develop
branch featureA
commit
checkout develop
merge hotfix
checkout featureA
commit
checkout featureB
commit
checkout develop
merge featureA
branch release
checkout release
commit
checkout main
commit
checkout release
merge main
checkout develop
merge release
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.parseError = function (err, hash) {

View File

@@ -251,7 +251,51 @@ requirementDiagram
test_req - contains -> test_req3
test_req <- copies - test_entity2
</div>
<script src="./mermaid.js"></script>
<div class="mermaid" style="width: 100%; height: 20%;">
gitGraph
commit
branch hotfix
checkout hotfix
commit
branch develop
checkout develop
commit id:"An id" tag:"A tag"
branch featureB
checkout featureB
commit type:HIGHLIGHT
checkout main
checkout hotfix
commit type:NORMAL
checkout develop
commit type:REVERSE
checkout featureB
commit
checkout main
merge hotfix
checkout featureB
commit
checkout develop
branch featureA
commit
checkout develop
merge hotfix
checkout featureA
commit
checkout featureB
commit
checkout develop
merge featureA
branch release
checkout release
commit
checkout main
commit
checkout release
merge main
checkout develop
merge release
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.parseError = function (err, hash) {
// console.error('Mermaid error: ', err);

View File

@@ -255,6 +255,50 @@ requirementDiagram
test_req - contains -> test_req3
test_req <- copies - test_entity2
</div>
<div class="mermaid" class="width height">
gitGraph:
commit
branch hotfix
checkout hotfix
commit
branch develop
checkout develop
commit id:"An id" tag:"A tag"
branch featureB
checkout featureB
commit type:HIGHLIGHT
checkout main
checkout hotfix
commit type:NORMAL
checkout develop
commit type:REVERSE
checkout featureB
commit
checkout main
merge hotfix
checkout featureB
commit
checkout develop
branch featureA
commit
checkout develop
merge hotfix
checkout featureA
commit
checkout featureB
commit
checkout develop
merge featureA
branch release
checkout release
commit
checkout main
commit
checkout release
merge main
checkout develop
merge release
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.parseError = function (err, hash) {

View File

@@ -254,6 +254,52 @@ requirementDiagram
test_req - contains -> test_req3
test_req <- copies - test_entity2
</div>
<div class="mermaid" class="width height">
gitGraph:
commit
branch hotfix
checkout hotfix
commit
branch develop
checkout develop
commit id:"An id" tag:"A tag"
branch featureB
checkout featureB
commit type:HIGHLIGHT
checkout main
checkout hotfix
commit type:NORMAL
checkout develop
commit type:REVERSE
checkout featureB
commit
checkout main
merge hotfix
checkout featureB
commit
checkout develop
branch featureA
commit
checkout develop
merge hotfix
checkout featureA
commit
checkout featureB
commit
checkout develop
merge featureA
branch release
checkout release
commit
checkout main
commit
checkout release
merge main
checkout develop
merge release
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.parseError = function (err, hash) {

View File

@@ -1,41 +1,41 @@
<html>
<head>
<link
href="https://fonts.googleapis.com/css?family=Montserrat&display=swap"
rel="stylesheet"
/>
</head>
<body>
<h1>User Journey</h1>
<div class="mermaid">
journey
title Go shopping
section Get to the shops
Get car keys:5: Dad
Get into car:5: Dad, Mum, Child 1, Child 2
Really drive to supermarket:3: Dad
section Do shopping
Do actual shop:3: Mum
Get in the way:2: Dad, Child 1, Child 2
Pay: 2: Dad
section Go home
Lose keys:3: Dad
Get cross:1: Dad, Child 1
Find keys:4: Mum
Get into car:4: Dad, Mum, Child 1, Child 2
Drive home:3: Dad
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.initialize({
theme: 'forest',
logLevel: 3,
journey: { taskMargin: 30 },
});
</script>
</body>
</html>
<html>
<head>
<link
href="https://fonts.googleapis.com/css?family=Montserrat&display=swap"
rel="stylesheet"
/>
</head>
<body>
<h1>User Journey</h1>
<div class="mermaid">
journey
title Go shopping
section Get to the shops
Get car keys:5: Dad
Get into car:5: Dad, Mum, Child 1, Child 2
Really drive to supermarket:3: Dad
section Do shopping
Do actual shop:3: Mum
Get in the way:2: Dad, Child 1, Child 2
Pay: 2: Dad
section Go home
Lose keys:3: Dad
Get cross:1: Dad, Child 1
Find keys:4: Mum
Get into car:4: Dad, Mum, Child 1, Child 2
Drive home:3: Dad
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.initialize({
theme: 'forest',
logLevel: 3,
journey: { taskMargin: 30 },
});
</script>
</body>
</html>

View File

@@ -1,18 +1,18 @@
<!doctype html>
<html>
<head>
<style>
/* .mermaid {
font-family: "trebuchet ms", verdana, arial;;
} */
/* .mermaid {
font-family: 'arial';
} */
</style>
</head>
<body>
<div id="graph-to-be"></div>
<script src="./bundle-test.js" charset="utf-8"></script>
</body>
<!doctype html>
<html>
<head>
<style>
/* .mermaid {
font-family: "trebuchet ms", verdana, arial;;
} */
/* .mermaid {
font-family: 'arial';
} */
</style>
</head>
<body>
<div id="graph-to-be"></div>
<script src="./bundle-test.js" charset="utf-8"></script>
</body>
</html>

View File

@@ -16,7 +16,8 @@
// // `config` is the resolved Cypress config
// }
const { addMatchImageSnapshotPlugin } = require('cypress-image-snapshot/plugin');
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
addMatchImageSnapshotPlugin(on, config);
};

View File

@@ -24,4 +24,8 @@
// -- This is will overwrite an existing command --
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
import '@percy/cypress';
// import '@percy/cypress';
import { addMatchImageSnapshotCommand } from 'cypress-image-snapshot/command';
addMatchImageSnapshotCommand();

View File

@@ -15,7 +15,7 @@
// Import commands.js using ES2015 syntax:
import './commands';
import '@percy/cypress';
// import '@percy/cypress';
// Alternatively you can use CommonJS syntax:
// require('./commands')

45
demos/er.html Normal file
View File

@@ -0,0 +1,45 @@
<!DOCTYPE html>
<html>
<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>
<div class="mermaid">
erDiagram
title This is a title
accDescription Test a description
CUSTOMER ||--o{ ORDER : places
ORDER ||--|{ LINE-ITEM : contains
CUSTOMER }|..|{ DELIVERY-ADDRESS : uses
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.initialize({
theme: 'forest',
// themeCSS: '.node rect { fill: red; }',
logLevel: 3,
securityLevel: 'loose',
flowchart: { curve: 'basis' },
gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorMargin: 50 },
// sequenceDiagram: { actorMargin: 300 } // deprecated
});
</script>
</body>
</html>

View File

@@ -230,6 +230,8 @@
<h3>flowchart</h3>
<div class="mermaid">
flowchart TD
title Christmas
accDescription Get money
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me thinksssssx<br/>sssssssssssssssssssuuu<br />tttsssssssssssssssssssssss}
C -->|One| D[Laptop]

View File

@@ -37,7 +37,7 @@
axisFormat %m-%d %a
excludes weekends, 2021-10-01,2021-10-04,2021-10-05,2021-10-06,2021-10-07
includes 2021-10-09
section Airworks 3.4.1
开发 :b, 2021-10-07, 5d
测试 :after b, 4d
@@ -467,6 +467,7 @@
<div class="mermaid">
sequenceDiagram
accDescription Hello friends
participant Alice
participant Bob
participant John as John<br />Second Line
@@ -619,7 +620,7 @@
<div class="mermaid">
classDiagram
Class01 <|-- AveryLongClass : Cool
Class01 <|-- AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01
Class03 "0" *-- "0..n" Class04
@@ -656,7 +657,7 @@
<div class="mermaid">
classDiagram
Class01~T~ <|-- AveryLongClass : Cool
Class01~T~ <|-- AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01
Class03~T~ "0" *-- "0..n" Class04
Class05 "1" o-- "many" Class06
@@ -786,6 +787,43 @@
<script src="./mermaid.js"></script>
<script>
const ALLOWED_TAGS = [
'a',
'b',
'blockquote',
'br',
'dd',
'div',
'dl',
'dt',
'em',
'foreignObject',
'h1',
'h2',
'h3',
'h4',
'h5',
'h6',
'h7',
'h8',
'hr',
'i',
'li',
'ul',
'ol',
'p',
'pre',
'span',
'strike',
'strong',
'table',
'tbody',
'td',
'tfoot',
'th',
'thead',
'tr',
];
mermaid.initialize({
theme: 'forest',
// themeCSS: '.node rect { fill: red; }',
@@ -794,6 +832,13 @@
flowchart: { curve: 'basis' },
gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorMargin: 50 },
dompurifyConfig: {
USE_PROFILES: {
svg: true,
},
ADD_TAGS: ALLOWED_TAGS,
ADD_ATTR: ['transform-origin'],
},
// sequenceDiagram: { actorMargin: 300 } // deprecated
});
</script>

72
demos/sequence.html Normal file
View File

@@ -0,0 +1,72 @@
<!DOCTYPE html>
<html>
<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>
<div class="mermaid">
sequenceDiagram
title: FancySequenceDiagram
accDescription Test a description
participant Alice
participant Bob
participant John as John<br />Second Line
rect rgb(200, 220, 100)
rect rgb(200, 255, 200)
Alice ->> Bob: Hello Bob, how are you?
Bob-->>John: How about you John?
end
Bob--x Alice: I am good thanks!
Bob-x John: I am good thanks!
Note right of John: John thinks a long<br />long time, so long<br />that the text does<br />not fit on a row.
Bob-->Alice: Checking with John...
Note over John:wrap: John looks like he's still thinking, so Bob prods him a bit.
Bob-x John: Hey John - we're still waiting to know<br />how you're doing
Note over John:nowrap: John's trying hard not to break his train of thought.
Bob-x John:wrap: John! Are you still debating about how you're doing? How long does it take??
Note over John: After a few more moments, John<br />finally snaps out of it.
end
alt either this
Alice->>John: Yes
else or this
Alice->>John: No
else or this will happen
Alice->John: Maybe
end
par this happens in parallel
Alice -->> Bob: Parallel message 1
and
Alice -->> John: Parallel message 2
end
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.initialize({
theme: 'forest',
// themeCSS: '.node rect { fill: red; }',
logLevel: 3,
securityLevel: 'loose',
flowchart: { curve: 'basis' },
gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorMargin: 50 },
// sequenceDiagram: { actorMargin: 300 } // deprecated
});
</script>
</body>
</html>

31512
dist/mermaid.core.js vendored Normal file

File diff suppressed because one or more lines are too long

1
dist/mermaid.core.js.map vendored Normal file

File diff suppressed because one or more lines are too long

129228
dist/mermaid.js vendored Normal file

File diff suppressed because one or more lines are too long

1
dist/mermaid.js.map vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -11,7 +11,7 @@ It is a Javascript based diagramming and charting tool that renders Markdown-ins
<!-- **Edit this Page** [![N|Solid](img/GitHub-Mark-32px.png)](https://github.com/mermaid-js/mermaid/blob/develop/docs/README.md) -->
[![Build Status](https://travis-ci.org/mermaid-js/mermaid.svg?branch=master)](https://travis-ci.org/mermaid-js/mermaid) [![NPM](https://img.shields.io/npm/v/mermaid)](https://www.npmjs.com/package/mermaid) [![Coverage Status](https://coveralls.io/repos/github/mermaid-js/mermaid/badge.svg?branch=master)](https://coveralls.io/github/mermaid-js/mermaid?branch=master) [![Join our Slack!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=slack&label=slack)](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE) [![This project is using Percy.io for visual regression testing.](https://percy.io/static/images/percy-badge.svg)](https://percy.io/Mermaid/mermaid)
[![Build Status](https://travis-ci.org/mermaid-js/mermaid.svg?branch=master)](https://travis-ci.org/mermaid-js/mermaid) [![NPM](https://img.shields.io/npm/v/mermaid)](https://www.npmjs.com/package/mermaid) [![Coverage Status](https://coveralls.io/repos/github/mermaid-js/mermaid/badge.svg?branch=master)](https://coveralls.io/github/mermaid-js/mermaid?branch=master) [![Join our Slack!](https://img.shields.io/static/v1?message=join%20chat&color=9cf&logo=slack&label=slack)](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE)
<!-- Mermaidn book banner -->
[![banner](img/book-banner-post-release.jpg)](https://mermaid-js.github.io/mermaid/landing/)

View File

@@ -926,7 +926,7 @@ Default value: true
**Notes:** Sets the siteConfig. The siteConfig is a protected configuration for repeat use. Calls
to reset() will reset the currentConfig to siteConfig. Calls to reset(configApi.defaultConfig)
will reset siteConfig and currentConfig to the defaultConfig Note: currentConfig is set in this
function \*Default value: At default, will mirror Global Config\*\*
function _Default value: At default, will mirror Global Config_
### Parameters
@@ -1073,16 +1073,61 @@ To be removed
```html
<script>
var config = { theme: 'default', logLevel: 'fatal', securityLevel: 'strict', startOnLoad: true,
arrowMarkerAbsolute: false, er: { diagramPadding: 20, layoutDirection: 'TB', minEntityWidth: 100,
minEntityHeight: 75, entityPadding: 15, stroke: 'gray', fill: 'honeydew', fontSize: 12, useMaxWidth:
true, }, flowchart: { diagramPadding: 8, htmlLabels: true, curve: 'basis', }, sequence: {
diagramMarginX: 50, diagramMarginY: 10, actorMargin: 50, width: 150, height: 65, boxMargin: 10,
boxTextMargin: 5, noteMargin: 10, messageMargin: 35, messageAlign: 'center', mirrorActors: true,
bottomMarginAdj: 1, useMaxWidth: true, rightAngles: false, showSequenceNumbers: false, }, gantt: {
titleTopMargin: 25, barHeight: 20, barGap: 4, topPadding: 50, leftPadding: 75, gridLineStartPadding:
35, fontSize: 11, fontFamily: '"Open Sans", sans-serif', numberSectionStyles: 4, axisFormat:
'%Y-%m-%d', topAxis: false, }, }; mermaid.initialize(config);
var config = {
theme: 'default',
logLevel: 'fatal',
securityLevel: 'strict',
startOnLoad: true,
arrowMarkerAbsolute: false,
er: {
diagramPadding: 20,
layoutDirection: 'TB',
minEntityWidth: 100,
minEntityHeight: 75,
entityPadding: 15,
stroke: 'gray',
fill: 'honeydew',
fontSize: 12,
useMaxWidth: true,
},
flowchart: {
diagramPadding: 8,
htmlLabels: true,
curve: 'basis',
},
sequence: {
diagramMarginX: 50,
diagramMarginY: 10,
actorMargin: 50,
width: 150,
height: 65,
boxMargin: 10,
boxTextMargin: 5,
noteMargin: 10,
messageMargin: 35,
messageAlign: 'center',
mirrorActors: true,
bottomMarginAdj: 1,
useMaxWidth: true,
rightAngles: false,
showSequenceNumbers: false,
},
gantt: {
titleTopMargin: 25,
barHeight: 20,
barGap: 4,
topPadding: 50,
leftPadding: 75,
gridLineStartPadding: 35,
fontSize: 11,
fontFamily: '"Open Sans", sans-serif',
numberSectionStyles: 4,
axisFormat: '%Y-%m-%d',
topAxis: false,
},
};
mermaid.initialize(config);
</script>
```

View File

@@ -4,7 +4,7 @@ When mermaid starts configuration is extracted to a configuration to be used for
* The default configuration
* Overrides on the site level, set is set by the initialize call and will be applied for all diagrams in the site/app. The term for this is the **siteConfig**.
* Directives - diagram authors can update select configuration parameters directly int he diagram code via directives and these are applied to the render config.
* Directives - diagram authors can update select configuration parameters directly in the diagram code via directives and these are applied to the render config.
**The render config** is configuration that is used when rendering by applying these configurations.
@@ -27,4 +27,4 @@ Initialize call is called **only once**. It is called by the site integrator in
This method resets the configuration for a diagram to the site configuration, the configuration provided by the site integrator. Before each rendering of a diagram reset is called in the very beginning of render.
##
##

View File

@@ -105,3 +105,54 @@ sequenceDiagram
John->>Bob: How about you?
Bob-->>John: Jolly good!
```
## Sequence Diagram: Blogging app service communication
```mermaid-example
sequenceDiagram
participant web as Web Browser
participant blog as Blog Service
participant account as Account Service
participant mail as Mail Service
participant db as Storage
Note over web,db: The user must be logged in to submit blog posts
web->>+account: Logs in using credentials
account->>db: Query stored accounts
db->>account: Respond with query result
alt Credentials not found
account->>web: Invalid credentials
else Credentials found
account->>-web: Successfully logged in
Note over web,db: When the user is authenticated, they can now submit new posts
web->>+blog: Submit new post
blog->>db: Store post data
par Notifications
blog--)mail: Send mail to blog subscribers
blog--)db: Store in-site notifications
and Response
blog-->>-web: Successfully posted
end
end
```
A commit flow diagram.
```mermaid
gitGraph:
commit "Ashish"
branch newbranch
checkout newbranch
commit id:"1111"
commit tag:"test"
checkout main
commit type: HIGHLIGHT
commit
merge newbranch
commit
branch b2
commit
```

437
docs/gitgraph.md Normal file
View File

@@ -0,0 +1,437 @@
# Gitgraph Diagrams
**Edit this Page** [![N|Solid](img/GitHub-Mark-32px.png)](https://github.com/mermaid-js/mermaid/blob/develop/docs/gitgraph.md)
> A Git Graph is a pictorial representation of git commits and git actions(commands) on various branches.
These kind of diagram are particularyly helpful to developers and devops teams to share their Git branching strategies. For example, it makes it easier to visualize how git flow works.
Mermaid can render Git diagrams
```mermaid-example
gitGraph
commit
commit
branch develop
checkout develop
commit
commit
checkout main
merge develop
commit
commit
```
In Mermaid, we support the basic git operations like:
- *commit* : Representing a new commit on the current branch.
- *branch* : To create & switch to a new branch, setting it as the current branch.
- *checkout* : To checking out an existing branch and setting it as the current branch.
- *merge* : To merge an existing branch onto the current branch.
With the help of these key git commands, you will be able to draw a gitgraph in Mermaid very easily and quickly.
Entity names are often capitalised, although there is no accepted standard on this, and it is not required in Mermaid.
## Syntax
Mermaid syntax for Gitgraph is very straigth-forward and simple. It follows a declarative-approach, where each commit is drawn on the timeline in the diagram, in order of its occurance/presence in code. Basically, it follows the insertion order for each command.
First thing you do is to declare your diagram type using the **gitgraph** keyword. This `gitgraph` keyword, tells Mermaid that you wish to draw a gitgraph, and parse the diagram code accordingly.
Each gitgraph, is initialized with ***main*** branch. So unless you create a different branch, by-default the commits will go to the main branch. This is driven with how git works, where in the begging you always start with the main branch (formerly called as ***master*** branch). And by-default, `main` branch is set as your ***current branch***.
You make use of ***commit*** keyword to register a commit on the current branch. Let see how this works:
A simple gitgraph showing three commits on the default (***main***) branch:
```mermaid-example
gitGraph
commit
commit
commit
```
If you look closely at the previous example, you can see the default branch `main` along with three commits. Also, notice, the by-default each commit has been given a unique & random Id. What if you would want to give your own custom ID to a commit? Yes, it is possible to do that with Mermaid.
### Adding custom commit id
For a given commit you may specify a custom id at the time of declaring it using the `id` attribute, followed by `:` and your custom value within `""` quote. For example: `commit id: "your_custom_id"`
Let us see how this works with the help of the following diagram:
```mermaid-example
gitGraph
commit id: "Alpha"
commit id: "Beta"
commit id: "Gamma"
```
In this example, we have given our custom id's to the commits.
### Modifying commit type
In Mermaid, a commit can be of three type, which render a bit different in the diagram. These types are:
- `NORMAL` : Default commit type. Represented by a solid circle in the diagram
- `REVERSE` : To emphasize a commit as a reverse commit. Represented by a crossed solid circle in the diagram.
- `HIGHLIGHT` : To highlight a particular commit in the diagram. Represented by a filled rectangle in the diagram.
For a given commit you may specify its type at the time of declaring it using the `type` attribute, followed by `:` and the required type option discussed above. For example: `commit type: HIGHLIGHT`
NOTE: If no commit type is specified, `NORMAL` is picked as default.
Let us see how these different commit type look with the help of the following diagram:
```mermaid-example
gitGraph
commit id: "Normal"
commit
commit id: "Reverse" type: REVERSE
commit
commit id: "Hightlight" type: HIGHLIGHT
commit
```
In this example, we have specified different types to each commit. Also, see how we have clubbed both `id` and `type` together at the time of declaring our commits.
### Adding Tags
For a given commit you may decorate it as a **tag**, similar to the concept of tags or release version in git world.
You can attach a custom tag at the time of declaring a commit using the `tag` attribute, followed by `:` and your custom value within `""` quote. For example: `commit tag: "your_custom_tag"`
Let us see how this works with the help of the following diagram:
```mermaid-example
gitGraph
commit
commit id: "Normal" tag: "v1.0.0"
commit
commit id: "Reverse" type: REVERSE tag: "RC_1"
commit
commit id: "Hightlight" type: HIGHLIGHT tag: "8.8.4"
commit
```
In this example, we have given custom tags to the commits. Also, see how we have combined all these attributes in a single commit declaration. You can mix-match these attributes as you like.
### Create a new branch
In Mermaid, in-order to create a new branch, you make use of the `branch` keyword. You also need to provide a name of the new branch. The name has to be unique and cannot be that of an existing branch. Usage example: `branch develop`
When Mermaid, reads the `branch` keyword, it creates a new branch and sets it as the current branch. Equivalent to you creating a new branch and checking it out in Git world.
Let see this in an example:
```mermaid-example
gitGraph
commit
commit
branch develop
commit
commit
commit
```
In this example, see how we started with default `main` branch, and pushed to commits on that.
Then we created the `develop` branch, and all commits afterwards are put on the `develop` branch as it became the current branch.
### Checking out an existing branch
In Mermaid, in-order to switch to an existing branch, you make use of the `checkout` keyword. You also need to provide a name of an existing branch. If no branch is found with the given name, it will result in console error. Usage example: `checkout develop`
When Mermaid, reads the `checkout` keyword, it finds the given branch and sets it as the current branch. Equivalent to checking out a branch in Git world.
Let see modify our previous example:
```mermaid-example
gitGraph
commit
commit
branch develop
commit
commit
commit
checkout main
commit
commit
```
In this example, see how we started with default `main` branch, and pushed to commits on that.
Then we created the `develop` branch, and all three commits afterwards are put on the `develop` branch as it became the current branch.
After this we made use of the `checkout` keyword to set the current branch as `main`, and all commit that follow are registered against the current branch, i.e. `main`.
### Merging two branches
In Mermaid, in-order to merge or join to an existing branch, you make use of the `merge` keyword. You also need to provide a name of an existing branch to merge from. If no branch is found with the given name, it will result in console error. Also, if you can only merge two separate branches, and cannot merge a branch with itself. In such case an error is throw.
Usage example: `merge develop`
When Mermaid, reads the `merge` keyword, it finds the given branch and its head commit (the last commit on that branch), and joins it with the head commit on the **current branch**. Each merge result in a ***merge commit***, represented in the diagram with **filled double circle**.
Let see modify our previous example to merge our two branches:
```mermaid-example
gitGraph
commit
commit
branch develop
commit
commit
commit
checkout main
commit
commit
merge develop
commit
commit
```
In this example, see how we started with default `main` branch, and pushed to commits on that.
Then we created the `develop` branch, and all three commits afterwards are put on the `develop` branch as it became the current branch.
After this we made use of the `checkout` keyword to set the current branch as `main`, and all commit that follow are registered against the current branch, i.e. `main`.
After this we merge the `develop` branch onto the current branch `main`, resulting in a merge commit.
Since the current branch at this point is still `main`, the last two commits are registered against that.
## Themes
Mermaid supports a bunch of pre-defined themes which you can use to find the right one for you. PS: you can actually override an existing theme's variable to get your own custom theme going. Learn more about themeing your diagram [here](./theming.md).
Following are the different pre-defined theme options:
- `base`
- `forest`
- `dark`
- `default`
- `neutral`
**NOTE**: To change theme you can either use the `initialize` call or *directives*. Learn more about [directives](./directives.md)
Let's put them to use, add see how our sample diagram looks like in different themes:
### Base Theme
```mermaid-example
%%{init: { 'logLevel': 'debug', 'theme': 'base' } }%%
gitGraph
commit
branch hotfix
checkout hotfix
commit
branch develop
checkout develop
commit id:"ash" tag:"abc"
branch featureB
checkout featureB
commit type:HIGHLIGHT
checkout main
checkout hotfix
commit type:NORMAL
checkout develop
commit type:REVERSE
checkout featureB
commit
checkout main
merge hotfix
checkout featureB
commit
checkout develop
branch featureA
commit
checkout develop
merge hotfix
checkout featureA
commit
checkout featureB
commit
checkout develop
merge featureA
branch release
checkout release
commit
checkout main
commit
checkout release
merge main
checkout develop
merge release
```
### Forest Theme
```mermaid-example
%%{init: { 'logLevel': 'debug', 'theme': 'forest' } }%%
gitGraph
commit
branch hotfix
checkout hotfix
commit
branch develop
checkout develop
commit id:"ash" tag:"abc"
branch featureB
checkout featureB
commit type:HIGHLIGHT
checkout main
checkout hotfix
commit type:NORMAL
checkout develop
commit type:REVERSE
checkout featureB
commit
checkout main
merge hotfix
checkout featureB
commit
checkout develop
branch featureA
commit
checkout develop
merge hotfix
checkout featureA
commit
checkout featureB
commit
checkout develop
merge featureA
branch release
checkout release
commit
checkout main
commit
checkout release
merge main
checkout develop
merge release
```
### Default Theme
```mermaid-example
%%{init: { 'logLevel': 'debug', 'theme': 'default' } }%%
gitGraph
commit type:HIGHLIGHT
branch hotfix
checkout hotfix
commit
branch develop
checkout develop
commit id:"ash" tag:"abc"
branch featureB
checkout featureB
commit type:HIGHLIGHT
checkout main
checkout hotfix
commit type:NORMAL
checkout develop
commit type:REVERSE
checkout featureB
commit
checkout main
merge hotfix
checkout featureB
commit
checkout develop
branch featureA
commit
checkout develop
merge hotfix
checkout featureA
commit
checkout featureB
commit
checkout develop
merge featureA
branch release
checkout release
commit
checkout main
commit
checkout release
merge main
checkout develop
merge release
```
### Dark Theme
```mermaid-example
%%{init: { 'logLevel': 'debug', 'theme': 'dark' } }%%
gitGraph
commit
branch hotfix
checkout hotfix
commit
branch develop
checkout develop
commit id:"ash" tag:"abc"
branch featureB
checkout featureB
commit type:HIGHLIGHT
checkout main
checkout hotfix
commit type:NORMAL
checkout develop
commit type:REVERSE
checkout featureB
commit
checkout main
merge hotfix
checkout featureB
commit
checkout develop
branch featureA
commit
checkout develop
merge hotfix
checkout featureA
commit
checkout featureB
commit
checkout develop
merge featureA
branch release
checkout release
commit
checkout main
commit
checkout release
merge main
checkout develop
merge release
```
### Neutral Theme
```mermaid-example
%%{init: { 'logLevel': 'debug', 'theme': 'neutral' } }%%
gitGraph
commit
branch hotfix
checkout hotfix
commit
branch develop
checkout develop
commit id:"ash" tag:"abc"
branch featureB
checkout featureB
commit type:HIGHLIGHT
checkout main
checkout hotfix
commit type:NORMAL
checkout develop
commit type:REVERSE
checkout featureB
commit
checkout main
merge hotfix
checkout featureB
commit
checkout develop
branch featureA
commit
checkout develop
merge hotfix
checkout featureA
commit
checkout featureB
commit
checkout develop
merge featureA
branch release
checkout release
commit
checkout main
commit
checkout release
merge main
checkout develop
merge release
```
## Customize using Theme Variables

View File

@@ -17,8 +17,8 @@
/>
<!-- <link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css"> -->
<link rel="stylesheet" href="theme.css" />
<script src="//cdn.jsdelivr.net/npm/mermaid@8.13.0/dist/mermaid.min.js"></script>
<!-- <script src="http://localhost:9000/mermaid.js"></script> -->
<!-- <script src="//cdn.jsdelivr.net/npm/mermaid@8.14.0/dist/mermaid.min.js"></script> -->
<script src="http://localhost:9000/mermaid.js"></script>
<script>
// prettier-ignore
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){

169
docs/integrations.md~HEAD Normal file
View File

@@ -0,0 +1,169 @@
# Integrations
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.
## Productivity
- [GitLab](https://docs.gitlab.com/ee/user/markdown.html#diagrams-and-flowcharts) (**Native support**)
- [Azure Devops](https://docs.microsoft.com/en-us/azure/devops/project/wiki/wiki-markdown-guidance?view=azure-devops#add-mermaid-diagrams-to-a-wiki-page) (**Native support**)
- [Tuleap](https://docs.tuleap.org/user-guide/writing-in-tuleap.html#graphs) (**Native support**)
- [Joplin](https://joplinapp.org) (**Native support**)
- [Notion](https://notion.so) (**Native support**)
- [GitHub](https://github.com)
- [GitHub action: Compile mermaid to image](https://github.com/neenjaw/compile-mermaid-markdown-action)
- [svg-generator](https://github.com/SimonKenyonShepard/mermaidjs-github-svg-generator)
- [GitBook](http://gitbook.com)
- [Mermaid Plugin](https://github.com/JozoVilcek/gitbook-plugin-mermaid)
- [Markdown with Mermaid CLI](https://github.com/miao1007/gitbook-plugin-mermaid-cli)
- [Mermaid plugin for GitBook](https://github.com/wwformat/gitbook-plugin-mermaid-pdf)
- [Atlassian Products](https://www.atlassian.com)
- [Mermaid Plugin for Confluence](https://marketplace.atlassian.com/apps/1214124/mermaid-plugin-for-confluence?hosting=server&tab=overview)
- [CloudScript.io Addon](https://marketplace.atlassian.com/apps/1219878/cloudscript-io-mermaid-addon?hosting=cloud&tab=overview)
- [Auto convert diagrams in Jira](https://github.com/coddingtonbear/jirafs-mermaid)
- [Redmine](https://redmine.org)
- [Mermaid Macro](https://www.redmine.org/plugins/redmine_mermaid_macro)
- [redmine-mermaid](https://github.com/styz/redmine_mermaid)
- [markdown-for-mermaid-plugin](https://github.com/jamieh-mongolian/markdown-for-mermaid-plugin)
## CRM/ERP/Similar
- [coreBOS](http://blog.corebos.org/blog/december2019)
## Blogs
- [Wordpress](https://wordpress.org)
- [WordPress Markdown Editor](https://wordpress.org/plugins/wp-githuber-md)
- [WP-ReliableMD](https://wordpress.org/plugins/wp-reliablemd/)
- [Hexo](https://hexo.io)
- [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)
## CMS
- [VuePress](https://vuepress.vuejs.org/)
- [Plugin for Mermaid.js](https://github.com/eFrane/vuepress-plugin-mermaidjs)
- [vuepress-plugin-mermaidjs-cli](https://github.com/gwleclerc/vuepress-plugin-mermaidjs-cli)
- [Grav CMS](https://getgrav.org/)
- [Mermaid Diagrams](https://github.com/DanielFlaum/grav-plugin-mermaid-diagrams)
- [Gitlab Markdown Adapter](https://github.com/Goutte/grav-plugin-gitlab-markdown-adapter)
## Communication
- [Discourse](https://discourse.org)
- [Mermaid Plugin](https://github.com/pnewell/discourse-mermaid), [And](https://github.com/unfoldingWord-dev/discourse-mermaid)
- [Mattermost](https://mattermost.com/)
- [Mermaid Plugin](https://github.com/SpikeTings/Mermaid)
- [phpBB](https://phpbb.com)
- [phpbb-ext-mermaid](https://github.com/AlfredoRamos/phpbb-ext-mermaid)
- [NodeBB](https://nodebb.org)
- [Mermaid Plugin](https://www.npmjs.com/package/nodebb-plugin-mermaid)
## Wikis
- [MediaWiki](https://www.mediawiki.org)
- [Mermaid Extension](https://www.mediawiki.org/wiki/Extension:Mermaid)
- [Flex Diagrams Extension](https://www.mediawiki.org/wiki/Extension:Flex_Diagrams)
- [Semantic Media Wiki](https://semantic-mediawiki.org)
- [Mermaid Plugin](https://github.com/SemanticMediaWiki/Mermaid)
- [FosWiki](https://foswiki.org)
- [Mermaid Plugin](https://foswiki.org/Extensions/MermaidPlugin)
- [DokuWiki](https://dokuwiki.org)
- [Flowcharts](https://www.dokuwiki.org/plugin:flowcharts?s[]=mermaid)
- [ComboStrap](https://combostrap.com/mermaid)
- [TiddlyWiki](https://tiddlywiki.com/)
- [mermaid-tw5: full js library](https://github.com/efurlanm/mermaid-tw5)
- [tw5-mermaid: wrapper for Mermaid Live](https://github.com/jasonmhoule/tw5-mermaid)
## Editor Plugins
- [Vs Code](https://code.visualstudio.com/)
- [Markdown Preview Mermaid Support](https://marketplace.visualstudio.com/items?itemName=bierner.markdown-mermaid)
- [Mermaid Preview](https://marketplace.visualstudio.com/items?itemName=vstirbu.vscode-mermaid-preview)
- [Mermaid Markdown Syntax Highlighting](https://marketplace.visualstudio.com/items?itemName=bpruitt-goddard.mermaid-markdown-syntax-highlighting)
- [Mermaid Editor](https://marketplace.visualstudio.com/items?itemName=tomoyukim.vscode-mermaid-editor)
- [Mermaid Export](https://marketplace.visualstudio.com/items?itemName=Gruntfuggly.mermaid-export)
- [Markdown PDF](https://marketplace.visualstudio.com/items?itemName=yzane.markdown-pdf)
- [Preview](https://marketplace.visualstudio.com/items?itemName=searKing.preview-vscode)
- [Preview Sequence Diagrams](https://marketplace.visualstudio.com/items?itemName=arichika.previewseqdiag-vscode)
- [Markdown-It](https://github.com/markdown-it/markdown-it)
- [Textual UML Parser](https://github.com/manastalukdar/markdown-it-textual-uml)
- [Mermaid Plugin](https://github.com/tylingsoft/markdown-it-mermaid)
- [md-it-mermaid](https://github.com/iamcco/md-it-mermaid)
- [markdown-it-mermaid-fence-new](https://github.com/Revomatico/markdown-it-mermaid-fence-new)
- [markdown-it-mermaid-less](https://github.com/searKing/markdown-it-mermaid-less)
- [Atom](https://atom.io)
- [Markdown Preview Enhanced](https://atom.io/packages/markdown-preview-enhanced)
- [Atom Mermaid](https://atom.io/packages/atom-mermaid)
- [Language Mermaid Syntax Highlighter](https://atom.io/packages/language-mermaid)
- [Sublime Text 3](https://sublimetext.com)
- [Mermaid Package](https://packagecontrol.io/packages/Mermaid)
- [Astah](http://astah.net)
- [Export to Mermaid](https://github.com/Avens666/Astah_Jude_UML_export_to_Markdown-mermaid-Plantuml-)
- [Light Table](http://lighttable.com/)
- [Mermaid Plugin](https://github.com/cldwalker/Mermaid)
- [Draw.io](http://draw.io) - [Plugin](https://github.com/nopeslide/drawio_mermaid_plugin)
- [Inkdrop](http://inkdrop.app) - [Plugin](https://github.com/inkdropapp/inkdrop-mermaid)
- [Vim](https://vim.org)
- [Vim Diagram Syntax](https://github.com/zhaozg/vim-diagram)
- [GNU Emacs](https://www.gnu.org/software/emacs/)
- [Major mode for .mmd files](https://github.com/abrochard/mermaid-mode)
- [Org-Mode integration](https://github.com/arnm/ob-mermaid)
- [Brackets](http://brackets.io/)
- [Mermaid Preview](https://s3.amazonaws.com/extend.brackets/alanhohn.mermaid-preview/alanhohn.mermaid-preview-1.0.2.zip)
- [Iodide](https://github.com/iodide-project/iodide)
- [iodide-mermaid-plugin](https://github.com/iodide-project/iodide-mermaid-plugin)
- [Google docs](https://docs.google.com/)
- [Mermaid plugin for google docs](https://workspace.google.com/marketplace/app/mermaid/636321283856)
- [Podlite](https://github.com/zag/podlite-desktop)
- [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)
## 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)
- [jSDoc](https://jsdoc.app/)
- [jsdoc-mermaid](https://github.com/Jellyvision/jsdoc-mermaid)
- [MkDocs](https://mkdocs.org)
- [mkdocs-mermaid2-plugin](https://github.com/fralau/mkdocs-mermaid2-plugin)
- [Type Doc](https://typedoc.org/)
- [typedoc-plugin-mermaid](https://www.npmjs.com/package/typedoc-plugin-mermaid)
- [Docsy Hugo Theme](https://www.docsy.dev/docs/adding-content/lookandfeel/#diagrams-with-mermaid) (Native support in theme)
- [Codedoc](https://codedoc.cc/)
- [codedoc-mermaid-plugin](https://www.npmjs.com/package/codedoc-mermaid-plugin)
## Browser Extensions
| Name | Chrome Web Store | Firefox Add-ons | Opera | Edge | Source/Repository |
| -- | -- | -- | -- | -- | -- |
| GitHub + Mermaid | [🎡🔗](https://chrome.google.com/webstore/detail/github-%20-mermaid/goiiopgdnkogdbjmncgedmgpoajilohe) | [🦊🔗](https://addons.mozilla.org/firefox/addon/github-mermaid/) | - | - | [🐙🔗](https://github.com/BackMarket/github-mermaid-extension)
| Asciidoctor Live Preview | [🎡🔗](https://chrome.google.com/webstore/detail/asciidoctorjs-live-previe/iaalpfgpbocpdfblpnhhgllgbdbchmia) | - | - | [🌀🔗](https://microsoftedge.microsoft.com/addons/detail/asciidoctorjs-live-previ/pefkelkanablhjdekgdahplkccnbdggd?hl=en-US) | -|
| Diagram Tab| -| - | - | - | [🐙🔗](https://github.com/khafast/diagramtab) |
| Markdown Diagrams| [🎡🔗](https://chrome.google.com/webstore/detail/markdown-diagrams/pmoglnmodacnbbofbgcagndelmgaclel/) | [🦊🔗](https://addons.mozilla.org/en-US/firefox/addon/markdown-diagrams/) | [🔴🔗](https://addons.opera.com/en/extensions/details/markdown-diagrams/) | [🌀🔗](https://microsoftedge.microsoft.com/addons/detail/markdown-diagrams/hceenoomhhdkjjijnmlclkpenkapfihe) | [🐙🔗](https://github.com/marcozaccari/markdown-diagrams-browser-extension/tree/master/doc/examples) |
| Markdown Viewer| - | [🦊🔗](https://addons.mozilla.org/en-US/firefox/addon/markdown-viewer-chrome/) | - | - | [🐙🔗](https://github.com/simov/markdown-viewer)|
| Extensions for Mermaid| - | [🦊🔗](https://addons.mozilla.org/en-US/firefox/addon/markdown-viewer-chrome/) | [🔴🔗](https://addons.opera.com/en/extensions/details/extensions-for-mermaid/)| - | [🐙🔗](https://github.com/Stefan-S/mermaid-extension) |
| Chrome Diagrammer| [🎡🔗](https://chrome.google.com/webstore/detail/chrome-diagrammer/bkpbgjmkomfoakfklcjeoegkklgjnnpk) | - |- | - | - |
| Mermaid Diagrams | [🎡🔗](https://chrome.google.com/webstore/detail/mermaid-diagrams/phfcghedmopjadpojhmmaffjmfiakfil) | - | - | - | - |
|Mermaid Markdown | [🎡🔗](https://chrome.google.com/webstore/detail/mermaid-markdown/mboeoikjijmjcjgpccghbcoegikliijg) | - | - | - | - |
| Monkeys | [🎡🔗](https://chrome.google.com/webstore/detail/monkeys-mermaid-for-githu/cplfdpoajbclbgphaphphcldamfkjlgi) | - | - | - | - |
| Mermaid Previewer | [🎡🔗](https://chrome.google.com/webstore/detail/mermaid-previewer/oidjnlhbegipkcklbdfnbkikplpghfdl) | - | - | - | - |
## Other
- [Jekyll](https://jekyllrb.com/)
- [jekyll-mermaid](https://rubygems.org/gems/jekyll-mermaid)
- [jekyll-mermaid-diagrams](https://github.com/fuzhibo/jekyll-mermaid-diagrams)
- [Reveal.js](https://github.com/hakimel/reveal.js)
- [reveal.js-mermaid-plugin](https://github.com/ludwick/reveal.js-mermaid-plugin)
- [Bisheng](https://www.npmjs.com/package/bisheng)
- [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-server: Generate diagrams using a HTTP request](https://github.com/TomWright/mermaid-server)

View File

@@ -15,3 +15,8 @@ You may also reach out to the team via our public Slack chat channels; however,
Keep current with the latest Mermaid releases. We regularly update Mermaid, and these updates may fix security defects discovered in previous versions. Check the Mermaid release notes for security-related updates.
Keep your applications dependencies up to date. Make sure you upgrade your package dependencies to keep the dependencies up to date. Avoid pinning to specific versions for your dependencies and, if you do, make sure you check periodically to see if your dependencies have had security updates, and update the pin accordingly.
## Configuring DomPurify
By default Mermaid uses a baseline [DOMPurify](https://github.com/cure53/DOMPurify) config. It is possible to override the options passed to DOMPurify by adding a `dompurifyConfig` key to the Mermaid options. This could potentially break the output of Mermaid so use this with caution.

View File

@@ -351,7 +351,7 @@ links <actor>: <json-formatted link-name link-url pairs>
An example is below:
```mmd
```mermaid-example
sequenceDiagram
participant Alice
participant John

View File

@@ -0,0 +1,504 @@
# Sequence diagrams
**Edit this Page** [![N|Solid](img/GitHub-Mark-32px.png)](https://github.com/mermaid-js/mermaid/blob/develop/docs/sequenceDiagram.md)
> A Sequence diagram is an interaction diagram that shows how processes operate with one another and in what order.
Mermaid can render sequence diagrams.
```mermaid-example
sequenceDiagram
Alice->>John: Hello John, how are you?
John-->>Alice: Great!
Alice-)John: See you later!
```
```note
A note on nodes, the word "end" could potentially break the diagram, due to the way that the mermaid language is scripted.
If unavoidable, one must use parentheses(), quotation marks "", or brackets {},[], to enclose the word "end". i.e : (end), [end], {end}.
```
## 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
sequenceDiagram
participant Alice
participant Bob
Alice->>Bob: Hi Bob
Bob->>Alice: Hi Alice
```
### Actors
If you specifically want to use the actor symbol instead of a rectangle with text you can do so by using actor statements as per below.
```mermaid-example
sequenceDiagram
actor Alice
actor Bob
Alice->>Bob: Hi Bob
Bob->>Alice: Hi Alice
```
### Aliases
The actor can have a convenient identifier and a descriptive label.
```mermaid-example
sequenceDiagram
participant A as Alice
participant J as John
A->>J: Hello John, how are you?
J->>A: Great!
```
## Messages
Messages can be of two displayed either solid or with a dotted line.
```
[Actor][Arrow][Actor]:Message text
```
There are six types of arrows currently supported:
| Type | Description |
| ---- | ------------------------------------------- |
| -> | Solid line without arrow |
| --> | Dotted line without arrow |
| ->> | Solid line with arrowhead |
| -->> | Dotted line with arrowhead |
| -x | Solid line with a cross at the end |
| --x | Dotted line with a cross at the end. |
| -) | Solid line with an open arrow at the end (async) |
| --) | Dotted line with a open arrow at the end (async) |
## Activations
It is possible to activate and deactivate an actor. (de)activation can be dedicated declarations:
```mermaid-example
sequenceDiagram
Alice->>John: Hello John, how are you?
activate John
John-->>Alice: Great!
deactivate John
```
There is also a shortcut notation by appending `+`/`-` suffix to the message arrow:
```mermaid-example
sequenceDiagram
Alice->>+John: Hello John, how are you?
John-->>-Alice: Great!
```
Activations can be stacked for same actor:
```mermaid-example
sequenceDiagram
Alice->>+John: Hello John, how are you?
Alice->>+John: John, can you hear me?
John-->>-Alice: Hi Alice, I can hear you!
John-->>-Alice: I feel great!
```
## Notes
It is possible to add notes to a sequence diagram. This is done by the notation
Note [ right of | left of | over ] [Actor]: Text in note content
See the example below:
```mermaid-example
sequenceDiagram
participant John
Note right of John: Text in note
```
It is also possible to create notes spanning two participants:
```mermaid-example
sequenceDiagram
Alice->John: Hello John, how are you?
Note over Alice,John: A typical interaction
```
## Loops
It is possible to express loops in a sequence diagram. This is done by the notation
```
loop Loop text
... statements ...
end
```
See the example below:
```mermaid-example
sequenceDiagram
Alice->John: Hello John, how are you?
loop Every minute
John-->Alice: Great!
end
```
## Alt
It is possible to express alternative paths in a sequence diagram. This is done by the notation
```
alt Describing text
... statements ...
else
... statements ...
end
```
or if there is sequence that is optional (if without else).
```
opt Describing text
... statements ...
end
```
See the example below:
```mermaid-example
sequenceDiagram
Alice->>Bob: Hello Bob, how are you?
alt is sick
Bob->>Alice: Not so good :(
else is well
Bob->>Alice: Feeling fresh like a daisy
end
opt Extra response
Bob->>Alice: Thanks for asking
end
```
## Parallel
It is possible to show actions that are happening in parallel.
This is done by the notation
```
par [Action 1]
... statements ...
and [Action 2]
... statements ...
and [Action N]
... statements ...
end
```
See the example below:
```mermaid-example
sequenceDiagram
par Alice to Bob
Alice->>Bob: Hello guys!
and Alice to John
Alice->>John: Hello guys!
end
Bob-->>Alice: Hi Alice!
John-->>Alice: Hi Alice!
```
It is also possible to nest parallel blocks.
```mermaid-example
sequenceDiagram
par Alice to Bob
Alice->>Bob: Go help John
and Alice to John
Alice->>John: I want this done today
par John to Charlie
John->>Charlie: Can we do this today?
and John to Diana
John->>Diana: Can you help us today?
end
end
```
## Background Highlighting
It is possible to highlight flows by providing colored background rects. This is done by the notation
The colors are defined using rgb and rgba syntax.
```
rect rgb(0, 255, 0)
... content ...
end
```
```
rect rgba(0, 0, 255, .1)
... content ...
end
```
See the examples below:
```mermaid-example
sequenceDiagram
participant Alice
participant John
rect rgb(191, 223, 255)
note right of Alice: Alice calls John.
Alice->>+John: Hello John, how are you?
rect rgb(200, 150, 255)
Alice->>+John: John, can you hear me?
John-->>-Alice: Hi Alice, I can hear you!
end
John-->>-Alice: I feel great!
end
Alice ->>+ John: Did you want to go to the game tonight?
John -->>- Alice: Yeah! See you there.
```
## Comments
Comments can be entered within a sequence diagram, which will be ignored by the parser. Comments need to be on their own line, and must be prefaced with `%%` (double percent signs). Any text after the start of the comment to the next newline will be treated as a comment, including any diagram syntax
```mmd
sequenceDiagram
Alice->>John: Hello John, how are you?
%% this is a comment
John-->>Alice: Great!
```
## Entity codes to escape characters
It is possible to escape characters using the syntax exemplified here.
```mermaid-example
sequenceDiagram
A->>B: I #9829; you!
B->>A: I #9829; you #infin; times more!
```
Numbers given are base 10, so `#` can be encoded as `#35;`. It is also supported to use HTML character names.
Because semicolons can be used instead of line breaks to define the markup, you need to use `#59;` to include a semicolon in message text.
## sequenceNumbers
It is possible to get a sequence number attached to each arrow in a sequence diagram. This can be configured when adding mermaid to the website as shown below:
```html
<script>
mermaid.initialize({
sequence: { showSequenceNumbers: true },
});
</script>
```
It can also be be turned on via the diagram code as in the diagram:
```mermaid-example
sequenceDiagram
autonumber
Alice->>John: Hello John, how are you?
loop Healthcheck
John->>John: Fight against hypochondria
end
Note right of John: Rational thoughts!
John-->>Alice: Great!
John->>Bob: How about you?
Bob-->>John: Jolly good!
```
## Actor Menus
Actors can have popup-menus containing individualized links to external pages. For example, if an actor represented a web service, useful links might include a link to the service health dashboard, repo containing the code for the service, or a wiki page describing the service.
This can be configured by adding one or more link lines with the format:
```
link <actor>: <link-label> @ <link-url>
```
```mmd
sequenceDiagram
participant Alice
participant John
link Alice: Dashboard @ https://dashboard.contoso.com/alice
link Alice: Wiki @ https://wiki.contoso.com/alice
link John: Dashboard @ https://dashboard.contoso.com/john
link John: Wiki @ https://wiki.contoso.com/john
Alice->>John: Hello John, how are you?
John-->>Alice: Great!
Alice-)John: See you later!
```
#### Advanced Menu Syntax
There is an advanced syntax that relies on JSON formatting. If you are comfortable with JSON format, then this exists as well.
This can be configured by adding the links lines with the format:
```
links <actor>: <json-formatted link-name link-url pairs>
```
An example is below:
```mmd
sequenceDiagram
participant Alice
participant John
links Alice: {"Dashboard": "https://dashboard.contoso.com/alice", "Wiki": "https://wiki.contoso.com/alice"}
links John: {"Dashboard": "https://dashboard.contoso.com/john", "Wiki": "https://wiki.contoso.com/john"}
Alice->>John: Hello John, how are you?
John-->>Alice: Great!
Alice-)John: See you later!
```
## Styling
Styling of a sequence diagram is done by defining a number of css classes. During rendering these classes are extracted from the file located at src/themes/sequence.scss
### Classes used
| Class | Description |
| ------------ | ----------------------------------------------------------- |
| actor | Style for the actor box at the top of the diagram. |
| text.actor | Styles for text in the actor box at the top of the diagram. |
| actor-line | The vertical line for an actor. |
| messageLine0 | Styles for the solid message line. |
| messageLine1 | Styles for the dotted message line. |
| messageText | Defines styles for the text on the message arrows. |
| labelBox | Defines styles label to left in a loop. |
| labelText | Styles for the text in label for loops. |
| loopText | Styles for the text in the loop box. |
| loopLine | Defines styles for the lines in the loop box. |
| note | Styles for the note box. |
| noteText | Styles for the text on in the note boxes. |
### Sample stylesheet
```css
body {
background: white;
}
.actor {
stroke: #ccccff;
fill: #ececff;
}
text.actor {
fill: black;
stroke: none;
font-family: Helvetica;
}
.actor-line {
stroke: grey;
}
.messageLine0 {
stroke-width: 1.5;
stroke-dasharray: '2 2';
marker-end: 'url(#arrowhead)';
stroke: black;
}
.messageLine1 {
stroke-width: 1.5;
stroke-dasharray: '2 2';
stroke: black;
}
#arrowhead {
fill: black;
}
.messageText {
fill: black;
stroke: none;
font-family: 'trebuchet ms', verdana, arial;
font-size: 14px;
}
.labelBox {
stroke: #ccccff;
fill: #ececff;
}
.labelText {
fill: black;
stroke: none;
font-family: 'trebuchet ms', verdana, arial;
}
.loopText {
fill: black;
stroke: none;
font-family: 'trebuchet ms', verdana, arial;
}
.loopLine {
stroke-width: 2;
stroke-dasharray: '2 2';
marker-end: 'url(#arrowhead)';
stroke: #ccccff;
}
.note {
stroke: #decc93;
fill: #fff5ad;
}
.noteText {
fill: black;
stroke: none;
font-family: 'trebuchet ms', verdana, arial;
font-size: 14px;
}
```
## Configuration
Is it possible to adjust the margins for rendering the sequence diagram.
This is done by defining `mermaid.sequenceConfig` or by the CLI to use a json file with the configuration.
How to use the CLI is described in the [mermaidCLI](mermaidCLI) page.
`mermaid.sequenceConfig` can be set to a JSON string with config parameters or the corresponding object.
```javascript
mermaid.sequenceConfig = {
diagramMarginX: 50,
diagramMarginY: 10,
boxTextMargin: 5,
noteMargin: 10,
messageMargin: 35,
mirrorActors: true
};
```
### Possible configuration parameters:
| Parameter | Description | Default value |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------ |
| mirrorActors | Turns on/off the rendering of actors below the diagram as well as above it | false |
| bottomMarginAdj | Adjusts how far down the graph ended. Wide borders styles with css could generate unwanted clipping which is why this config param exists. | 1 |
| actorFontSize | Sets the font size for the actor's description | 14 |
| actorFontFamily | Sets the font family for the actor's description | "Open-Sans", "sans-serif" |
| actorFontWeight | Sets the font weight for the actor's description | "Open-Sans", "sans-serif" |
| noteFontSize | Sets the font size for actor-attached notes | 14 |
| noteFontFamily | Sets the font family for actor-attached notes | "trebuchet ms", verdana, arial |
| noteFontWeight | Sets the font weight for actor-attached notes | "trebuchet ms", verdana, arial |
| noteAlign | Sets the text alignment for text in actor-attached notes | center |
| messageFontSize | Sets the font size for actor<->actor messages | 16 |
| messageFontFamily | Sets the font family for actor<->actor messages | "trebuchet ms", verdana, arial |
| messageFontWeight | Sets the font weight for actor<->actor messages | "trebuchet ms", verdana, arial |

View File

@@ -2,7 +2,7 @@
**Edit this Page** [![N|Solid](img/GitHub-Mark-32px.png)](https://github.com/mermaid-js/mermaid/blob/develop/docs/theming.md)
With Version 8.7.0 Mermaid comes out with a system for dynamic and integrated configuration of themes. The intent is to increase the customizability and ease of Styling for mermaid diagrams.
With Version 8.7.0 Mermaid comes out with a system for dynamic and integrated configuration of themes. The intent is to increase the customizability and ease of styling for mermaid diagrams.
The theme can be altered by changing the root level variable `theme` variable in the configuration. To change it for the whole site you must use the `initialize` call. To do it for just for a single diagram you can use the `%%init%%` directive
@@ -99,7 +99,7 @@ Leaving it empty will set all variable values to default.
## Color and Color Calculation:
Color definitions have certain interactions in mermaid, this is in order to ensure visibility for diagrams. mermaid will adjust some variables automatically, when colors are changed in order to compensate and maintain readability.
Color definitions have certain interactions in mermaid, this is in order to ensure visibility for diagrams. Mermaid will adjust some variables automatically, when colors are changed in order to compensate and maintain readability.
**The Default Value Column** to the right of the Variable column will denote the Variable paired/associated with the Variable on the left and the nature of this pairing or association. If it for instance says primaryColor it means that it gets primaryColor as default value. If it says "based on primaryColor" it means that it is calculated/ derived from primaryColor. This calculation can be primary color inversion, a change of hue, darkening or lightening by 10%, etc.

View File

@@ -1,12 +1,12 @@
<?xml version='1.0' encoding='iso-8859-1'?>
<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" xmlns:xlink="http://www.w3.org/1999/xlink" enable-background="new 0 0 512 512">
<g>
<path d="m411.313,123.313c6.25-6.25 6.25-16.375 0-22.625s-16.375-6.25-22.625,0l-32,32-9.375,9.375-20.688-20.688c-12.484-12.5-32.766-12.5-45.25,0l-16,16c-1.261,1.261-2.304,2.648-3.31,4.051-21.739-8.561-45.324-13.426-70.065-13.426-105.867,0-192,86.133-192,192s86.133,192 192,192 192-86.133 192-192c0-24.741-4.864-48.327-13.426-70.065 1.402-1.007 2.79-2.049 4.051-3.31l16-16c12.5-12.492 12.5-32.758 0-45.25l-20.688-20.688 9.375-9.375 32.001-31.999zm-219.313,100.687c-52.938,0-96,43.063-96,96 0,8.836-7.164,16-16,16s-16-7.164-16-16c0-70.578 57.422-128 128-128 8.836,0 16,7.164 16,16s-7.164,16-16,16z"/>
<path d="m459.02,148.98c-6.25-6.25-16.375-6.25-22.625,0s-6.25,16.375 0,22.625l16,16c3.125,3.125 7.219,4.688 11.313,4.688 4.094,0 8.188-1.563 11.313-4.688 6.25-6.25 6.25-16.375 0-22.625l-16.001-16z"/>
<path d="m340.395,75.605c3.125,3.125 7.219,4.688 11.313,4.688 4.094,0 8.188-1.563 11.313-4.688 6.25-6.25 6.25-16.375 0-22.625l-16-16c-6.25-6.25-16.375-6.25-22.625,0s-6.25,16.375 0,22.625l15.999,16z"/>
<path d="m400,64c8.844,0 16-7.164 16-16v-32c0-8.836-7.156-16-16-16-8.844,0-16,7.164-16,16v32c0,8.836 7.156,16 16,16z"/>
<path d="m496,96.586h-32c-8.844,0-16,7.164-16,16 0,8.836 7.156,16 16,16h32c8.844,0 16-7.164 16-16 0-8.836-7.156-16-16-16z"/>
<path d="m436.98,75.605c3.125,3.125 7.219,4.688 11.313,4.688 4.094,0 8.188-1.563 11.313-4.688l32-32c6.25-6.25 6.25-16.375 0-22.625s-16.375-6.25-22.625,0l-32,32c-6.251,6.25-6.251,16.375-0.001,22.625z"/>
</g>
</svg>
<?xml version='1.0' encoding='iso-8859-1'?>
<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" xmlns:xlink="http://www.w3.org/1999/xlink" enable-background="new 0 0 512 512">
<g>
<path d="m411.313,123.313c6.25-6.25 6.25-16.375 0-22.625s-16.375-6.25-22.625,0l-32,32-9.375,9.375-20.688-20.688c-12.484-12.5-32.766-12.5-45.25,0l-16,16c-1.261,1.261-2.304,2.648-3.31,4.051-21.739-8.561-45.324-13.426-70.065-13.426-105.867,0-192,86.133-192,192s86.133,192 192,192 192-86.133 192-192c0-24.741-4.864-48.327-13.426-70.065 1.402-1.007 2.79-2.049 4.051-3.31l16-16c12.5-12.492 12.5-32.758 0-45.25l-20.688-20.688 9.375-9.375 32.001-31.999zm-219.313,100.687c-52.938,0-96,43.063-96,96 0,8.836-7.164,16-16,16s-16-7.164-16-16c0-70.578 57.422-128 128-128 8.836,0 16,7.164 16,16s-7.164,16-16,16z"/>
<path d="m459.02,148.98c-6.25-6.25-16.375-6.25-22.625,0s-6.25,16.375 0,22.625l16,16c3.125,3.125 7.219,4.688 11.313,4.688 4.094,0 8.188-1.563 11.313-4.688 6.25-6.25 6.25-16.375 0-22.625l-16.001-16z"/>
<path d="m340.395,75.605c3.125,3.125 7.219,4.688 11.313,4.688 4.094,0 8.188-1.563 11.313-4.688 6.25-6.25 6.25-16.375 0-22.625l-16-16c-6.25-6.25-16.375-6.25-22.625,0s-6.25,16.375 0,22.625l15.999,16z"/>
<path d="m400,64c8.844,0 16-7.164 16-16v-32c0-8.836-7.156-16-16-16-8.844,0-16,7.164-16,16v32c0,8.836 7.156,16 16,16z"/>
<path d="m496,96.586h-32c-8.844,0-16,7.164-16,16 0,8.836 7.156,16 16,16h32c8.844,0 16-7.164 16-16 0-8.836-7.156-16-16-16z"/>
<path d="m436.98,75.605c3.125,3.125 7.219,4.688 11.313,4.688 4.094,0 8.188-1.563 11.313-4.688l32-32c6.25-6.25 6.25-16.375 0-22.625s-16.375-6.25-22.625,0l-32,32c-6.251,6.25-6.251,16.375-0.001,22.625z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

11
launch.json Normal file
View File

@@ -0,0 +1,11 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "attach",
"name": "Attach",
"port": 9229
}
]
}

View File

@@ -30,7 +30,7 @@
"lint": "eslint ./ --ext js,html",
"lint:fix": "yarn lint --fix",
"e2e:depr": "yarn lint && jest e2e --config e2e/jest.config.js",
"cypress": "percy exec -- cypress run",
"cypress": "cypress run",
"e2e": "start-server-and-test dev http://localhost:9000/ cypress",
"e2e-upd": "yarn lint && jest e2e -u --config e2e/jest.config.js",
"dev": "webpack serve --config ./.webpack/webpack.config.e2e.babel.js",
@@ -58,6 +58,7 @@
},
"dependencies": {
"@braintree/sanitize-url": "^6.0.0",
"cypress-image-snapshot": "^4.0.1",
"d3": "^7.0.0",
"dagre": "^0.8.5",
"dagre-d3": "^0.6.4",
@@ -74,22 +75,19 @@
"@babel/register": "^7.14.5",
"@commitlint/cli": "^16.0.0",
"@commitlint/config-conventional": "^16.0.0",
"@percy/cli": "^1.0.0-beta.58",
"@percy/cypress": "^3.1.0",
"@percy/migrate": "^0.11.0",
"babel-jest": "^27.0.6",
"babel-loader": "^8.2.2",
"concurrently": "^7.0.0",
"coveralls": "^3.0.2",
"css-to-string-loader": "^0.1.3",
"cypress": "9.5.1",
"cypress": "9.5.2",
"documentation": "13.2.0",
"eslint": "^8.2.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-cypress": "^2.12.1",
"eslint-plugin-html": "^6.2.0",
"eslint-plugin-jest": "^26.0.0",
"eslint-plugin-jsdoc": "^37.0.3",
"eslint-plugin-jsdoc": "^38.0.3",
"eslint-plugin-markdown": "^2.2.1",
"eslint-plugin-prettier": "^4.0.0",
"husky": "^7.0.1",

View File

@@ -9,15 +9,16 @@
* @param id
*/
export default function addSVGAccessibilityFields(yy_parser, svg, id) {
if (typeof svg.insert == 'undefined') {
return;
}
let title_string = yy_parser.getTitle();
let description = yy_parser.getAccDescription();
svg.attr('role', 'img').attr('aria-labelledby', 'chart-title-' + id + ' chart-desc-' + id);
svg
.insert('desc', ':first-child')
.attr('id', 'chart-desc-' + id)
.text(description);
svg
.insert('title', ':first-child')
.attr('id', 'chart-title-' + id)

View File

@@ -52,7 +52,7 @@ export const updateCurrentConfig = (siteCfg, _directives) => {
* **Notes:** Sets the siteConfig. The siteConfig is a protected configuration for repeat use. Calls
* to reset() will reset the currentConfig to siteConfig. Calls to reset(configApi.defaultConfig)
* will reset siteConfig and currentConfig to the defaultConfig Note: currentConfig is set in this
* function *Default value: At default, will mirror Global Config**
* function _Default value: At default, will mirror Global Config_
*
* @param conf - The base currentConfig to use as siteConfig
* @returns {object} - The siteConfig

View File

@@ -1,139 +1,139 @@
# Cluster handling
Dagre does not support edges between nodes and clusters or between clusters to other clusters. In order to remedy this shortcoming the dagre wrapper implements a few work-arounds.
In the diagram below there are two clusters and there are no edges to nodes outside the own cluster.
```mermaid
flowchart
subgraph C1
a --> b
end
subgraph C2
c
end
C1 --> C2
```
In this case the dagre-wrapper will transform the graph to the graph below.
```mermaid
flowchart
C1 --> C2
```
The new nodes C1 and C2 are a special type of nodes, clusterNodes. ClusterNodes have have the nodes in the cluster including the cluster attached in a graph object.
When rendering this diagram it it beeing rendered recursivly. The diagram is rendered by the dagre-mermaid:render function which in turn will be used to render the node C1 and the node C2. The result of those renderings will be inserted as nodes in the "root" diagram. With this recursive approach it would be possible to have different layout direction for each cluster.
```
{ clusterNode: true, graph }
```
*Data for a clusterNode*
When a cluster has edges to or from some of its nodes leading outside the cluster the approach of recursive rendering can not be used as the layout of the graph needs to take responsibility for nodes outside of the cluster.
```mermaid
flowchart
subgraph C1
a
end
subgraph C2
b
end
a --> C2
```
To handle this case a special type of edge is inserted. The edge to/from the cluster is replaced with an edge to/from a node in the cluster which is tagged with toCluster/fromCluster. When rendering this edge the intersection between the edge and the border of the cluster is calculated making the edge start/stop there. In practice this renders like an an edge to/from the cluster.
In the diagram above the root diagram would be rendered with C1 whereas C2 would be rendered recursively.
Of these two approaches the top one renders better and is used when possible. When this is not possible, ie an edge is added crossing the border the non recursive approach is used.
# Graph objects and their properties
Explains the representation of various objects used to render the flow charts and what the properties mean. This ofc from the perspective of the dagre-wrapper.
## node
Sample object:
```json
{
"shape":"rect",
"labelText":"Test",
"rx":0,
"ry":0,
"class":"default",
"style":"",
"id":"Test",
"type":"group",
"padding":15}
```
This is set by the renderer of the diagram and insert the data that the wrapper neds for rendering.
| property | description |
| ---------- | ----------------------------------------------------------------------------------------------------------- |
| labelStyle | Css styles for the label. User for instance for stylling the labels for clusters |
| shape | The shape of the node. |
| labelText | The text on the label |
| rx | The corner radius - maybe part of the shape instead? Used for rects. |
| ry | The corner radius - maybe part of the shape instead? Used for rects. |
| classes | Classes to be set for the shape. Not used |
| style | Css styles for the actual shape |
| id | id of the shape |
| type | if set to group then this node indicates *a cluster*. |
| padding | Padding. Passed from the render as this might differ between different diagrams. Maybe obsolete. |
| data | Non-generic data specific to the shape. |
# edge
arrowType sets the type of arrows to use. The following arrow types are currently supported:
arrow_cross
double_arrow_cross
arrow_point
double_arrow_point
arrow_circle
double_arrow_circle
Lets try to make these types semantic free so that diagram type semantics does not find its way in to this more generic layer.
Required edgeData for proper rendering:
| property | description |
| ---------- | ---------------------------------------- |
| id | Id of the edge |
| arrowHead | overlap between arrowHead and arrowType? |
| arrowType | overlap between arrowHead and arrowType? |
| style | |
| labelStyle | |
| label | overlap between label and labelText? |
| labelPos | |
| labelType | overlap between label and labelText? |
| thickness | Sets the thinkess of the edge. Can be \['normal', 'thick'\] |
| pattern | Sets the pattern of the edge. Can be \['solid', 'dotted', 'dashed'\] |
# Markers
Define what markers that should be included in the diagram with the insert markers function. The function takes two arguments, first the element in which the markers should be included and a list of the markers that should be added.
Ex:
insertMarkers(el, \['point', 'circle'\])
The example above adds the markers point and cross. This means that edges with the arrowTypes arrow_cross, double_arrow_cross, arrow_point and double_arrow_cross will get the corresponding markers but arrowType arrow_cross will have no impact.
Current markers:
* point - the standard arrow from flowcharts
* circle - Arrows ending with circle
* cross - arrows starting and ending with a cross
// Todo - in case of common renderer
# Common functions used by the renderer to be implemented by the Db
getDirection
getClasses
# Cluster handling
Dagre does not support edges between nodes and clusters or between clusters to other clusters. In order to remedy this shortcoming the dagre wrapper implements a few work-arounds.
In the diagram below there are two clusters and there are no edges to nodes outside the own cluster.
```mermaid
flowchart
subgraph C1
a --> b
end
subgraph C2
c
end
C1 --> C2
```
In this case the dagre-wrapper will transform the graph to the graph below.
```mermaid
flowchart
C1 --> C2
```
The new nodes C1 and C2 are a special type of nodes, clusterNodes. ClusterNodes have have the nodes in the cluster including the cluster attached in a graph object.
When rendering this diagram it it beeing rendered recursivly. The diagram is rendered by the dagre-mermaid:render function which in turn will be used to render the node C1 and the node C2. The result of those renderings will be inserted as nodes in the "root" diagram. With this recursive approach it would be possible to have different layout direction for each cluster.
```
{ clusterNode: true, graph }
```
*Data for a clusterNode*
When a cluster has edges to or from some of its nodes leading outside the cluster the approach of recursive rendering can not be used as the layout of the graph needs to take responsibility for nodes outside of the cluster.
```mermaid
flowchart
subgraph C1
a
end
subgraph C2
b
end
a --> C2
```
To handle this case a special type of edge is inserted. The edge to/from the cluster is replaced with an edge to/from a node in the cluster which is tagged with toCluster/fromCluster. When rendering this edge the intersection between the edge and the border of the cluster is calculated making the edge start/stop there. In practice this renders like an an edge to/from the cluster.
In the diagram above the root diagram would be rendered with C1 whereas C2 would be rendered recursively.
Of these two approaches the top one renders better and is used when possible. When this is not possible, ie an edge is added crossing the border the non recursive approach is used.
# Graph objects and their properties
Explains the representation of various objects used to render the flow charts and what the properties mean. This ofc from the perspective of the dagre-wrapper.
## node
Sample object:
```json
{
"shape":"rect",
"labelText":"Test",
"rx":0,
"ry":0,
"class":"default",
"style":"",
"id":"Test",
"type":"group",
"padding":15}
```
This is set by the renderer of the diagram and insert the data that the wrapper neds for rendering.
| property | description |
| ---------- | ----------------------------------------------------------------------------------------------------------- |
| labelStyle | Css styles for the label. User for instance for stylling the labels for clusters |
| shape | The shape of the node. |
| labelText | The text on the label |
| rx | The corner radius - maybe part of the shape instead? Used for rects. |
| ry | The corner radius - maybe part of the shape instead? Used for rects. |
| classes | Classes to be set for the shape. Not used |
| style | Css styles for the actual shape |
| id | id of the shape |
| type | if set to group then this node indicates *a cluster*. |
| padding | Padding. Passed from the render as this might differ between different diagrams. Maybe obsolete. |
| data | Non-generic data specific to the shape. |
# edge
arrowType sets the type of arrows to use. The following arrow types are currently supported:
arrow_cross
double_arrow_cross
arrow_point
double_arrow_point
arrow_circle
double_arrow_circle
Lets try to make these types semantic free so that diagram type semantics does not find its way in to this more generic layer.
Required edgeData for proper rendering:
| property | description |
| ---------- | ---------------------------------------- |
| id | Id of the edge |
| arrowHead | overlap between arrowHead and arrowType? |
| arrowType | overlap between arrowHead and arrowType? |
| style | |
| labelStyle | |
| label | overlap between label and labelText? |
| labelPos | |
| labelType | overlap between label and labelText? |
| thickness | Sets the thinkess of the edge. Can be \['normal', 'thick'\] |
| pattern | Sets the pattern of the edge. Can be \['solid', 'dotted', 'dashed'\] |
# Markers
Define what markers that should be included in the diagram with the insert markers function. The function takes two arguments, first the element in which the markers should be included and a list of the markers that should be added.
Ex:
insertMarkers(el, \['point', 'circle'\])
The example above adds the markers point and cross. This means that edges with the arrowTypes arrow_cross, double_arrow_cross, arrow_point and double_arrow_cross will get the corresponding markers but arrowType arrow_cross will have no impact.
Current markers:
* point - the standard arrow from flowcharts
* circle - Arrows ending with circle
* cross - arrows starting and ending with a cross
// Todo - in case of common renderer
# Common functions used by the renderer to be implemented by the Db
getDirection
getClasses

View File

@@ -1,32 +1,32 @@
const intersectRect = (node, point) => {
var x = node.x;
var y = node.y;
// Rectangle intersection algorithm from:
// http://math.stackexchange.com/questions/108113/find-edge-between-two-boxes
var dx = point.x - x;
var dy = point.y - y;
var w = node.width / 2;
var h = node.height / 2;
var sx, sy;
if (Math.abs(dy) * w > Math.abs(dx) * h) {
// Intersection is top or bottom of rect.
if (dy < 0) {
h = -h;
}
sx = dy === 0 ? 0 : (h * dx) / dy;
sy = h;
} else {
// Intersection is left or right of rect.
if (dx < 0) {
w = -w;
}
sx = w;
sy = dx === 0 ? 0 : (w * dy) / dx;
}
return { x: x + sx, y: y + sy };
};
export default intersectRect;
const intersectRect = (node, point) => {
var x = node.x;
var y = node.y;
// Rectangle intersection algorithm from:
// http://math.stackexchange.com/questions/108113/find-edge-between-two-boxes
var dx = point.x - x;
var dy = point.y - y;
var w = node.width / 2;
var h = node.height / 2;
var sx, sy;
if (Math.abs(dy) * w > Math.abs(dx) * h) {
// Intersection is top or bottom of rect.
if (dy < 0) {
h = -h;
}
sx = dy === 0 ? 0 : (h * dx) / dy;
sy = h;
} else {
// Intersection is left or right of rect.
if (dx < 0) {
w = -w;
}
sx = w;
sy = dx === 0 ? 0 : (w * dy) / dx;
}
return { x: x + sx, y: y + sy };
};
export default intersectRect;

View File

@@ -100,7 +100,7 @@ const config = {
arrowMarkerAbsolute: false,
/**
* This option controls which currentConfig keys are considered *secure* and can only be changed
* This option controls which currentConfig keys are considered _secure_ and can only be changed
* via call to mermaidAPI.initialize. Calls to mermaidAPI.reinitialize cannot make changes to the
* `secure` keys in the current currentConfig. This prevents malicious graph directives from
* overriding a site's default security.
@@ -1064,6 +1064,25 @@ const config = {
rect_padding: 10,
line_height: 20,
},
gitGraph: {
diagramPadding: 8,
nodeSpacing: 150,
nodeFillColor: 'yellow',
nodeStrokeWidth: 2,
nodeStrokeColor: 'grey',
lineStrokeWidth: 4,
branchOffset: 50,
lineColor: 'grey',
leftMargin: 50,
branchColors: ['#442f74', '#983351', '#609732', '#AA9A39'],
nodeRadius: 10,
nodeLabel: {
width: 75,
height: 100,
x: -25,
y: 0,
},
},
};
config.class.arrowMarkerAbsolute = config.arrowMarkerAbsolute;

View File

@@ -93,7 +93,12 @@ const sanitizeMore = (text, config) => {
export const sanitizeText = (text, config) => {
if (!text) return text;
const txt = DOMPurify.sanitize(sanitizeMore(text, config));
let txt = '';
if (config['dompurifyConfig']) {
txt = DOMPurify.sanitize(sanitizeMore(text, config), config['dompurifyConfig']);
} else {
txt = DOMPurify.sanitize(sanitizeMore(text, config));
}
return txt;
};

View File

@@ -5,6 +5,7 @@ import * as configApi from '../../config';
let entities = {};
let relationships = [];
let title = '';
let description = '';
const Cardinality = {
ZERO_OR_ONE: 'ZERO_OR_ONE',
@@ -75,6 +76,14 @@ const getTitle = function () {
return title;
};
const setAccDescription = function (txt) {
description = txt;
};
const getAccDescription = function () {
return description;
};
const clear = function () {
entities = {};
relationships = [];
@@ -94,4 +103,6 @@ export default {
clear,
setTitle,
getTitle,
setAccDescription,
getAccDescription,
};

View File

@@ -7,6 +7,7 @@ import { getConfig } from '../../config';
import { log } from '../../logger';
import erMarkers from './erMarkers';
import { configureSvgSize } from '../../utils';
import addSVGAccessibilityFields from '../../accessibility';
const conf = {};
@@ -637,6 +638,8 @@ export const draw = function (text, id) {
configureSvgSize(svg, height, width, conf.useMaxWidth);
svg.attr('viewBox', `${svgBounds.x - padding} ${svgBounds.y - padding} ${width} ${height}`);
addSVGAccessibilityFields(parser.yy, svg, id);
}; // draw
export default {

View File

@@ -2,8 +2,14 @@
%options case-insensitive
%x open_directive type_directive arg_directive block
%x title
%x accDescription
%%
title { this.begin("title");return 'title'; }
<title>(?!\n|;|#)*[^\n]* { this.popState(); return "title_value"; }
accDescription { this.begin("accDescription");return 'accDescription'; }
<accDescription>(?!\n|;|#)*[^\n]* { this.popState(); return "description_value"; }
\%\%\{ { this.begin('open_directive'); return 'open_directive'; }
<open_directive>((?:(?!\}\%\%)[^:.])*) { this.begin('type_directive'); return 'type_directive'; }
<type_directive>":" { this.popState(); this.begin('arg_directive'); return ':'; }
@@ -84,6 +90,8 @@ statement
}
| entityName BLOCK_START BLOCK_STOP { yy.addEntity($1); }
| entityName { yy.addEntity($1); }
| title title_value { $$=$2.trim();yy.setTitle($$); }
| accDescription description_value { $$=$2.trim();yy.setAccDescription($$); }
;
entityName

View File

@@ -181,6 +181,17 @@ describe('when parsing ER diagram it...', function () {
expect(Object.keys(erDb.getEntities()).length).toBe(1);
});
it('should allow for a title and acc description', function () {
const teacherRole = 'is teacher of';
const line1 = `TEACHER }o--o{ STUDENT : "${teacherRole}"`;
erDiagram.parser.parse(
`erDiagram\ntitle graph title\n accDescription this graph is about stuff\n${line1}`
);
expect(erDb.getTitle()).toBe('graph title');
expect(erDb.getAccDescription()).toBe('this graph is about stuff');
});
it('should allow more than one relationship between the same two entities', function () {
const line1 = 'CAR ||--o{ PERSON : "insured for"';
const line2 = 'CAR }o--|| PERSON : "owned by"';

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,12 @@
import { log } from '../../logger';
import { random } from '../../utils';
import mermaidAPI from '../../mermaidAPI';
import * as configApi from '../../config';
import common from '../common/common';
let commits = {};
let head = null;
let branches = { master: head };
let curBranch = 'master';
let branches = { main: head };
let curBranch = 'main';
let direction = 'LR';
let seq = 0;
@@ -11,41 +14,45 @@ function getId() {
return random({ length: 7 });
}
/**
* @param currentCommit
* @param otherCommit
*/
function isfastforwardable(currentCommit, otherCommit) {
log.debug('Entering isfastforwardable:', currentCommit.id, otherCommit.id);
let cnt = 0;
while (currentCommit.seq <= otherCommit.seq && currentCommit !== otherCommit && cnt < 1000) {
cnt++;
// only if other branch has more commits
if (otherCommit.parent == null) break;
if (Array.isArray(otherCommit.parent)) {
log.debug('In merge commit:', otherCommit.parent);
return (
isfastforwardable(currentCommit, commits[otherCommit.parent[0]]) ||
isfastforwardable(currentCommit, commits[otherCommit.parent[1]])
);
} else {
otherCommit = commits[otherCommit.parent];
}
}
log.debug(currentCommit.id, otherCommit.id);
return currentCommit.id === otherCommit.id;
}
export const parseDirective = function (statement, context, type) {
mermaidAPI.parseDirective(this, statement, context, type);
};
// /**
// * @param currentCommit
// * @param otherCommit
// */
// function isfastforwardable(currentCommit, otherCommit) {
// log.debug('Entering isfastforwardable:', currentCommit.id, otherCommit.id);
// let cnt = 0;
// while (currentCommit.seq <= otherCommit.seq && currentCommit !== otherCommit && cnt < 1000) {
// cnt++;
// // only if other branch has more commits
// if (otherCommit.parent == null) break;
// if (Array.isArray(otherCommit.parent)) {
// log.debug('In merge commit:', otherCommit.parent);
// return (
// isfastforwardable(currentCommit, commits[otherCommit.parent[0]]) ||
// isfastforwardable(currentCommit, commits[otherCommit.parent[1]])
// );
// } else {
// otherCommit = commits[otherCommit.parent];
// }
// }
// log.debug(currentCommit.id, otherCommit.id);
// return currentCommit.id === otherCommit.id;
// }
/**
* @param currentCommit
* @param otherCommit
*/
function isReachableFrom(currentCommit, otherCommit) {
const currentSeq = currentCommit.seq;
const otherSeq = otherCommit.seq;
if (currentSeq > otherSeq) return isfastforwardable(otherCommit, currentCommit);
return false;
}
// function isReachableFrom(currentCommit, otherCommit) {
// const currentSeq = currentCommit.seq;
// const otherSeq = otherCommit.seq;
// if (currentSeq > otherSeq) return isfastforwardable(otherCommit, currentCommit);
// return false;
// }
/**
* @param list
@@ -82,12 +89,19 @@ export const getOptions = function () {
return options;
};
export const commit = function (msg) {
export const commit = function (msg, id, type, tag) {
log.debug('Entering commit:', msg, id, type, tag);
id = common.sanitizeText(id, configApi.getConfig());
msg = common.sanitizeText(msg, configApi.getConfig());
tag = common.sanitizeText(tag, configApi.getConfig());
const commit = {
id: getId(),
id: id ? id : seq + '-' + getId(),
message: msg,
seq: seq++,
parent: head == null ? null : head.id,
type: type ? type : commitType.NORMAL,
tag: tag ? tag : '',
parents: head == null ? [] : [head.id],
branch: curBranch,
};
head = commit;
commits[commit.id] = commit;
@@ -96,61 +110,159 @@ export const commit = function (msg) {
};
export const branch = function (name) {
branches[name] = head != null ? head.id : null;
log.debug('in createBranch');
name = common.sanitizeText(name, configApi.getConfig());
if (typeof branches[name] === 'undefined') {
branches[name] = head != null ? head.id : null;
checkout(name);
log.debug('in createBranch');
} else {
let error = new Error(
'Trying to create an existing branch. (Help: Either use a new name if you want create a new branch or try using "checkout ' +
name +
'")'
);
error.hash = {
text: 'branch ' + name,
token: 'branch ' + name,
line: '1',
loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
expected: ['"checkout ' + name + '"'],
};
throw error;
}
};
export const merge = function (otherBranch) {
otherBranch = common.sanitizeText(otherBranch, configApi.getConfig());
const currentCommit = commits[branches[curBranch]];
const otherCommit = commits[branches[otherBranch]];
if (isReachableFrom(currentCommit, otherCommit)) {
log.debug('Already merged');
return;
}
if (isfastforwardable(currentCommit, otherCommit)) {
branches[curBranch] = branches[otherBranch];
head = commits[branches[curBranch]];
} else {
// create merge commit
const commit = {
id: getId(),
message: 'merged branch ' + otherBranch + ' into ' + curBranch,
seq: seq++,
parent: [head == null ? null : head.id, branches[otherBranch]],
if (curBranch === otherBranch) {
let error = new Error('Incorrect usage of "merge". Cannot merge a branch to itself');
error.hash = {
text: 'merge ' + otherBranch,
token: 'merge ' + otherBranch,
line: '1',
loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
expected: ['branch abc'],
};
head = commit;
commits[commit.id] = commit;
branches[curBranch] = commit.id;
throw error;
} else if (typeof currentCommit === 'undefined' || !currentCommit) {
let error = new Error(
'Incorrect usage of "merge". Current branch (' + curBranch + ')has no commits'
);
error.hash = {
text: 'merge ' + otherBranch,
token: 'merge ' + otherBranch,
line: '1',
loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
expected: ['commit'],
};
throw error;
} else if (typeof branches[otherBranch] === 'undefined') {
let error = new Error(
'Incorrect usage of "merge". Branch to be merged (' + otherBranch + ') does not exist'
);
error.hash = {
text: 'merge ' + otherBranch,
token: 'merge ' + otherBranch,
line: '1',
loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
expected: ['branch ' + otherBranch],
};
throw error;
} else if (typeof otherCommit === 'undefined' || !otherCommit) {
let error = new Error(
'Incorrect usage of "merge". Branch to be merged (' + otherBranch + ') has no commits'
);
error.hash = {
text: 'merge ' + otherBranch,
token: 'merge ' + otherBranch,
line: '1',
loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
expected: ['"commit"'],
};
throw error;
} else if (currentCommit === otherCommit) {
let error = new Error('Incorrect usage of "merge". Both branches have same head');
error.hash = {
text: 'merge ' + otherBranch,
token: 'merge ' + otherBranch,
line: '1',
loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
expected: ['branch abc'],
};
throw error;
}
// if (isReachableFrom(currentCommit, otherCommit)) {
// log.debug('Already merged');
// return;
// }
// if (isfastforwardable(currentCommit, otherCommit)) {
// branches[curBranch] = branches[otherBranch];
// head = commits[branches[curBranch]];
// } else {
// create merge commit
const commit = {
id: seq + '-' + getId(),
message: 'merged branch ' + otherBranch + ' into ' + curBranch,
seq: seq++,
parents: [head == null ? null : head.id, branches[otherBranch]],
branch: curBranch,
type: commitType.MERGE,
};
head = commit;
commits[commit.id] = commit;
branches[curBranch] = commit.id;
// }
log.debug(branches);
log.debug('in mergeBranch');
};
export const checkout = function (branch) {
log.debug('in checkout');
curBranch = branch;
const id = branches[curBranch];
head = commits[id];
branch = common.sanitizeText(branch, configApi.getConfig());
console.info(branches);
if (typeof branches[branch] === 'undefined') {
let error = new Error(
'Trying to checkout branch which is not yet created. (Help try using "branch ' + branch + '")'
);
error.hash = {
text: 'checkout ' + branch,
token: 'checkout ' + branch,
line: '1',
loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
expected: ['"branch ' + branch + '"'],
};
throw error;
//branches[branch] = head != null ? head.id : null;
//log.debug('in createBranch');
} else {
curBranch = branch;
const id = branches[curBranch];
console.log(id);
console.log('hi');
console.log(commits);
head = commits[id];
}
};
export const reset = function (commitRef) {
log.debug('in reset', commitRef);
const ref = commitRef.split(':')[0];
let parentCount = parseInt(commitRef.split(':')[1]);
let commit = ref === 'HEAD' ? head : commits[branches[ref]];
log.debug(commit, parentCount);
while (parentCount > 0) {
commit = commits[commit.parent];
parentCount--;
if (!commit) {
const err = 'Critical error - unique parent commit not found during reset';
log.error(err);
throw err;
}
}
head = commit;
branches[curBranch] = commit.id;
};
// export const reset = function (commitRef) {
// log.debug('in reset', commitRef);
// const ref = commitRef.split(':')[0];
// let parentCount = parseInt(commitRef.split(':')[1]);
// let commit = ref === 'HEAD' ? head : commits[branches[ref]];
// log.debug(commit, parentCount);
// while (parentCount > 0) {
// commit = commits[commit.parent];
// parentCount--;
// if (!commit) {
// const err = 'Critical error - unique parent commit not found during reset';
// log.error(err);
// throw err;
// }
// }
// head = commit;
// branches[curBranch] = commit.id;
// };
/**
* @param arr
@@ -185,14 +297,14 @@ function prettyPrintCommitHistory(commitArr) {
if (branches[branch] === commit.id) label.push(branch);
}
log.debug(label.join(' '));
if (Array.isArray(commit.parent)) {
const newCommit = commits[commit.parent[0]];
if (commit.parents && commit.parents.length == 2) {
const newCommit = commits[commit.parents[0]];
upsert(commitArr, commit, newCommit);
commitArr.push(commits[commit.parent[1]]);
} else if (commit.parent == null) {
commitArr.push(commits[commit.parents[1]]);
} else if (commit.parents.length == 0) {
return;
} else {
const nextCommit = commits[commit.parent];
const nextCommit = commits[commit.parents];
upsert(commitArr, commit, nextCommit);
}
commitArr = uniqBy(commitArr, (c) => c.id);
@@ -208,15 +320,16 @@ export const prettyPrint = function () {
export const clear = function () {
commits = {};
head = null;
branches = { master: head };
curBranch = 'master';
branches = { main: head };
curBranch = 'main';
seq = 0;
};
export const getBranchesAsObjArray = function () {
const branchArr = [];
for (let branch in branches) {
branchArr.push({ name: branch, commit: commits[branches[branch]] });
// branchArr.push({ name: branch, commit: commits[branches[branch]] });
branchArr.push({ name: branch });
}
return branchArr;
};
@@ -234,7 +347,7 @@ export const getCommitsArray = function () {
commitArr.forEach(function (o) {
log.debug(o.id);
});
commitArr.sort((a, b) => b.seq - a.seq);
commitArr.sort((a, b) => a.seq - b.seq);
return commitArr;
};
export const getCurrentBranch = function () {
@@ -247,7 +360,16 @@ export const getHead = function () {
return head;
};
export const commitType = {
NORMAL: 0,
REVERSE: 1,
HIGHLIGHT: 2,
MERGE: 3,
};
export default {
parseDirective,
getConfig: () => configApi.getConfig().gitGraph,
setDirection,
setOptions,
getOptions,
@@ -255,7 +377,7 @@ export default {
branch,
merge,
checkout,
reset,
//reset,
prettyPrint,
clear,
getBranchesAsObjArray,
@@ -265,4 +387,5 @@ export default {
getCurrentBranch,
getDirection,
getHead,
commitType,
};

View File

@@ -0,0 +1,570 @@
/* eslint-env jasmine */
// Todo reintroduce without cryptoRandomString
import gitGraphAst from './gitGraphAst';
import { parser } from './parser/gitGraph';
//import randomString from 'crypto-random-string';
//import cryptoRandomString from 'crypto-random-string';
import { logger } from '../../logger';
//jest.mock('crypto-random-string');
describe('when parsing a gitGraph', function () {
let randomNumber;
beforeEach(function () {
parser.yy = gitGraphAst;
parser.yy.clear();
randomNumber = 0;
});
// afterEach(function() {
// cryptoRandomString.mockReset();
// });
it('should handle a gitGraph commit with NO pararms, get auto-genrated reandom ID', function () {
const str = `gitGraph:
commit
`;
parser.parse(str);
const commits = parser.yy.getCommits();
//console.info(commits);
expect(Object.keys(commits).length).toBe(1);
expect(parser.yy.getCurrentBranch()).toBe('main');
expect(parser.yy.getDirection()).toBe('LR');
expect(Object.keys(parser.yy.getBranches()).length).toBe(1);
const key = Object.keys(commits)[0];
expect(commits[key].message).toBe('');
expect(commits[key].id).not.toBeNull();
expect(commits[key].tag).toBe('');
expect(commits[key].type).toBe(0);
});
it('should handle a gitGraph commit with custom commit id only', function () {
const str = `gitGraph:
commit id:"1111"
`;
//console.log(str);
parser.parse(str);
const commits = parser.yy.getCommits();
expect(Object.keys(commits).length).toBe(1);
expect(parser.yy.getCurrentBranch()).toBe('main');
expect(parser.yy.getDirection()).toBe('LR');
expect(Object.keys(parser.yy.getBranches()).length).toBe(1);
const key = Object.keys(commits)[0];
expect(commits[key].message).toBe('');
expect(commits[key].id).toBe('1111');
expect(commits[key].tag).toBe('');
expect(commits[key].type).toBe(0);
});
it('should handle a gitGraph commit with custom commit tag only', function () {
const str = `gitGraph:
commit tag:"test"
`;
parser.parse(str);
const commits = parser.yy.getCommits();
expect(Object.keys(commits).length).toBe(1);
expect(parser.yy.getCurrentBranch()).toBe('main');
expect(parser.yy.getDirection()).toBe('LR');
expect(Object.keys(parser.yy.getBranches()).length).toBe(1);
const key = Object.keys(commits)[0];
expect(commits[key].message).toBe('');
expect(commits[key].id).not.toBeNull();
expect(commits[key].tag).toBe('test');
expect(commits[key].type).toBe(0);
});
it('should handle a gitGraph commit with custom commit type HIGHLIGHT only', function () {
const str = `gitGraph:
commit type: HIGHLIGHT
`;
parser.parse(str);
const commits = parser.yy.getCommits();
expect(Object.keys(commits).length).toBe(1);
expect(parser.yy.getCurrentBranch()).toBe('main');
expect(parser.yy.getDirection()).toBe('LR');
expect(Object.keys(parser.yy.getBranches()).length).toBe(1);
const key = Object.keys(commits)[0];
expect(commits[key].message).toBe('');
expect(commits[key].id).not.toBeNull();
expect(commits[key].tag).toBe('');
expect(commits[key].type).toBe(2);
});
it('should handle a gitGraph commit with custom commit type REVERSE only', function () {
const str = `gitGraph:
commit type: REVERSE
`;
parser.parse(str);
const commits = parser.yy.getCommits();
expect(Object.keys(commits).length).toBe(1);
expect(parser.yy.getCurrentBranch()).toBe('main');
expect(parser.yy.getDirection()).toBe('LR');
expect(Object.keys(parser.yy.getBranches()).length).toBe(1);
const key = Object.keys(commits)[0];
expect(commits[key].message).toBe('');
expect(commits[key].id).not.toBeNull();
expect(commits[key].tag).toBe('');
expect(commits[key].type).toBe(1);
});
it('should handle a gitGraph commit with custom commit type NORMAL only', function () {
const str = `gitGraph:
commit type: NORMAL
`;
parser.parse(str);
const commits = parser.yy.getCommits();
expect(Object.keys(commits).length).toBe(1);
expect(parser.yy.getCurrentBranch()).toBe('main');
expect(parser.yy.getDirection()).toBe('LR');
expect(Object.keys(parser.yy.getBranches()).length).toBe(1);
const key = Object.keys(commits)[0];
expect(commits[key].message).toBe('');
expect(commits[key].id).not.toBeNull();
expect(commits[key].tag).toBe('');
expect(commits[key].type).toBe(0);
});
it('should handle a gitGraph commit with custom commit msg only', function () {
const str = `gitGraph:
commit "test commit"
`;
parser.parse(str);
const commits = parser.yy.getCommits();
expect(Object.keys(commits).length).toBe(1);
expect(parser.yy.getCurrentBranch()).toBe('main');
expect(parser.yy.getDirection()).toBe('LR');
expect(Object.keys(parser.yy.getBranches()).length).toBe(1);
const key = Object.keys(commits)[0];
expect(commits[key].message).toBe('test commit');
expect(commits[key].id).not.toBeNull();
expect(commits[key].tag).toBe('');
expect(commits[key].type).toBe(0);
});
it('should handle a gitGraph commit with custom commit "msg:" key only', function () {
const str = `gitGraph:
commit msg: "test commit"
`;
parser.parse(str);
const commits = parser.yy.getCommits();
expect(Object.keys(commits).length).toBe(1);
expect(parser.yy.getCurrentBranch()).toBe('main');
expect(parser.yy.getDirection()).toBe('LR');
expect(Object.keys(parser.yy.getBranches()).length).toBe(1);
const key = Object.keys(commits)[0];
expect(commits[key].message).toBe('test commit');
expect(commits[key].id).not.toBeNull();
expect(commits[key].tag).toBe('');
expect(commits[key].type).toBe(0);
});
it('should handle a gitGraph commit with custom commit id, tag only', function () {
const str = `gitGraph:
commit id:"1111" tag: "test tag"
`;
parser.parse(str);
const commits = parser.yy.getCommits();
expect(Object.keys(commits).length).toBe(1);
expect(parser.yy.getCurrentBranch()).toBe('main');
expect(parser.yy.getDirection()).toBe('LR');
expect(Object.keys(parser.yy.getBranches()).length).toBe(1);
const key = Object.keys(commits)[0];
expect(commits[key].message).toBe('');
expect(commits[key].id).toBe('1111');
expect(commits[key].tag).toBe('test tag');
expect(commits[key].type).toBe(0);
});
it('should handle a gitGraph commit with custom commit type, tag only', function () {
const str = `gitGraph:
commit type:HIGHLIGHT tag: "test tag"
`;
parser.parse(str);
const commits = parser.yy.getCommits();
expect(Object.keys(commits).length).toBe(1);
expect(parser.yy.getCurrentBranch()).toBe('main');
expect(parser.yy.getDirection()).toBe('LR');
expect(Object.keys(parser.yy.getBranches()).length).toBe(1);
const key = Object.keys(commits)[0];
expect(commits[key].message).toBe('');
expect(commits[key].id).not.toBeNull();
expect(commits[key].tag).toBe('test tag');
expect(commits[key].type).toBe(2);
});
it('should handle a gitGraph commit with custom commit tag and type only', function () {
const str = `gitGraph:
commit tag: "test tag" type:HIGHLIGHT
`;
parser.parse(str);
const commits = parser.yy.getCommits();
expect(Object.keys(commits).length).toBe(1);
expect(parser.yy.getCurrentBranch()).toBe('main');
expect(parser.yy.getDirection()).toBe('LR');
expect(Object.keys(parser.yy.getBranches()).length).toBe(1);
const key = Object.keys(commits)[0];
expect(commits[key].message).toBe('');
expect(commits[key].id).not.toBeNull();
expect(commits[key].tag).toBe('test tag');
expect(commits[key].type).toBe(2);
});
it('should handle a gitGraph commit with custom commit id, type and tag only', function () {
const str = `gitGraph:
commit id:"1111" type:REVERSE tag: "test tag"
`;
parser.parse(str);
const commits = parser.yy.getCommits();
expect(Object.keys(commits).length).toBe(1);
expect(parser.yy.getCurrentBranch()).toBe('main');
expect(parser.yy.getDirection()).toBe('LR');
expect(Object.keys(parser.yy.getBranches()).length).toBe(1);
const key = Object.keys(commits)[0];
expect(commits[key].message).toBe('');
expect(commits[key].id).toBe('1111');
expect(commits[key].tag).toBe('test tag');
expect(commits[key].type).toBe(1);
});
it('should handle a gitGraph commit with custom commit id, type, tag and msg', function () {
const str = `gitGraph:
commit id:"1111" type:REVERSE tag: "test tag" msg:"test msg"
`;
parser.parse(str);
const commits = parser.yy.getCommits();
expect(Object.keys(commits).length).toBe(1);
expect(parser.yy.getCurrentBranch()).toBe('main');
expect(parser.yy.getDirection()).toBe('LR');
expect(Object.keys(parser.yy.getBranches()).length).toBe(1);
const key = Object.keys(commits)[0];
expect(commits[key].message).toBe('test msg');
expect(commits[key].id).toBe('1111');
expect(commits[key].tag).toBe('test tag');
expect(commits[key].type).toBe(1);
});
it('should handle a gitGraph commit with custom type,tag, msg, commit id,', function () {
const str = `gitGraph:
commit type:REVERSE tag: "test tag" msg: "test msg" id: "1111"
`;
parser.parse(str);
const commits = parser.yy.getCommits();
expect(Object.keys(commits).length).toBe(1);
expect(parser.yy.getCurrentBranch()).toBe('main');
expect(parser.yy.getDirection()).toBe('LR');
expect(Object.keys(parser.yy.getBranches()).length).toBe(1);
const key = Object.keys(commits)[0];
expect(commits[key].message).toBe('test msg');
expect(commits[key].id).toBe('1111');
expect(commits[key].tag).toBe('test tag');
expect(commits[key].type).toBe(1);
});
it('should handle a gitGraph commit with custom tag, msg, commit id, type,', function () {
const str = `gitGraph:
commit tag: "test tag" msg:"test msg" id:"1111" type:REVERSE
`;
parser.parse(str);
const commits = parser.yy.getCommits();
expect(Object.keys(commits).length).toBe(1);
expect(parser.yy.getCurrentBranch()).toBe('main');
expect(parser.yy.getDirection()).toBe('LR');
expect(Object.keys(parser.yy.getBranches()).length).toBe(1);
const key = Object.keys(commits)[0];
expect(commits[key].message).toBe('test msg');
expect(commits[key].id).toBe('1111');
expect(commits[key].tag).toBe('test tag');
expect(commits[key].type).toBe(1);
});
it('should handle a gitGraph commit with custom msg, commit id, type,tag', function () {
const str = `gitGraph:
commit msg:"test msg" id:"1111" type:REVERSE tag: "test tag"
`;
parser.parse(str);
const commits = parser.yy.getCommits();
expect(Object.keys(commits).length).toBe(1);
expect(parser.yy.getCurrentBranch()).toBe('main');
expect(parser.yy.getDirection()).toBe('LR');
expect(Object.keys(parser.yy.getBranches()).length).toBe(1);
const key = Object.keys(commits)[0];
expect(commits[key].message).toBe('test msg');
expect(commits[key].id).toBe('1111');
expect(commits[key].tag).toBe('test tag');
expect(commits[key].type).toBe(1);
});
it('should handle 3 straight commits', function () {
const str = `gitGraph:
commit
commit
commit
`;
parser.parse(str);
const commits = parser.yy.getCommits();
expect(Object.keys(commits).length).toBe(3);
expect(parser.yy.getCurrentBranch()).toBe('main');
expect(parser.yy.getDirection()).toBe('LR');
expect(Object.keys(parser.yy.getBranches()).length).toBe(1);
});
it('should handle new branch creation', function () {
const str = `gitGraph:
commit
branch testBranch
`;
parser.parse(str);
const commits = parser.yy.getCommits();
expect(Object.keys(commits).length).toBe(1);
expect(parser.yy.getCurrentBranch()).toBe('testBranch');
expect(parser.yy.getDirection()).toBe('LR');
expect(Object.keys(parser.yy.getBranches()).length).toBe(2);
});
it('should handle new branch checkout', function () {
const str = `gitGraph:
commit
branch testBranch
checkout testBranch
`;
parser.parse(str);
const commits = parser.yy.getCommits();
expect(Object.keys(commits).length).toBe(1);
expect(parser.yy.getCurrentBranch()).toBe('testBranch');
expect(parser.yy.getDirection()).toBe('LR');
expect(Object.keys(parser.yy.getBranches()).length).toBe(2);
});
it('should handle new branch checkout & commit', function () {
const str = `gitGraph:
commit
branch testBranch
checkout testBranch
commit
`;
parser.parse(str);
const commits = parser.yy.getCommits();
expect(Object.keys(commits).length).toBe(2);
expect(parser.yy.getCurrentBranch()).toBe('testBranch');
expect(parser.yy.getDirection()).toBe('LR');
expect(Object.keys(parser.yy.getBranches()).length).toBe(2);
const commit1 = Object.keys(commits)[0];
const commit2 = Object.keys(commits)[1];
expect(commits[commit1].branch).toBe('main');
expect(commits[commit1].parents).toStrictEqual([]);
expect(commits[commit2].branch).toBe('testBranch');
expect(commits[commit2].parents).toStrictEqual([commit1]);
});
it('should handle new branch checkout & commit and merge', function () {
const str = `gitGraph:
commit
branch testBranch
checkout testBranch
commit
commit
checkout main
merge testBranch
`;
parser.parse(str);
const commits = parser.yy.getCommits();
expect(Object.keys(commits).length).toBe(4);
expect(parser.yy.getCurrentBranch()).toBe('main');
expect(parser.yy.getDirection()).toBe('LR');
expect(Object.keys(parser.yy.getBranches()).length).toBe(2);
const commit1 = Object.keys(commits)[0];
const commit2 = Object.keys(commits)[1];
const commit3 = Object.keys(commits)[2];
const commit4 = Object.keys(commits)[3];
expect(commits[commit1].branch).toBe('main');
console.log(commits);
console.log(commits[commit1].parents);
expect(commits[commit1].parents).toStrictEqual([]);
expect(commits[commit2].branch).toBe('testBranch');
expect(commits[commit2].parents).toStrictEqual([commits[commit1].id]);
expect(commits[commit3].branch).toBe('testBranch');
expect(commits[commit3].parents).toStrictEqual([commits[commit2].id]);
expect(commits[commit4].branch).toBe('main');
expect(commits[commit4].parents).toStrictEqual([commits[commit1].id, commits[commit3].id]);
expect(parser.yy.getBranchesAsObjArray()).toStrictEqual([
{ name: 'main' },
{ name: 'testBranch' },
]);
});
it('should throw error when try to branch existing branch: main', function () {
const str = `gitGraph
commit
branch testBranch
commit
branch main
commit
checkout main
merge testBranch
`;
try {
parser.parse(str);
// Fail test if above expression doesn't throw anything.
expect(true).toBe(false);
} catch (e) {
expect(e.message).toBe(
'Trying to create an existing branch. (Help: Either use a new name if you want create a new branch or try using "checkout main")'
);
}
});
it('should throw error when try to branch existing branch: testBranch', function () {
const str = `gitGraph
commit
branch testBranch
commit
branch testBranch
commit
checkout main
merge testBranch
`;
try {
parser.parse(str);
// Fail test if above expression doesn't throw anything.
expect(true).toBe(false);
} catch (e) {
expect(e.message).toBe(
'Trying to create an existing branch. (Help: Either use a new name if you want create a new branch or try using "checkout testBranch")'
);
}
});
it('should throw error when try to checkout unknown branch: testBranch', function () {
const str = `gitGraph
commit
checkout testBranch
commit
branch testBranch
commit
checkout main
merge testBranch
`;
try {
parser.parse(str);
// Fail test if above expression doesn't throw anything.
expect(true).toBe(false);
} catch (e) {
expect(e.message).toBe(
'Trying to checkout branch which is not yet created. (Help try using "branch testBranch")'
);
}
});
it('should throw error when trying to merge, when current branch has no commits', function () {
const str = `gitGraph
merge testBranch
commit
checkout testBranch
commit
branch testBranch
commit
checkout main
merge testBranch
`;
try {
parser.parse(str);
// Fail test if above expression doesn't throw anything.
expect(true).toBe(false);
} catch (e) {
expect(e.message).toBe('Incorrect usage of "merge". Current branch (main)has no commits');
}
});
it('should throw error when trying to merge unknown branch', function () {
const str = `gitGraph
commit
merge testBranch
commit
checkout testBranch
commit
branch testBranch
commit
checkout main
merge testBranch
`;
try {
parser.parse(str);
// Fail test if above expression doesn't throw anything.
expect(true).toBe(false);
} catch (e) {
expect(e.message).toBe(
'Incorrect usage of "merge". Branch to be merged (testBranch) does not exist'
);
}
});
it('should throw error when trying to merge branch to itself', function () {
const str = `gitGraph
commit
branch testBranch
merge testBranch
`;
try {
parser.parse(str);
// Fail test if above expression doesn't throw anything.
expect(true).toBe(false);
} catch (e) {
expect(e.message).toBe('Incorrect usage of "merge". Cannot merge a branch to itself');
}
});
it('should throw error when trying to merge branches having same heads', function () {
const str = `gitGraph
commit
branch testBranch
checkout main
merge testBranch
`;
try {
parser.parse(str);
// Fail test if above expression doesn't throw anything.
expect(true).toBe(false);
} catch (e) {
expect(e.message).toBe('Incorrect usage of "merge". Both branches have same head');
}
});
it('should throw error when trying to merge branch which has no commits', function () {
const str = `gitGraph
branch test1
checkout main
commit
merge test1
`;
try {
parser.parse(str);
// Fail test if above expression doesn't throw anything.
expect(true).toBe(false);
} catch (e) {
expect(e.message).toBe(
'Incorrect usage of "merge". Branch to be merged (test1) has no commits'
);
}
});
});

View File

@@ -0,0 +1,372 @@
import { curveBasis, line, select } from 'd3';
import db from './gitGraphAst';
import gitGraphParser from './parser/gitGraph';
import { logger } from '../../logger';
import { interpolateToCurve } from '../../utils';
let allCommitsDict = {};
let branchNum;
let config = {
nodeSpacing: 150,
nodeFillColor: 'yellow',
nodeStrokeWidth: 2,
nodeStrokeColor: 'grey',
lineStrokeWidth: 4,
branchOffset: 50,
lineColor: 'grey',
leftMargin: 50,
branchColors: ['#442f74', '#983351', '#609732', '#AA9A39'],
nodeRadius: 10,
nodeLabel: {
width: 75,
height: 100,
x: -25,
y: 0,
},
};
let apiConfig = {};
export const setConf = function (c) {
apiConfig = c;
};
/** @param svg */
function svgCreateDefs(svg) {
svg
.append('defs')
.append('g')
.attr('id', 'def-commit')
.append('circle')
.attr('r', config.nodeRadius)
.attr('cx', 0)
.attr('cy', 0);
svg
.select('#def-commit')
.append('foreignObject')
.attr('width', config.nodeLabel.width)
.attr('height', config.nodeLabel.height)
.attr('x', config.nodeLabel.x)
.attr('y', config.nodeLabel.y)
.attr('class', 'node-label')
.attr('requiredFeatures', 'http://www.w3.org/TR/SVG11/feature#Extensibility')
.append('p')
.html('');
}
/**
* @param svg
* @param points
* @param colorIdx
* @param interpolate
*/
function svgDrawLine(svg, points, colorIdx, interpolate) {
const curve = interpolateToCurve(interpolate, curveBasis);
const color = config.branchColors[colorIdx % config.branchColors.length];
const lineGen = line()
.x(function (d) {
return Math.round(d.x);
})
.y(function (d) {
return Math.round(d.y);
})
.curve(curve);
svg
.append('svg:path')
.attr('d', lineGen(points))
.style('stroke', color)
.style('stroke-width', config.lineStrokeWidth)
.style('fill', 'none');
}
// Pass in the element and its pre-transform coords
/**
* @param element
* @param coords
*/
function getElementCoords(element, coords) {
coords = coords || element.node().getBBox();
const ctm = element.node().getCTM();
const xn = ctm.e + coords.x * ctm.a;
const yn = ctm.f + coords.y * ctm.d;
return {
left: xn,
top: yn,
width: coords.width,
height: coords.height,
};
}
/**
* @param svg
* @param fromId
* @param toId
* @param direction
* @param color
*/
function svgDrawLineForCommits(svg, fromId, toId, direction, color) {
logger.debug('svgDrawLineForCommits: ', fromId, toId);
const fromBbox = getElementCoords(svg.select('#node-' + fromId + ' circle'));
const toBbox = getElementCoords(svg.select('#node-' + toId + ' circle'));
switch (direction) {
case 'LR':
// (toBbox)
// +--------
// + (fromBbox)
if (fromBbox.left - toBbox.left > config.nodeSpacing) {
const lineStart = {
x: fromBbox.left - config.nodeSpacing,
y: toBbox.top + toBbox.height / 2,
};
const lineEnd = { x: toBbox.left + toBbox.width, y: toBbox.top + toBbox.height / 2 };
svgDrawLine(svg, [lineStart, lineEnd], color, 'linear');
svgDrawLine(
svg,
[
{ x: fromBbox.left, y: fromBbox.top + fromBbox.height / 2 },
{ x: fromBbox.left - config.nodeSpacing / 2, y: fromBbox.top + fromBbox.height / 2 },
{ x: fromBbox.left - config.nodeSpacing / 2, y: lineStart.y },
lineStart,
],
color
);
} else {
svgDrawLine(
svg,
[
{
x: fromBbox.left,
y: fromBbox.top + fromBbox.height / 2,
},
{
x: fromBbox.left - config.nodeSpacing / 2,
y: fromBbox.top + fromBbox.height / 2,
},
{
x: fromBbox.left - config.nodeSpacing / 2,
y: toBbox.top + toBbox.height / 2,
},
{
x: toBbox.left + toBbox.width,
y: toBbox.top + toBbox.height / 2,
},
],
color
);
}
break;
case 'BT':
// + (fromBbox)
// |
// |
// + (toBbox)
if (toBbox.top - fromBbox.top > config.nodeSpacing) {
const lineStart = {
x: toBbox.left + toBbox.width / 2,
y: fromBbox.top + fromBbox.height + config.nodeSpacing,
};
const lineEnd = { x: toBbox.left + toBbox.width / 2, y: toBbox.top };
svgDrawLine(svg, [lineStart, lineEnd], color, 'linear');
svgDrawLine(
svg,
[
{ x: fromBbox.left + fromBbox.width / 2, y: fromBbox.top + fromBbox.height },
{
x: fromBbox.left + fromBbox.width / 2,
y: fromBbox.top + fromBbox.height + config.nodeSpacing / 2,
},
{ x: toBbox.left + toBbox.width / 2, y: lineStart.y - config.nodeSpacing / 2 },
lineStart,
],
color
);
} else {
svgDrawLine(
svg,
[
{
x: fromBbox.left + fromBbox.width / 2,
y: fromBbox.top + fromBbox.height,
},
{
x: fromBbox.left + fromBbox.width / 2,
y: fromBbox.top + config.nodeSpacing / 2,
},
{
x: toBbox.left + toBbox.width / 2,
y: toBbox.top - config.nodeSpacing / 2,
},
{
x: toBbox.left + toBbox.width / 2,
y: toBbox.top,
},
],
color
);
}
break;
}
}
/**
* @param svg
* @param selector
*/
function cloneNode(svg, selector) {
return svg.select(selector).node().cloneNode(true);
}
/**
* @param svg
* @param commitid
* @param branches
* @param direction
*/
function renderCommitHistory(svg, commitid, branches, direction) {
let commit;
const numCommits = Object.keys(allCommitsDict).length;
if (typeof commitid === 'string') {
do {
commit = allCommitsDict[commitid];
logger.debug('in renderCommitHistory', commit.id, commit.seq);
if (svg.select('#node-' + commitid).size() > 0) {
return;
}
svg
.append(function () {
return cloneNode(svg, '#def-commit');
})
.attr('class', 'commit')
.attr('id', function () {
return 'node-' + commit.id;
})
.attr('transform', function () {
switch (direction) {
case 'LR':
return (
'translate(' +
(commit.seq * config.nodeSpacing + config.leftMargin) +
', ' +
branchNum * config.branchOffset +
')'
);
case 'BT':
return (
'translate(' +
(branchNum * config.branchOffset + config.leftMargin) +
', ' +
(numCommits - commit.seq) * config.nodeSpacing +
')'
);
}
})
.attr('fill', config.nodeFillColor)
.attr('stroke', config.nodeStrokeColor)
.attr('stroke-width', config.nodeStrokeWidth);
let branch;
for (let branchName in branches) {
if (branches[branchName].commit === commit) {
branch = branches[branchName];
break;
}
}
if (branch) {
logger.debug('found branch ', branch.name);
svg
.select('#node-' + commit.id + ' p')
.append('xhtml:span')
.attr('class', 'branch-label')
.text(branch.name + ', ');
}
svg
.select('#node-' + commit.id + ' p')
.append('xhtml:span')
.attr('class', 'commit-id')
.text(commit.id);
if (commit.message !== '' && direction === 'BT') {
svg
.select('#node-' + commit.id + ' p')
.append('xhtml:span')
.attr('class', 'commit-msg')
.text(', ' + commit.message);
}
commitid = commit.parent;
} while (commitid && allCommitsDict[commitid]);
}
if (Array.isArray(commitid)) {
logger.debug('found merge commmit', commitid);
renderCommitHistory(svg, commitid[0], branches, direction);
branchNum++;
renderCommitHistory(svg, commitid[1], branches, direction);
branchNum--;
}
}
/**
* @param svg
* @param commit
* @param direction
* @param branchColor
*/
function renderLines(svg, commit, direction, branchColor) {
branchColor = branchColor || 0;
while (commit.seq > 0 && !commit.lineDrawn) {
if (typeof commit.parent === 'string') {
svgDrawLineForCommits(svg, commit.id, commit.parent, direction, branchColor);
commit.lineDrawn = true;
commit = allCommitsDict[commit.parent];
} else if (Array.isArray(commit.parent)) {
svgDrawLineForCommits(svg, commit.id, commit.parent[0], direction, branchColor);
svgDrawLineForCommits(svg, commit.id, commit.parent[1], direction, branchColor + 1);
renderLines(svg, allCommitsDict[commit.parent[1]], direction, branchColor + 1);
commit.lineDrawn = true;
commit = allCommitsDict[commit.parent[0]];
}
}
}
export const draw = function (txt, id, ver) {
try {
const parser = gitGraphParser.parser;
parser.yy = db;
parser.yy.clear();
logger.debug('in gitgraph renderer', txt + '\n', 'id:', id, ver);
// Parse the graph definition
parser.parse(txt + '\n');
config = Object.assign(config, apiConfig, db.getOptions());
logger.debug('effective options', config);
const direction = db.getDirection();
allCommitsDict = db.getCommits();
const branches = db.getBranchesAsObjArray();
if (direction === 'BT') {
config.nodeLabel.x = branches.length * config.branchOffset;
config.nodeLabel.width = '100%';
config.nodeLabel.y = -1 * 2 * config.nodeRadius;
}
const svg = select(`[id="${id}"]`);
svgCreateDefs(svg);
branchNum = 1;
for (let branch in branches) {
const v = branches[branch];
renderCommitHistory(svg, v.commit.id, branches, direction);
renderLines(svg, v.commit, direction);
branchNum++;
}
svg.attr('height', function () {
if (direction === 'BT') return Object.keys(allCommitsDict).length * config.nodeSpacing;
return (branches.length + 1) * config.branchOffset;
});
} catch (e) {
logger.error('Error while rendering gitgraph');
logger.error(e.message);
}
};
export default {
setConf,
draw,
};

View File

@@ -1,38 +1,44 @@
/* eslint-disable */
import { curveBasis, line, select } from 'd3';
import { interpolateToCurve, getStylesFromArray, configureSvgSize } from '../../utils';
import db from './gitGraphAst';
//import * as db from './mockDb';
import gitGraphParser from './parser/gitGraph';
import { log } from '../../logger';
import { interpolateToCurve } from '../../utils';
/* eslint-disable */
import { getConfig } from '../../config';
//import * as configApi from '../../config';
let allCommitsDict = {};
let branchNum;
let config = {
nodeSpacing: 150,
nodeFillColor: 'yellow',
nodeStrokeWidth: 2,
nodeStrokeColor: 'grey',
lineStrokeWidth: 4,
branchOffset: 50,
lineColor: 'grey',
leftMargin: 50,
branchColors: ['#442f74', '#983351', '#609732', '#AA9A39'],
nodeRadius: 10,
nodeLabel: {
width: 75,
height: 100,
x: -25,
y: 0,
},
};
let apiConfig = {};
export const setConf = function (c) {
apiConfig = c;
//let conf = configApi.getConfig();
//const commitType = db.commitType;
const commitType = {
NORMAL: 0,
REVERSE: 1,
HIGHLIGHT: 2,
MERGE: 3,
};
let branchPos = {};
let commitPos = {};
let lanes = [];
let maxPos = 0;
const clear = () => {
branchPos = {};
commitPos = {};
allCommitsDict = {};
maxPos = 0;
lanes = []
};
// let apiConfig = {};
// export const setConf = function(c) {
// apiConfig = c;
// };
/** @param svg */
function svgCreateDefs(svg) {
const config = getConfig().gitGraph;
svg
.append('defs')
.append('g')
@@ -60,44 +66,12 @@ function svgCreateDefs(svg) {
* @param colorIdx
* @param interpolate
*/
function svgDrawLine(svg, points, colorIdx, interpolate) {
const curve = interpolateToCurve(interpolate, curveBasis);
const color = config.branchColors[colorIdx % config.branchColors.length];
const lineGen = line()
.x(function (d) {
return Math.round(d.x);
})
.y(function (d) {
return Math.round(d.y);
})
.curve(curve);
svg
.append('svg:path')
.attr('d', lineGen(points))
.style('stroke', color)
.style('stroke-width', config.lineStrokeWidth)
.style('fill', 'none');
}
/**
* Pass in the element and its pre-transform coords
// Pass in the element and its pre-transform coords
*
* @param element
* @param coords
*/
function getElementCoords(element, coords) {
coords = coords || element.node().getBBox();
const ctm = element.node().getCTM();
const xn = ctm.e + coords.x * ctm.a;
const yn = ctm.f + coords.y * ctm.d;
return {
left: xn,
top: yn,
width: coords.width,
height: coords.height,
};
}
/**
* @param svg
@@ -106,116 +80,299 @@ function getElementCoords(element, coords) {
* @param direction
* @param color
*/
function svgDrawLineForCommits(svg, fromId, toId, direction, color) {
log.debug('svgDrawLineForCommits: ', fromId, toId);
const fromBbox = getElementCoords(svg.select('#node-' + fromId + ' circle'));
const toBbox = getElementCoords(svg.select('#node-' + toId + ' circle'));
switch (direction) {
case 'LR':
// (toBbox)
// +--------
// + (fromBbox)
if (fromBbox.left - toBbox.left > config.nodeSpacing) {
const lineStart = {
x: fromBbox.left - config.nodeSpacing,
y: toBbox.top + toBbox.height / 2,
};
const lineEnd = { x: toBbox.left + toBbox.width, y: toBbox.top + toBbox.height / 2 };
svgDrawLine(svg, [lineStart, lineEnd], color, 'linear');
svgDrawLine(
svg,
[
{ x: fromBbox.left, y: fromBbox.top + fromBbox.height / 2 },
{ x: fromBbox.left - config.nodeSpacing / 2, y: fromBbox.top + fromBbox.height / 2 },
{ x: fromBbox.left - config.nodeSpacing / 2, y: lineStart.y },
lineStart,
],
color
);
} else {
svgDrawLine(
svg,
[
{
x: fromBbox.left,
y: fromBbox.top + fromBbox.height / 2,
},
{
x: fromBbox.left - config.nodeSpacing / 2,
y: fromBbox.top + fromBbox.height / 2,
},
{
x: fromBbox.left - config.nodeSpacing / 2,
y: toBbox.top + toBbox.height / 2,
},
{
x: toBbox.left + toBbox.width,
y: toBbox.top + toBbox.height / 2,
},
],
color
);
}
break;
case 'BT':
// + (fromBbox)
// |
// |
// + (toBbox)
if (toBbox.top - fromBbox.top > config.nodeSpacing) {
const lineStart = {
x: toBbox.left + toBbox.width / 2,
y: fromBbox.top + fromBbox.height + config.nodeSpacing,
};
const lineEnd = { x: toBbox.left + toBbox.width / 2, y: toBbox.top };
svgDrawLine(svg, [lineStart, lineEnd], color, 'linear');
svgDrawLine(
svg,
[
{ x: fromBbox.left + fromBbox.width / 2, y: fromBbox.top + fromBbox.height },
{
x: fromBbox.left + fromBbox.width / 2,
y: fromBbox.top + fromBbox.height + config.nodeSpacing / 2,
},
{ x: toBbox.left + toBbox.width / 2, y: lineStart.y - config.nodeSpacing / 2 },
lineStart,
],
color
);
} else {
svgDrawLine(
svg,
[
{
x: fromBbox.left + fromBbox.width / 2,
y: fromBbox.top + fromBbox.height,
},
{
x: fromBbox.left + fromBbox.width / 2,
y: fromBbox.top + config.nodeSpacing / 2,
},
{
x: toBbox.left + toBbox.width / 2,
y: toBbox.top - config.nodeSpacing / 2,
},
{
x: toBbox.left + toBbox.width / 2,
y: toBbox.top,
},
],
color
);
}
break;
}
}
const drawText = (txt) => {
const svgLabel = document.createElementNS('http://www.w3.org/2000/svg', 'text');
// svgLabel.setAttribute('style', style.replace('color:', 'fill:'));
let rows = [];
if (typeof txt === 'string') {
rows = txt.split(/\\n|\n|<br\s*\/?>/gi);
} else if (Array.isArray(txt)) {
rows = txt;
} else {
rows = [];
}
for (let j = 0; j < rows.length; j++) {
const tspan = document.createElementNS('http://www.w3.org/2000/svg', 'tspan');
tspan.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve');
tspan.setAttribute('dy', '1em');
tspan.setAttribute('x', '0');
tspan.setAttribute('class', 'row');
tspan.textContent = rows[j].trim();
svgLabel.appendChild(tspan);
}
/**
* @param svg
* @param selector
*/
function cloneNode(svg, selector) {
return svg.select(selector).node().cloneNode(true);
return svgLabel;
}
const drawCommits = (svg, commits, modifyGraph) => {
const gBullets = svg.append('g').attr('class', 'commit-bullets');
const gLabels = svg.append('g').attr('class', 'commit-labels');
let pos = 0;
const keys = Object.keys(commits);
const sortedKeys = keys.sort((a, b) => {
return commits[a].seq - commits[b].seq;
})
sortedKeys.forEach((key, index) => {
const commit = commits[key];
const y = branchPos[commit.branch].pos;
const x = pos + 10;
// Don't draw the commits now but calculate the positioning which is used by the branmch lines etc.
if (modifyGraph) {
let typeClass;
switch(commit.type) {
case commitType.NORMAL:
typeClass = 'commit-normal';
break;
case commitType.REVERSE:
typeClass = 'commit-reverse';
break;
case commitType.HIGHLIGHT:
typeClass = 'commit-highlight';
break;
case commitType.MERGE:
typeClass = 'commit-merge';
break;
default:
typeClass = 'commit-normal';
}
if (commit.type === commitType.HIGHLIGHT) {
const circle = gBullets.append('rect');
circle.attr('x', x-10);
circle.attr('y', y-10);
circle.attr('height', 20);
circle.attr('width', 20);
circle.attr('class', 'commit ' + commit.id + ' commit-highlight' + branchPos[commit.branch].index + ' ' + typeClass+'-outer');
gBullets.append('rect')
.attr('x', x-6)
.attr('y', y-6)
.attr('height', 12)
.attr('width', 12)
.attr('class', 'commit ' + commit.id + ' commit' + branchPos[commit.branch].index + ' ' + typeClass+'-inner');
} else {
const circle = gBullets.append('circle');
circle.attr('cx', x);
circle.attr('cy', y);
circle.attr('r', commit.type === commitType.MERGE ? 9:10);
circle.attr('class', 'commit ' + commit.id + ' commit' + branchPos[commit.branch].index);
if(commit.type === commitType.MERGE) {
const circle2 = gBullets.append('circle');
circle2.attr('cx', x);
circle2.attr('cy', y);
circle2.attr('r', 6);
circle2.attr('class', 'commit '+typeClass + ' ' + commit.id + ' commit' + branchPos[commit.branch].index);
}
if(commit.type === commitType.REVERSE) {
const cross = gBullets.append('path');
cross
.attr('d', `M ${x-5},${y-5}L${x+5},${y+5}M${x-5},${y+5}L${x+5},${y-5}`)
.attr('class', 'commit '+typeClass + ' ' + commit.id + ' commit' + branchPos[commit.branch].index);
}
}
}
commitPos[commit.id] = {x: pos + 10, y: y};
// The first iteration over the commits are for positioning purposes, this
// is required for drawing the lines. The circles and labels is drawn after the labels
// placing them on top of the lines.
if (modifyGraph) {
const px=4;
const py=2;
if(commit.type !== commitType.MERGE) {
const labelBkg = gLabels.insert('rect')
.attr('class', 'commit-label-bkg');
const text = gLabels.append('text')
.attr('x', pos)
.attr('y', y + 25)
.attr('class', 'commit-label')
.text(commit.id);
let bbox = text.node().getBBox();
// Now we have the label, lets position the background
labelBkg
.attr('x', pos + 10 - bbox.width / 2 - py)
.attr('y', y + 13.5)
.attr('width', bbox.width + 2 * py)
.attr('height', bbox.height + 2 * py);
text.attr('x', pos + 10 - bbox.width / 2);
}
if(commit.tag) {
const rect = gLabels.insert('polygon');
const hole = gLabels.append('circle');
const tag = gLabels.append('text')
// Note that we are delaying setting the x position until we know the width of the text
.attr('y', y - 16)
.attr('class', 'tag-label')
.text(commit.tag);
let tagBbox = tag.node().getBBox();
tag.attr('x', pos + 10 - tagBbox.width / 2);
const h2 = tagBbox.height/2
const ly = y - 19.2 ;
rect
.attr('class', 'tag-label-bkg')
.attr('points', `
${pos - tagBbox.width / 2 - px/2},${ly + py}
${pos - tagBbox.width / 2 - px/2},${ly - py}
${pos + 10 - tagBbox.width / 2 - px},${ly - h2 - py}
${pos + 10 + tagBbox.width / 2 + px},${ly - h2 - py}
${pos + 10 + tagBbox.width / 2 + px},${ly + h2 + py }
${pos + 10 - tagBbox.width / 2 - px},${ly + h2 + py}`);
hole
.attr('cx', pos - tagBbox.width / 2 + px/2)
.attr('cy', ly)
.attr('r', 1.5)
.attr('class', 'tag-hole');
}
}
pos +=50;
if(pos>maxPos) {
maxPos = pos;
}
});
}
/**
* Detect if there are other commits between commit1s x-position and commit2s x-position on the same branch as commit2.
* @param {*} commit1
* @param {*} commit2
* @returns
*/
const hasOverlappingCommits = (commit1, commit2, allCommits) => {
const commit1Pos = commitPos[commit2.id];
const commit2Pos = commitPos[commit1.id];
// Find commits on the same branch as commit2
const keys = Object.keys(allCommits);
const overlappingComits = keys.filter((key) => {
return allCommits[key].branch === commit2.branch && allCommits[key].seq > commit1.seq && allCommits[key].seq < commit2.seq
});
return overlappingComits.length > 0;
}
/**
*
*/
const findLane = (y1, y2, _depth) => {
const depth = _depth || 0;
const candidate = y1 + Math.abs(y1 - y2) / 2;
if(depth > 5) {
return candidate;
}
let ok = true;
for(let i = 0; i < lanes.length; i++) {
if(Math.abs(lanes[i] - candidate) < 10) {
ok = false;
}
}
if(ok) {
lanes.push(candidate);
return candidate;
}
const diff = Math.abs(y1 - y2);
return findLane(y1, y2-(diff/5), depth);
}
const drawArrow = (svg, commit1, commit2, allCommits) => {
const conf = getConfig();
const p1 = commitPos[commit1.id];
const p2 = commitPos[commit2.id];
const overlappingCommits = hasOverlappingCommits(commit1, commit2, allCommits);
log.debug('drawArrow', p1, p2, overlappingCommits, commit1.id, commit2.id);
let url = '';
if (conf.arrowMarkerAbsolute) {
url =
window.location.protocol +
'//' +
window.location.host +
window.location.pathname +
window.location.search;
url = url.replace(/\(/g, '\\(');
url = url.replace(/\)/g, '\\)');
}
let arc = '';
let arc2 = '';
let radius = 0;
let offset = 0
let colorClassNum = branchPos[commit2.branch].index
let lineDef;
if(overlappingCommits) {
arc = 'A 10 10, 0, 0, 0,';
arc2 = 'A 10 10, 0, 0, 1,';
radius = 10;
offset = 10;
// Figure out the color of the arrow,arrows going down take the color from the destination branch
colorClassNum = branchPos[commit2.branch].index;
const lineY = p1.y < p2.y ? findLane(p1.y, p2.y):findLane(p2.y, p1.y);
if(p1.y < p2.y) {
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${lineY-radius} ${arc} ${p1.x + offset} ${lineY} L ${p2.x-radius} ${lineY} ${arc2} ${p2.x} ${lineY+offset} L ${p2.x} ${p2.y}`;
} else {
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${lineY+radius} ${arc2} ${p1.x + offset} ${lineY} L ${p2.x-radius} ${lineY} ${arc} ${p2.x} ${lineY-offset} L ${p2.x} ${p2.y}`;
}
} else {
if(p1.y < p2.y) {
arc = 'A 20 20, 0, 0, 0,';
radius = 20;
offset = 20;
// Figure out the color of the arrow,arrows going down take the color from the destination branch
colorClassNum = branchPos[commit2.branch].index;
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y-radius} ${arc} ${p1.x + offset} ${p2.y} L ${p2.x} ${p2.y}`;
}
if(p1.y > p2.y) {
arc = 'A 20 20, 0, 0, 0,';
radius = 20;
offset = 20;
// Arrows going up take the color from the source branch
colorClassNum = branchPos[commit1.branch].index;
lineDef = `M ${p1.x} ${p1.y} L ${p2.x-radius} ${p1.y} ${arc} ${p2.x} ${p1.y-offset} L ${p2.x} ${p2.y}`;
}
if(p1.y === p2.y) {
colorClassNum = branchPos[commit1.branch].index
lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y-radius} ${arc} ${p1.x + offset} ${p2.y} L ${p2.x} ${p2.y}`;
}
}
const arrow = svg.append('path').attr('d', lineDef)
.attr('class', 'arrow arrow' + colorClassNum)
}
const drawArrows = (svg, commits) => {
const gArrows = svg.append('g').attr('class', 'commit-arrows');
let pos = 0;
const k = Object.keys(commits);
k.forEach((key, index) => {
const commit = commits[key];
if(commit.parents && commit.parents.length>0) {
commit.parents.forEach((parent) => {
drawArrow(gArrows, commits[parent], commit, commits);
});
}
});
}
/**
@@ -224,88 +381,41 @@ function cloneNode(svg, selector) {
* @param branches
* @param direction
*/
function renderCommitHistory(svg, commitid, branches, direction) {
let commit;
const numCommits = Object.keys(allCommitsDict).length;
if (typeof commitid === 'string') {
let cnt = 0;
do {
cnt++;
commit = allCommitsDict[commitid];
log.debug('in renderCommitHistory', commit.id, commit.seq);
if (svg.select('#node-' + commitid).size() > 0) {
return;
}
svg
.append(function () {
return cloneNode(svg, '#def-commit');
})
.attr('class', 'commit')
.attr('id', function () {
return 'node-' + commit.id;
})
.attr('transform', function () {
switch (direction) {
case 'LR':
return (
'translate(' +
(commit.seq * config.nodeSpacing + config.leftMargin) +
', ' +
branchNum * config.branchOffset +
')'
);
case 'BT':
return (
'translate(' +
(branchNum * config.branchOffset + config.leftMargin) +
', ' +
(numCommits - commit.seq) * config.nodeSpacing +
')'
);
}
})
.attr('fill', config.nodeFillColor)
.attr('stroke', config.nodeStrokeColor)
.attr('stroke-width', config.nodeStrokeWidth);
const drawBranches = (svg, branches) => {
const g = svg.append('g')
branches.forEach((branch, index) => {
const pos = branchPos[branch.name].pos;
const line = g.append('line');
line.attr('x1', 0);
line.attr('y1', pos);
line.attr('x2', maxPos);
line.attr('y2', pos);
line.attr('class', 'branch branch'+index)
let branch;
for (let branchName in branches) {
if (branches[branchName].commit === commit) {
branch = branches[branchName];
break;
}
}
if (branch) {
log.debug('found branch ', branch.name);
svg
.select('#node-' + commit.id + ' p')
.append('xhtml:span')
.attr('class', 'branch-label')
.text(branch.name + ', ');
}
svg
.select('#node-' + commit.id + ' p')
.append('xhtml:span')
.attr('class', 'commit-id')
.text(commit.id);
if (commit.message !== '' && direction === 'BT') {
svg
.select('#node-' + commit.id + ' p')
.append('xhtml:span')
.attr('class', 'commit-msg')
.text(', ' + commit.message);
}
commitid = commit.parent;
} while (commitid && allCommitsDict[commitid] && cnt < 1000);
}
lanes.push(pos);
// Create the actual text element
const labelElement = drawText(branch.name);
// Create outer g, edgeLabel, this will be positioned after graph layout
const bkg = g.insert('rect');
const branchLabel = g.insert('g').attr('class', 'branchLabel');
// Create inner g, label, this will be positioned now for centering the text
const label = branchLabel.insert('g').attr('class', 'label branch-label'+index);
label.node().appendChild(labelElement);
let bbox = labelElement.getBBox();
bkg.attr('class', 'branchLabelBkg label' + index)
.attr('rx', 4)
.attr('ry', 4)
.attr('x', -bbox.width -4)
.attr('y', -bbox.height / 2 +8 )
.attr('width', bbox.width + 18)
.attr('height', bbox.height + 4);
label.attr('transform', 'translate(' + (-bbox.width -14) + ', ' + (pos - bbox.height/2-1) + ')');
bkg.attr('transform', 'translate(' + -19 + ', ' + (pos - bbox.height/2) + ')');
})
if (Array.isArray(commitid)) {
log.debug('found merge commmit', commitid);
renderCommitHistory(svg, commitid[0], branches, direction);
branchNum++;
renderCommitHistory(svg, commitid[1], branches, direction);
branchNum--;
}
}
/**
@@ -314,77 +424,69 @@ function renderCommitHistory(svg, commitid, branches, direction) {
* @param direction
* @param branchColor
*/
function renderLines(svg, commit, direction, branchColor) {
branchColor = branchColor || 0;
let cnt = 0;
while (commit.seq > 0 && !commit.lineDrawn && cnt < 1000) {
cnt++;
if (typeof commit.parent === 'string') {
svgDrawLineForCommits(svg, commit.id, commit.parent, direction, branchColor);
commit.lineDrawn = true;
commit = allCommitsDict[commit.parent];
} else if (Array.isArray(commit.parent)) {
svgDrawLineForCommits(svg, commit.id, commit.parent[0], direction, branchColor);
svgDrawLineForCommits(svg, commit.id, commit.parent[1], direction, branchColor + 1);
renderLines(svg, allCommitsDict[commit.parent[1]], direction, branchColor + 1);
commit.lineDrawn = true;
commit = allCommitsDict[commit.parent[0]];
}
}
}
export const draw = function (txt, id, ver) {
try {
const parser = gitGraphParser.parser;
parser.yy = db;
parser.yy.clear();
const securityLevel = getConfig().securityLevel;
// Handle root and ocument for when rendering in sanbox mode
let sandboxElement;
if (securityLevel === 'sandbox') {
sandboxElement = select('#i' + id);
}
const root =
securityLevel === 'sandbox'
? select(sandboxElement.nodes()[0].contentDocument.body)
: select('body');
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
clear();
const conf = getConfig();
const config = conf.gitGraph;
// try {
const parser = gitGraphParser.parser;
parser.yy = db;
parser.yy.clear();
log.debug('in gitgraph renderer', txt + '\n', 'id:', id, ver);
// Parse the graph definition
parser.parse(txt + '\n');
// // Parse the graph definition
parser.parse(txt + '\n');
config = Object.assign(config, apiConfig, db.getOptions());
log.debug('effective options', config);
const direction = db.getDirection();
allCommitsDict = db.getCommits();
const branches = db.getBranchesAsObjArray();
if (direction === 'BT') {
config.nodeLabel.x = branches.length * config.branchOffset;
config.nodeLabel.width = '100%';
config.nodeLabel.y = -1 * 2 * config.nodeRadius;
}
const svg = root.select(`[id="${id}"]`);
svgCreateDefs(svg);
branchNum = 1;
for (let branch in branches) {
const v = branches[branch];
renderCommitHistory(svg, v.commit.id, branches, direction);
renderLines(svg, v.commit, direction);
branchNum++;
}
svg.attr('height', function () {
if (direction === 'BT') return Object.keys(allCommitsDict).length * config.nodeSpacing;
return (branches.length + 1) * config.branchOffset;
});
} catch (e) {
log.error('Error while rendering gitgraph');
log.error(e.message);
}
// config = Object.assign(config, apiConfig, db.getOptions());
const direction = db.getDirection();
allCommitsDict = db.getCommits();
const branches = db.getBranchesAsObjArray();
// Position branches vertically
let pos=0;
branches.forEach((branch, index) => {
branchPos[branch.name] = {pos, index};
pos+=50;
});
log.debug('brach pos ', branchPos);
log.debug('effective options', config, branches);
log.debug('commits', allCommitsDict);
const diagram = select(`[id="${id}"]`);
svgCreateDefs(diagram);
diagram
.append('defs')
.append('marker')
.attr('id', 'arrowhead')
.attr('refX',24)
.attr('refY', 10)
.attr('markerUnits', 'userSpaceOnUse')
.attr('markerWidth', 24)
.attr('markerHeight', 24)
.attr('orient', 'auto')
.append('path')
.attr('d', 'M 0 0 L 20 10 L 0 20 z'); // this is actual shape for arrowhead
drawCommits(diagram, allCommitsDict, false);
drawBranches(diagram, branches);
drawArrows(diagram, allCommitsDict);
drawCommits(diagram, allCommitsDict, true);
const padding = config.diagramPadding;
const svgBounds = diagram.node().getBBox();
const width = svgBounds.width + padding * 2;
const height = svgBounds.height + padding * 2;
configureSvgSize(diagram, height, width, conf.useMaxWidth);
const vBox = `${svgBounds.x - padding} ${svgBounds.y - padding} ${width} ${height}`;
// logger.debug(`viewBox ${vBox}`);
diagram.attr('viewBox', vBox);
};
export default {
setConf,
draw,
};

View File

@@ -0,0 +1,21 @@
import { getConfig } from '../../config';
export default (dir, _branches, _commits) => { // eslint-disable-line
const config = getConfig().gitGraph;
const branches = [];
const commits = [];
for (let i = 0; i < _branches.length; i++) {
const branch = Object.assign({}, _branches[i]);
if (dir === 'TB' || dir === 'BT') {
branch.x = config.branchOffset * i;
branch.y = -1;
} else {
branch.y = config.branchOffset * i;
branch.x = -1;
}
branches.push(branch);
}
return { branches, commits };
};

196
src/diagrams/git/mockDb.js Normal file
View File

@@ -0,0 +1,196 @@
export const getDirection = () => 'LR';
export const getCommits = () => {
return {
'0000001': {
id: '0000001',
seq: 1,
message: '',
branch: 'master',
parents: null,
tag: 'v0.1',
commitType: 'normal',
note: null,
},
'0000002': {
id: '0000002',
seq: 2,
message: '',
branch: 'develop',
parents: ['0000001'],
tag: null,
commitType: 'normal',
note: null,
},
'0000003': {
id: '0000003',
seq: 3,
message: '',
branch: 'featureB',
parents: ['0000002'],
tag: null,
commitType: 'normal',
note: null,
},
'0000004': {
id: '0000004',
seq: 4,
message: '',
branch: 'hotfix',
parents: ['0000001'],
tag: null,
commitType: 'normal',
note: null,
},
'0000005': {
id: '0000005',
seq: 5,
message: '',
branch: 'develop',
parents: ['0000002'],
tag: null,
commitType: 'normal',
note: null,
},
'0000006': {
id: '0000006',
seq: 6,
message: '',
branch: 'featureB',
parents: ['0000003'],
tag: null,
commitType: 'normal',
note: null,
},
'0000007': {
id: '0000007',
seq: 7,
message: '',
branch: 'master',
parents: ['0000004'],
tag: 'v0.2',
commitType: 'normal',
note: null,
},
'0000008': {
id: '0000008',
seq: 8,
message: '',
branch: 'featureB',
parents: ['0000006'],
tag: null,
commitType: 'normal',
note: null,
},
'0000009': {
id: '0000009',
seq: 9,
message: '',
branch: 'featureA',
parents: ['0000005'],
tag: null,
commitType: 'normal',
note: null,
},
'0000010': {
id: '0000010',
seq: 10,
message: '',
branch: 'develop',
parents: ['0000004', '0000005'],
tag: null,
commitType: 'normal',
note: null,
},
'0000011': {
id: '0000011',
seq: 11,
message: '',
branch: 'featureA',
parents: ['0000009'],
tag: null,
commitType: 'normal',
note: '',
},
'0000012': {
id: '0000012',
seq: 12,
message: '',
branch: 'featureB',
parents: ['0000008'],
tag: null,
commitType: 'normal',
note: null,
},
'0000013': {
id: '0000013',
seq: 13,
message: '',
branch: 'develop',
parents: ['0000010', '0000011'],
tag: null,
commitType: 'normal',
note: null,
},
'0000014': {
id: '0000014',
seq: 14,
message: '',
branch: 'release',
parents: ['0000013'],
tag: null,
commitType: 'normal',
note: null,
},
'0000015': {
id: '0000015',
seq: 15,
message: '',
branch: 'master',
parents: ['0000007'],
tag: null,
commitType: 'normal',
note: null,
},
'0000016': {
id: '0000016',
seq: 16,
message: '',
branch: 'release',
parents: ['0000014', '0000015'],
tag: 'v1.0',
commitType: 'normal',
note: null,
},
'0000017': {
id: '0000017',
seq: 17,
message: '',
branch: 'develop',
parents: ['0000013', '0000016'],
tag: null,
commitType: 'normal',
note: null,
},
};
};
export const clear = () => {};
export const getBranchesAsObjArray = () => [
{
name: 'master',
},
{
name: 'hotfix',
},
{
name: 'release',
},
{
name: 'develop',
},
{
name: 'featureA',
},
{
name: 'featureB',
},
];

View File

@@ -0,0 +1,39 @@
commit
branch develop
checkout develop
commit
branch featureB
checkout featureB
commit
checkout master
branch hotfix
checkout hotfix
commit
checkout develop
commit
checkout featureB
commit
checkout master
merge hotfix
checkout featureB
commit
checkout develop
branch featureA
commit
checkout develop
merge hotfix
checkout featureA
commit
checkout featureB
commit
checkout develop
merge featureA
branch release
checkout release
commit
checkout master
commit
checkout release
merge master
checkout develop
merge release

View File

@@ -9,19 +9,35 @@
%x string
%x options
%x open_directive
%x type_directive
%x arg_directive
%x close_directive
%options case-insensitive
%%
(\r?\n)+ return 'NL';
%%
\%\%\{ { this.begin('open_directive'); return 'open_directive'; }
<open_directive>((?:(?!\}\%\%)[^:.])*) { this.begin('type_directive'); return 'type_directive'; }
<type_directive>":" { this.popState(); this.begin('arg_directive'); return ':'; }
<type_directive,arg_directive>\}\%\% { this.popState(); this.popState(); return 'close_directive'; }
<arg_directive>((?:(?!\}\%\%).|\n)*) return 'arg_directive';
(\r?\n)+ /*{console.log('New line');return 'NL';}*/ return 'NL';
\s+ /* skip all whitespace */
\#[^\n]* /* skip comments */
\%%[^\n]* /* skip comments */
"gitGraph" return 'GG';
"commit" return 'COMMIT';
"id:" return 'COMMIT_ID';
"type:" return 'COMMIT_TYPE';
"msg:" return 'COMMIT_MSG';
"NORMAL" return 'NORMAL';
"REVERSE" return 'REVERSE';
"HIGHLIGHT" return 'HIGHLIGHT';
"tag:" return 'COMMIT_TAG';
"branch" return 'BRANCH';
"merge" return 'MERGE';
"reset" return 'RESET';
// "reset" return 'RESET';
"checkout" return 'CHECKOUT';
"LR" return 'DIR';
"BT" return 'DIR';
@@ -45,7 +61,10 @@
%% /* language grammar */
start
: GG ':' document EOF{ return $3; }
: eol start
| directive start
| GG document EOF{ return $3; }
| GG ':' document EOF{ return $3; }
| GG DIR ':' document EOF {yy.setDirection($2); return $4;}
;
@@ -64,28 +83,144 @@ body
| body line {$1.push($2); $$=$1;}
;
line
: statement NL{$$ =$1}
: statement eol {$$ =$1}
| NL
;
statement
: COMMIT commit_arg {yy.commit($2)}
: commitStatement
| BRANCH ID {yy.branch($2)}
| CHECKOUT ID {yy.checkout($2)}
| MERGE ID {yy.merge($2)}
| RESET reset_arg {yy.reset($2)}
// | RESET reset_arg {yy.reset($2)}
;
commitStatement
: COMMIT commit_arg {yy.commit($2)}
| COMMIT COMMIT_TAG STR {yy.commit('','',yy.commitType.NORMAL,$3)}
| COMMIT COMMIT_TYPE commitType {yy.commit('','',$3,'')}
| COMMIT COMMIT_TAG STR COMMIT_TYPE commitType {yy.commit('','',$5,$3)}
| COMMIT COMMIT_TYPE commitType COMMIT_TAG STR {yy.commit('','',$3,$5)}
| COMMIT COMMIT_ID STR {yy.commit('',$3,yy.commitType.NORMAL,'')}
| COMMIT COMMIT_ID STR COMMIT_TAG STR {yy.commit('',$3,yy.commitType.NORMAL,$5)}
| COMMIT COMMIT_TAG STR COMMIT_ID STR {yy.commit('',$5,yy.commitType.NORMAL,$3)}
| COMMIT COMMIT_ID STR COMMIT_TYPE commitType {yy.commit('',$3,$5,'')}
| COMMIT COMMIT_TYPE commitType COMMIT_ID STR {yy.commit('',$5,$3,'')}
| COMMIT COMMIT_ID STR COMMIT_TYPE commitType COMMIT_TAG STR {yy.commit('',$3,$5,$7)}
| COMMIT COMMIT_ID STR COMMIT_TAG STR COMMIT_TYPE commitType {yy.commit('',$3,$7,$5)}
| COMMIT COMMIT_TYPE commitType COMMIT_ID STR COMMIT_TAG STR {yy.commit('',$5,$3,$7)}
| COMMIT COMMIT_TYPE commitType COMMIT_TAG STR COMMIT_ID STR {yy.commit('',$7,$3,$5)}
| COMMIT COMMIT_TAG STR COMMIT_TYPE commitType COMMIT_ID STR {yy.commit('',$7,$5,$3)}
| COMMIT COMMIT_TAG STR COMMIT_ID STR COMMIT_TYPE commitType {yy.commit('',$5,$7,$3)}
| COMMIT COMMIT_MSG STR {yy.commit($3,'',yy.commitType.NORMAL,'')}
| COMMIT COMMIT_TAG STR COMMIT_MSG STR {yy.commit($5,'',yy.commitType.NORMAL,$3)}
| COMMIT COMMIT_MSG STR COMMIT_TAG STR {yy.commit($3,'',yy.commitType.NORMAL,$5)}
| COMMIT COMMIT_MSG STR COMMIT_TYPE commitType {yy.commit($3,'',$5,'')}
| COMMIT COMMIT_TYPE commitType COMMIT_MSG STR {yy.commit($5,'',$3,'')}
| COMMIT COMMIT_ID STR COMMIT_MSG STR {yy.commit($5,$3,yy.commitType.NORMAL,'')}
| COMMIT COMMIT_MSG STR COMMIT_ID STR {yy.commit($3,$5,yy.commitType.NORMAL,'')}
| COMMIT COMMIT_MSG STR COMMIT_TYPE commitType COMMIT_TAG STR {yy.commit($3,'',$5,$7)}
| COMMIT COMMIT_MSG STR COMMIT_TAG STR COMMIT_TYPE commitType {yy.commit($3,'',$7,$5)}
| COMMIT COMMIT_TYPE commitType COMMIT_MSG STR COMMIT_TAG STR {yy.commit($5,'',$3,$7)}
| COMMIT COMMIT_TYPE commitType COMMIT_TAG STR COMMIT_MSG STR {yy.commit($7,'',$3,$5)}
| COMMIT COMMIT_TAG STR COMMIT_TYPE commitType COMMIT_MSG STR {yy.commit($7,'',$5,$3)}
| COMMIT COMMIT_TAG STR COMMIT_MSG STR COMMIT_TYPE commitType {yy.commit($5,'',$7,$3)}
| COMMIT COMMIT_MSG STR COMMIT_TYPE commitType COMMIT_ID STR {yy.commit($3,$7,$5,'')}
| COMMIT COMMIT_MSG STR COMMIT_ID STR COMMIT_TYPE commitType {yy.commit($3,$5,$7,'')}
| COMMIT COMMIT_TYPE commitType COMMIT_MSG STR COMMIT_ID STR {yy.commit($5,$7,$3,'')}
| COMMIT COMMIT_TYPE commitType COMMIT_ID STR COMMIT_MSG STR {yy.commit($7,$5,$3,'')}
| COMMIT COMMIT_ID STR COMMIT_TYPE commitType COMMIT_MSG STR {yy.commit($7,$3,$5,'')}
| COMMIT COMMIT_ID STR COMMIT_MSG STR COMMIT_TYPE commitType {yy.commit($5,$3,$7,'')}
| COMMIT COMMIT_MSG STR COMMIT_TAG STR COMMIT_ID STR {yy.commit($3,$7,yy.commitType.NORMAL,$5)}
| COMMIT COMMIT_MSG STR COMMIT_ID STR COMMIT_TAG STR {yy.commit($3,$5,yy.commitType.NORMAL,$7)}
| COMMIT COMMIT_TAG STR COMMIT_MSG STR COMMIT_ID STR {yy.commit($5,$7,yy.commitType.NORMAL,$3)}
| COMMIT COMMIT_TAG STR COMMIT_ID STR COMMIT_MSG STR {yy.commit($7,$5,yy.commitType.NORMAL,$3)}
| COMMIT COMMIT_ID STR COMMIT_TAG STR COMMIT_MSG STR {yy.commit($7,$3,yy.commitType.NORMAL,$5)}
| COMMIT COMMIT_ID STR COMMIT_MSG STR COMMIT_TAG STR {yy.commit($5,$3,yy.commitType.NORMAL,$7)}
| COMMIT COMMIT_MSG STR COMMIT_ID STR COMMIT_TYPE commitType COMMIT_TAG STR {yy.commit($3,$5,$7,$9)}
| COMMIT COMMIT_MSG STR COMMIT_ID STR COMMIT_TAG STR COMMIT_TYPE commitType {yy.commit($3,$5,$9,$7)}
| COMMIT COMMIT_MSG STR COMMIT_TYPE commitType COMMIT_ID STR COMMIT_TAG STR {yy.commit($3,$7,$5,$9)}
| COMMIT COMMIT_MSG STR COMMIT_TYPE commitType COMMIT_TAG STR COMMIT_ID STR {yy.commit($3,$9,$5,$7)}
| COMMIT COMMIT_MSG STR COMMIT_TAG STR COMMIT_ID STR COMMIT_TYPE commitType {yy.commit($3,$7,$9,$5)}
| COMMIT COMMIT_MSG STR COMMIT_TAG STR COMMIT_TYPE commitType COMMIT_ID STR {yy.commit($3,$9,$7,$5)}
| COMMIT COMMIT_ID STR COMMIT_MSG STR COMMIT_TYPE commitType COMMIT_TAG STR {yy.commit($5,$3,$7,$9)}
| COMMIT COMMIT_ID STR COMMIT_MSG STR COMMIT_TAG STR COMMIT_TYPE commitType {yy.commit($5,$3,$9,$7)}
| COMMIT COMMIT_ID STR COMMIT_TYPE commitType COMMIT_MSG STR COMMIT_TAG STR {yy.commit($7,$3,$5,$9)}
| COMMIT COMMIT_ID STR COMMIT_TYPE commitType COMMIT_TAG STR COMMIT_MSG STR {yy.commit($9,$3,$5,$7)}
| COMMIT COMMIT_ID STR COMMIT_TAG STR COMMIT_MSG STR COMMIT_TYPE commitType {yy.commit($7,$3,$9,$5)}
| COMMIT COMMIT_ID STR COMMIT_TAG STR COMMIT_TYPE commitType COMMIT_MSG STR {yy.commit($9,$3,$7,$5)}
| COMMIT COMMIT_TAG STR COMMIT_ID STR COMMIT_TYPE commitType COMMIT_MSG STR {yy.commit($9,$5,$7,$3)}
| COMMIT COMMIT_TAG STR COMMIT_ID STR COMMIT_MSG STR COMMIT_TYPE commitType {yy.commit($7,$5,$9,$3)}
| COMMIT COMMIT_TAG STR COMMIT_TYPE commitType COMMIT_ID STR COMMIT_MSG STR {yy.commit($9,$7,$5,$3)}
| COMMIT COMMIT_TAG STR COMMIT_TYPE commitType COMMIT_MSG STR COMMIT_ID STR {yy.commit($7,$9,$5,$3)}
| COMMIT COMMIT_TAG STR COMMIT_MSG STR COMMIT_ID STR COMMIT_TYPE commitType {yy.commit($5,$7,$9,$3)}
| COMMIT COMMIT_TAG STR COMMIT_MSG STR COMMIT_TYPE commitType COMMIT_ID STR {yy.commit($5,$9,$7,$3)}
| COMMIT COMMIT_TYPE commitType COMMIT_ID STR COMMIT_MSG STR COMMIT_TAG STR {yy.commit($7,$5,$3,$9)}
| COMMIT COMMIT_TYPE commitType COMMIT_ID STR COMMIT_TAG STR COMMIT_MSG STR {yy.commit($9,$5,$3,$7)}
| COMMIT COMMIT_TYPE commitType COMMIT_TAG STR COMMIT_MSG STR COMMIT_ID STR {yy.commit($7,$9,$3,$5)}
| COMMIT COMMIT_TYPE commitType COMMIT_TAG STR COMMIT_ID STR COMMIT_MSG STR {yy.commit($9,$7,$3,$5)}
| COMMIT COMMIT_TYPE commitType COMMIT_MSG STR COMMIT_ID STR COMMIT_TAG STR {yy.commit($5,$7,$3,$9)}
| COMMIT COMMIT_TYPE commitType COMMIT_MSG STR COMMIT_TAG STR COMMIT_ID STR {yy.commit($5,$9,$3,$7)}
// | COMMIT COMMIT_ID STR {yy.commit('',$3,yy.commitType.NORMAL,'')}
// | COMMIT COMMIT_TYPE commitType {yy.commit('','',$3,'')}
// | COMMIT COMMIT_TAG STR {yy.commit('','',yy.commitType.NORMAL,$3)}
// | COMMIT COMMIT_MSG STR {yy.commit($3,'',yy.commitType.NORMAL,'')}
// | COMMIT COMMIT_TAG STR COMMIT_TYPE commitType {yy.commit('','',$5,$3)}
// | COMMIT COMMIT_TYPE commitType COMMIT_TAG STR {yy.commit('','',$3,$5)}
// | COMMIT COMMIT_ID STR COMMIT_TYPE commitType {yy.commit('',$3,$5,'')}
// | COMMIT COMMIT_ID STR COMMIT_TAG STR {yy.commit('',$3,yy.commitType.NORMAL,$5)}
// | COMMIT COMMIT_ID STR COMMIT_TYPE commitType COMMIT_TAG STR {yy.commit('',$3,$5,$7)}
// | COMMIT COMMIT_ID STR COMMIT_TAG STR COMMIT_TYPE commitType {yy.commit('',$3,$7,$5)}
;
commit_arg
: /* empty */ {$$ = ""}
| STR {$$=$1}
;
commitType
: NORMAL { $$=yy.commitType.NORMAL;}
| REVERSE { $$=yy.commitType.REVERSE;}
| HIGHLIGHT { $$=yy.commitType.HIGHLIGHT;}
;
reset_arg
: 'HEAD' reset_parents{$$ = $1+ ":" + $2 }
| ID reset_parents{$$ = $1+ ":" + yy.count; yy.count = 0}
;
reset_parents
: /* empty */ {yy.count = 0}
| CARET reset_parents { yy.count += 1 }
;
directive
: openDirective typeDirective closeDirective
| openDirective typeDirective ':' argDirective closeDirective
;
openDirective
: open_directive { yy.parseDirective('%%{', 'open_directive'); }
;
typeDirective
: type_directive { yy.parseDirective($1, 'type_directive'); }
;
argDirective
: arg_directive { $1 = $1.trim().replace(/'/g, '"'); yy.parseDirective($1, 'arg_directive'); }
;
closeDirective
: close_directive { yy.parseDirective('}%%', 'close_directive', 'gitGraph'); }
;
eol
: NL
| ';'
| EOF
;
// reset_arg
// : 'HEAD' reset_parents{$$ = $1+ ":" + $2 }
// | ID reset_parents{$$ = $1+ ":" + yy.count; yy.count = 0}
// ;
// reset_parents
// : /* empty */ {yy.count = 0}
// | CARET reset_parents { yy.count += 1 }
// ;

View File

@@ -1,4 +1,4 @@
const getStyles = () =>
const getStyles = (options) =>
`
.commit-id,
.commit-msg,
@@ -8,6 +8,48 @@ const getStyles = () =>
font-family: 'trebuchet ms', verdana, arial, sans-serif;
font-family: var(--mermaid-font-family);
}
${[0, 1, 2, 3, 4, 5, 6, 7]
.map(
(i) =>
`
.branch-label${i} { fill: ${options['gitBranchLabel' + i]}; }
.commit${i} { stroke: ${options['git' + i]}; fill: ${options['git' + i]}; }
.commit-highlight${i} { stroke: ${options['gitInv' + i]}; fill: ${options['gitInv' + i]}; }
.label${i} { fill: ${options['git' + i]}; }
.arrow${i} { stroke: ${options['git' + i]}; }
`
)
.join('\n')}
.branch {
stroke-width: 1;
stroke: ${options.lineColor};
stroke-dasharray: 2;
}
.commit-label { font-size: 10px; fill: ${options.commitLabelColor};}
.commit-label-bkg { font-size: 10px; fill: ${options.commitLabelBackground}; opacity: 0.5; }
.tag-label { font-size: 10px; fill: ${options.tagLabelColor};}
.tag-label-bkg { fill: ${options.tagLabelBackground}; stroke: ${options.tagLabelBorder}; }
.tag-hole { fill: ${options.textColor}; }
.commit-merge {
stroke: ${options.primaryColor};
fill: ${options.primaryColor};
}
.commit-reverse {
stroke: ${options.primaryColor};
fill: ${options.primaryColor};
stroke-width: 3;
}
.commit-highlight-outer {
}
.commit-highlight-inner {
stroke: ${options.primaryColor};
fill: ${options.primaryColor};
}
.arrow { stroke-width: 8; stroke-linecap: round; fill: none}
}
`;
export default getStyles;

View File

@@ -1,48 +1,48 @@
/** mermaid
* https://knsv.github.io/mermaid
* (c) 2015 Knut Sveidqvist
* MIT license.
*/
%lex
%options case-insensitive
%{
// Pre-lexer code can go here
%}
%%
"info" return 'info' ;
[\s\n\r]+ return 'NL' ;
[\s]+ return 'space';
"showInfo" return 'showInfo';
<<EOF>> return 'EOF' ;
. return 'TXT' ;
/lex
%start start
%% /* language grammar */
start
// %{ : info document 'EOF' { return yy; } }
: info document 'EOF' { return yy; }
;
document
: /* empty */
| document line
;
line
: statement { }
| 'NL'
;
statement
: showInfo { yy.setInfo(true); }
;
%%
/** mermaid
* https://knsv.github.io/mermaid
* (c) 2015 Knut Sveidqvist
* MIT license.
*/
%lex
%options case-insensitive
%{
// Pre-lexer code can go here
%}
%%
"info" return 'info' ;
[\s\n\r]+ return 'NL' ;
[\s]+ return 'space';
"showInfo" return 'showInfo';
<<EOF>> return 'EOF' ;
. return 'TXT' ;
/lex
%start start
%% /* language grammar */
start
// %{ : info document 'EOF' { return yy; } }
: info document 'EOF' { return yy; }
;
document
: /* empty */
| document line
;
line
: statement { }
| 'NL'
;
statement
: showInfo { yy.setInfo(true); }
;
%%

View File

@@ -1,3 +1,3 @@
const getStyles = () => ``;
export default getStyles;
const getStyles = () => ``;
export default getStyles;

View File

@@ -33,7 +33,7 @@
\%%(?!\{)[^\n]* /* skip comments */
[^\}]\%\%[^\n]* /* skip comments */
"participant" { this.begin('ID'); return 'participant'; }
"actor" { this.begin('ID'); return 'participant_actor'; }
"actor" { this.begin('ID'); return 'participant_actor'; }
<ID>[^\->:\n,;]+?(?=((?!\n)\s)+"as"(?!\n)\s|[#\n;]|$) { yytext = yytext.trim(); this.begin('ALIAS'); return 'ACTOR'; }
<ALIAS>"as" { this.popState(); this.popState(); this.begin('LINE'); return 'AS'; }
<ALIAS>(?:) { this.popState(); this.popState(); return 'NEWLINE'; }
@@ -56,7 +56,9 @@
"note" return 'note';
"activate" { this.begin('ID'); return 'activate'; }
"deactivate" { this.begin('ID'); return 'deactivate'; }
"title" return 'title';
"title"\s[^#\n;]+ return 'title';
"title:"\s[^#\n;]+ return 'legacy_title';
"accDescription"\s[^#\n;]+ return 'accDescription';
"sequenceDiagram" return 'SD';
"autonumber" return 'autonumber';
"," return ',';
@@ -121,7 +123,9 @@ statement
| link_statement 'NEWLINE'
| properties_statement 'NEWLINE'
| details_statement 'NEWLINE'
| title text2 'NEWLINE' {$$=[{type:'setTitle', text:$2}]}
| title {yy.setTitle($1.substring(6));$$=$1.substring(6);}
| legacy_title {yy.setTitle($1.substring(7));$$=$1.substring(7);}
| accDescription {yy.setAccDescription($1.substring(15));$$=$1.substring(15);}
| 'loop' restOfLine document end
{
$3.unshift({type: 'loopStart', loopText:yy.parseMessage($2), signalType: yy.LINETYPE.LOOP_START});

View File

@@ -8,7 +8,7 @@ let actors = {};
let messages = [];
const notes = [];
let title = '';
let titleWrapped = false;
let description = '';
let sequenceNumbersEnabled = false;
let wrapEnabled = false;
@@ -122,9 +122,6 @@ export const getActorKeys = function () {
export const getTitle = function () {
return title;
};
export const getTitleWrapped = function () {
return titleWrapped;
};
export const enableSequenceNumbers = function () {
sequenceNumbersEnabled = true;
};
@@ -139,6 +136,7 @@ export const autoWrap = () => wrapEnabled;
export const clear = function () {
actors = {};
messages = [];
sequenceNumbersEnabled = false;
};
export const parseMessage = function (str) {
@@ -323,9 +321,9 @@ export const getActorProperty = function (actor, key) {
return undefined;
};
export const setTitle = function (titleWrap) {
title = titleWrap.text;
titleWrapped = (titleWrap.wrap === undefined && autoWrap()) || !!titleWrap.wrap;
export const setTitle = function (txt) {
let sanitizedText = sanitizeText(txt, configApi.getConfig());
title = sanitizedText;
};
export const apply = function (param) {
@@ -408,6 +406,15 @@ export const apply = function (param) {
}
};
const setAccDescription = function (description_lex) {
let sanitizedText = sanitizeText(description_lex, configApi.getConfig());
description = sanitizedText;
};
const getAccDescription = function () {
return description;
};
export default {
addActor,
addMessage,
@@ -427,7 +434,6 @@ export default {
getTitle,
parseDirective,
getConfig: () => configApi.getConfig().sequence,
getTitleWrapped,
clear,
parseMessage,
LINETYPE,
@@ -436,4 +442,6 @@ export default {
addNote,
setTitle,
apply,
setAccDescription,
getAccDescription,
};

View File

@@ -60,7 +60,7 @@ Bob-->Alice: I am good thanks!`;
mermaidAPI.parse(str);
expect(parser.yy.showSequenceNumbers()).toBe(true);
});
it('it should handle a sequenceDiagram definition with a title', function () {
it('it should handle a sequenceDiagram definition with a title:', function () {
const str = `
sequenceDiagram
title: Diagram Title
@@ -73,6 +73,7 @@ Bob-->Alice: I am good thanks!`;
expect(actors.Alice.description).toBe('Alice');
actors.Bob.description = 'Bob';
expect(parser.yy.getAccDescription()).toBe('');
const messages = parser.yy.getMessages();
const title = parser.yy.getTitle();
@@ -81,6 +82,52 @@ Bob-->Alice: I am good thanks!`;
expect(messages[2].from).toBe('Bob');
expect(title).toBe('Diagram Title');
});
it('it should handle a sequenceDiagram definition with a title without a :', function () {
const str = `
sequenceDiagram
title Diagram Title
Alice->Bob:Hello Bob, how are you?
Note right of Bob: Bob thinks
Bob-->Alice: I am good thanks!`;
mermaidAPI.parse(str);
const actors = parser.yy.getActors();
expect(actors.Alice.description).toBe('Alice');
actors.Bob.description = 'Bob';
expect(parser.yy.getAccDescription()).toBe('');
const messages = parser.yy.getMessages();
const title = parser.yy.getTitle();
expect(messages.length).toBe(3);
expect(messages[0].from).toBe('Alice');
expect(messages[2].from).toBe('Bob');
expect(title).toBe('Diagram Title');
});
it('it should handle a sequenceDiagram definition with a accDescription', function () {
const str = `
sequenceDiagram
accDescription Accessibility Description
Alice->Bob:Hello Bob, how are you?
Note right of Bob: Bob thinks
Bob-->Alice: I am good thanks!`;
mermaidAPI.parse(str);
const actors = parser.yy.getActors();
expect(actors.Alice.description).toBe('Alice');
actors.Bob.description = 'Bob';
expect(parser.yy.getAccDescription()).toBe('Accessibility Description');
const messages = parser.yy.getMessages();
const title = parser.yy.getTitle();
expect(messages.length).toBe(3);
expect(messages[0].from).toBe('Alice');
expect(messages[2].from).toBe('Bob');
});
it('it should space in actor names', function () {
const str = `
sequenceDiagram
@@ -1586,6 +1633,7 @@ participant Alice
renderer.bounds.init();
mermaidAPI.parse(str);
renderer.draw(str, 'tst');
const { bounds, models } = renderer.bounds.getBounds();
@@ -1619,4 +1667,24 @@ participant Alice
models.lastActor().y + models.lastActor().height + mermaid.sequence.boxMargin
);
});
it('it should hide sequence numbers when autonumber is removed when autonumber is enabled', function () {
const str1 = `
sequenceDiagram
autonumber
Alice->Bob:Hello Bob, how are you?
Note right of Bob: Bob thinks
Bob-->Alice: I am good thanks!`;
mermaidAPI.parse(str1);
expect(parser.yy.showSequenceNumbers()).toBe(true);
const str2 = `
sequenceDiagram
Alice->Bob:Hello Bob, how are you?
Note right of Bob: Bob thinks
Bob-->Alice: I am good thanks!`;
mermaidAPI.parse(str2);
expect(parser.yy.showSequenceNumbers()).toBe(false);
});
});

View File

@@ -6,6 +6,7 @@ import common from '../common/common';
import sequenceDb from './sequenceDb';
import * as configApi from '../../config';
import utils, { assignWithDepth, configureSvgSize } from '../../utils';
import addSVGAccessibilityFields from '../../accessibility';
parser.yy = sequenceDb;
@@ -727,6 +728,7 @@ export const draw = function (text, id) {
log.error('error while drawing message', e);
}
}
// Increment sequence counter if msg.type is a line (and not another event like activation or note, etc)
if (
[
@@ -802,6 +804,8 @@ export const draw = function (text, id) {
' ' +
(height + extraVertForTitle)
);
addSVGAccessibilityFields(parser.yy, diagram, id);
log.debug(`models:`, bounds.models);
};

View File

@@ -1,88 +1,88 @@
/** mermaid
* https://mermaidjs.github.io/
* (c) 2015 Knut Sveidqvist
* MIT license.
*/
%lex
%options case-insensitive
// Directive states
%x open_directive type_directive arg_directive
%%
\%\%\{ { this.begin('open_directive'); return 'open_directive'; }
<open_directive>((?:(?!\}\%\%)[^:.])*) { this.begin('type_directive'); return 'type_directive'; }
<type_directive>":" { this.popState(); this.begin('arg_directive'); return ':'; }
<type_directive,arg_directive>\}\%\% { this.popState(); this.popState(); return 'close_directive'; }
<arg_directive>((?:(?!\}\%\%).|\n)*) return 'arg_directive';
\%%(?!\{)[^\n]* /* skip comments */
[^\}]\%\%[^\n]* /* skip comments */
[\n]+ return 'NEWLINE';
\s+ /* skip whitespace */
\#[^\n]* /* skip comments */
"journey" return 'journey';
"title"\s[^#\n;]+ return 'title';
"section"\s[^#:\n;]+ return 'section';
[^#:\n;]+ return 'taskName';
":"[^#\n;]+ return 'taskData';
":" return ':';
<<EOF>> return 'EOF';
. return 'INVALID';
/lex
%left '^'
%start start
%% /* language grammar */
start
: journey document 'EOF' { return $2; }
| directive start
;
document
: /* empty */ { $$ = [] }
| document line {$1.push($2);$$ = $1}
;
line
: SPACE statement { $$ = $2 }
| statement { $$ = $1 }
| NEWLINE { $$=[];}
| EOF { $$=[];}
;
directive
: openDirective typeDirective closeDirective 'NEWLINE'
| openDirective typeDirective ':' argDirective closeDirective 'NEWLINE'
;
statement
: title {yy.setTitle($1.substr(6));$$=$1.substr(6);}
| section {yy.addSection($1.substr(8));$$=$1.substr(8);}
| taskName taskData {yy.addTask($1, $2);$$='task';}
| directive
;
openDirective
: open_directive { yy.parseDirective('%%{', 'open_directive'); }
;
typeDirective
: type_directive { yy.parseDirective($1, 'type_directive'); }
;
argDirective
: arg_directive { $1 = $1.trim().replace(/'/g, '"'); yy.parseDirective($1, 'arg_directive'); }
;
closeDirective
: close_directive { yy.parseDirective('}%%', 'close_directive', 'journey'); }
;
%%
/** mermaid
* https://mermaidjs.github.io/
* (c) 2015 Knut Sveidqvist
* MIT license.
*/
%lex
%options case-insensitive
// Directive states
%x open_directive type_directive arg_directive
%%
\%\%\{ { this.begin('open_directive'); return 'open_directive'; }
<open_directive>((?:(?!\}\%\%)[^:.])*) { this.begin('type_directive'); return 'type_directive'; }
<type_directive>":" { this.popState(); this.begin('arg_directive'); return ':'; }
<type_directive,arg_directive>\}\%\% { this.popState(); this.popState(); return 'close_directive'; }
<arg_directive>((?:(?!\}\%\%).|\n)*) return 'arg_directive';
\%%(?!\{)[^\n]* /* skip comments */
[^\}]\%\%[^\n]* /* skip comments */
[\n]+ return 'NEWLINE';
\s+ /* skip whitespace */
\#[^\n]* /* skip comments */
"journey" return 'journey';
"title"\s[^#\n;]+ return 'title';
"section"\s[^#:\n;]+ return 'section';
[^#:\n;]+ return 'taskName';
":"[^#\n;]+ return 'taskData';
":" return ':';
<<EOF>> return 'EOF';
. return 'INVALID';
/lex
%left '^'
%start start
%% /* language grammar */
start
: journey document 'EOF' { return $2; }
| directive start
;
document
: /* empty */ { $$ = [] }
| document line {$1.push($2);$$ = $1}
;
line
: SPACE statement { $$ = $2 }
| statement { $$ = $1 }
| NEWLINE { $$=[];}
| EOF { $$=[];}
;
directive
: openDirective typeDirective closeDirective 'NEWLINE'
| openDirective typeDirective ':' argDirective closeDirective 'NEWLINE'
;
statement
: title {yy.setTitle($1.substr(6));$$=$1.substr(6);}
| section {yy.addSection($1.substr(8));$$=$1.substr(8);}
| taskName taskData {yy.addTask($1, $2);$$='task';}
| directive
;
openDirective
: open_directive { yy.parseDirective('%%{', 'open_directive'); }
;
typeDirective
: type_directive { yy.parseDirective($1, 'type_directive'); }
;
argDirective
: arg_directive { $1 = $1.trim().replace(/'/g, '"'); yy.parseDirective($1, 'arg_directive'); }
;
closeDirective
: close_directive { yy.parseDirective('}%%', 'close_directive', 'journey'); }
;
%%

View File

@@ -2,7 +2,7 @@ import moment from 'moment-mini';
/** @typedef {'debug' | 'info' | 'warn' | 'error' | 'fatal'} LogLevel A log level */
/** @type {object<LogLevel, number>} */
/** @type {Object<LogLevel, number>} */
export const LEVELS = {
debug: 1,
info: 2,

8
src/mermaidAPI.js Executable file → Normal file
View File

@@ -94,6 +94,7 @@ function parse(text) {
parser.parser.yy = flowDb;
break;
case 'sequence':
sequenceDb.clear();
parser = sequenceParser;
parser.parser.yy = sequenceDb;
break;
@@ -422,8 +423,8 @@ const render = function (id, _txt, cb, container) {
try {
switch (graphType) {
case 'git':
cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
gitGraphRenderer.setConf(cnf.git);
// cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
//gitGraphRenderer.setConf(cnf.git);
gitGraphRenderer.draw(txt, id, false);
break;
case 'flowchart':
@@ -643,7 +644,8 @@ const handleDirective = function (p, directive, type) {
/** @param {any} conf */
function updateRendererConfigs(conf) {
// Todo remove, all diagrams should get config on demoand from the config object, no need for this
gitGraphRenderer.setConf(conf.git);
// gitGraphRenderer.setConf(conf.git); // Todo Remove all of these
flowRenderer.setConf(conf.flowchart);
flowRendererV2.setConf(conf.flowchart);
if (typeof conf['sequenceDiagram'] !== 'undefined') {

View File

@@ -113,6 +113,12 @@ describe('when using mermaidAPI and ', function () {
expect(mermaidAPI.defaultConfig['logLevel']).toBe(5);
});
});
describe('dompurify config', function () {
it('should allow dompurify config to be set', function () {
mermaidAPI.initialize({ dompurifyConfig: { ADD_ATTR: ['onclick'] } });
expect(mermaidAPI.getConfig().dompurifyConfig.ADD_ATTR).toEqual(['onclick']);
});
});
describe('checking validity of input ', function () {
it('it should throw for an invalid definiton', function () {
expect(() => mermaidAPI.parse('this is not a mermaid diagram definition')).toThrow();

View File

@@ -1,96 +1,96 @@
g.classGroup text {
fill: $nodeBorder;
stroke: none;
font-family: 'trebuchet ms', verdana, arial;
font-family: var(--mermaid-font-family);
font-size: 10px;
.title {
font-weight: bolder;
}
}
.divider {
stroke: $nodeBorder;
stroke-width: 1;
}
g.clickable {
cursor: pointer;
}
g.classGroup rect {
fill: $nodeBkg;
stroke: $nodeBorder;
}
g.classGroup line {
stroke: $nodeBorder;
stroke-width: 1;
}
.classLabel .box {
stroke: none;
stroke-width: 0;
fill: $nodeBkg;
opacity: 0.5;
}
.classLabel .label {
fill: $nodeBorder;
font-size: 10px;
}
.relation {
stroke: $nodeBorder;
stroke-width: 1;
fill: none;
}
.dashed-line{
stroke-dasharray: 3;
}
@mixin composition {
fill: $nodeBorder !important ;
stroke: $nodeBorder !important ;
stroke-width: 1;
}
#compositionStart, .composition {
@include composition;
}
#compositionEnd, .composition {
@include composition;
}
@mixin aggregation {
fill: $nodeBkg !important ;
stroke: $nodeBorder !important ;
stroke-width: 1;
}
#aggregationStart, .aggregation {
@include aggregation;
}
#aggregationEnd, .aggregation {
@include aggregation;
}
#dependencyStart, .dependency {
@include composition;
}
#dependencyEnd, .dependency {
@include composition;
}
#extensionStart , .extension{
@include composition;
}
#extensionEnd, .extension {
@include composition;
}
g.classGroup text {
fill: $nodeBorder;
stroke: none;
font-family: 'trebuchet ms', verdana, arial;
font-family: var(--mermaid-font-family);
font-size: 10px;
.title {
font-weight: bolder;
}
}
.divider {
stroke: $nodeBorder;
stroke-width: 1;
}
g.clickable {
cursor: pointer;
}
g.classGroup rect {
fill: $nodeBkg;
stroke: $nodeBorder;
}
g.classGroup line {
stroke: $nodeBorder;
stroke-width: 1;
}
.classLabel .box {
stroke: none;
stroke-width: 0;
fill: $nodeBkg;
opacity: 0.5;
}
.classLabel .label {
fill: $nodeBorder;
font-size: 10px;
}
.relation {
stroke: $nodeBorder;
stroke-width: 1;
fill: none;
}
.dashed-line{
stroke-dasharray: 3;
}
@mixin composition {
fill: $nodeBorder !important ;
stroke: $nodeBorder !important ;
stroke-width: 1;
}
#compositionStart, .composition {
@include composition;
}
#compositionEnd, .composition {
@include composition;
}
@mixin aggregation {
fill: $nodeBkg !important ;
stroke: $nodeBorder !important ;
stroke-width: 1;
}
#aggregationStart, .aggregation {
@include aggregation;
}
#aggregationEnd, .aggregation {
@include aggregation;
}
#dependencyStart, .dependency {
@include composition;
}
#dependencyEnd, .dependency {
@include composition;
}
#extensionStart , .extension{
@include composition;
}
#extensionEnd, .extension {
@include composition;
}

Some files were not shown because too many files have changed in this diff Show More