diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 000000000..7e54e3631 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +**/*.spec.js \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json index a1aed17d7..e04aeb4d6 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,7 +1,8 @@ { "env": { "browser": true, - "es6": true + "es6": true, + "node": true }, "parserOptions": { "ecmaFeatures": { @@ -10,7 +11,7 @@ }, "sourceType": "module" }, - "extends": ["prettier"], + "extends": ["prettier", "eslint:recommended"], "plugins": ["prettier"], "rules": { "prettier/prettier": ["error"] diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md new file mode 100644 index 000000000..4f7444aa8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question.md @@ -0,0 +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! diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 000000000..b8150e857 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,50 @@ +name: Build + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [10.x, 12.x] + steps: + - uses: actions/checkout@v1 + + - name: Setup Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + + - name: Install Yarn + run: npm i yarn --global + + - name: Cache Node Modules + uses: actions/cache@v1 + with: + path: .cache + key: ${{ runner.OS }}-build-${{ hashFiles('**/yarn.lock') }} + + - name: Install Packages + run: | + yarn config set cache-folder $GITHUB_WORKSPACE/.cache/yarn + yarn install --frozen-lockfile + env: + CYPRESS_CACHE_FOLDER: ../../.cache/Cypress + + - name: Run Build + run: yarn build + + - name: Run Unit Tests + run: | + yarn test --coverage + cat ./coverage/lcov.info | ./node_modules/.bin/coveralls + env: + COVERALLS_SERVICE_NAME: ${{ secrets.COVERALLS_SERVICE_NAME }} + COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} + + - name: Run E2E Tests + run: yarn e2e + env: + PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }} + CYPRESS_CACHE_FOLDER: .cache/Cypress diff --git a/.github/workflows/lock-closed-issue.yml b/.github/workflows/lock-closed-issue.yml new file mode 100644 index 000000000..ae74c03ef --- /dev/null +++ b/.github/workflows/lock-closed-issue.yml @@ -0,0 +1,13 @@ +name: Lock closed issue + +on: + issues: + types: [closed] + +jobs: + triage: + runs-on: ubuntu-latest + steps: + - uses: Dunning-Kruger/lock-issues@v1 + with: + repo-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/release-preview-publish.yml b/.github/workflows/release-preview-publish.yml new file mode 100644 index 000000000..b6c29b6a3 --- /dev/null +++ b/.github/workflows/release-preview-publish.yml @@ -0,0 +1,40 @@ +name: Publish release preview package + +on: + push: + branches: + - 'release/**' + +jobs: + publish: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [10.x] + steps: + - uses: actions/checkout@v1 + - name: Setup Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: Install Yarn + run: npm i yarn --global + + - name: Install Json + run: npm i json --global + + - name: Install Packages + run: yarn install + + - name: Publish + run: | + PREVIEW_VERSION=$(git rev-list --count --first-parent HEAD) + VERSION=$(echo ${{github.ref}} | tail -c +20)-preview.$PREVIEW_VERSION + echo $VERSION + npm version --no-git-tag-version --allow-same-version $VERSION + npm set //npm.pkg.github.com/:_authToken ${{ secrets.GITHUB_TOKEN }} + npm set registry https://npm.pkg.github.com/mermaid-js + json -I -f package.json -e 'this.name="@mermaid-js/mermaid"' # Package name needs to be set to a scoped one because GitHub registry requires this + json -I -f package.json -e 'this.repository="git://github.com/mermaid-js/mermaid"' # Repo url needs to have a specific format too + npm publish + diff --git a/.github/workflows/unlock-reopened-issues.yml b/.github/workflows/unlock-reopened-issues.yml new file mode 100644 index 000000000..09469ed8b --- /dev/null +++ b/.github/workflows/unlock-reopened-issues.yml @@ -0,0 +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 }}" diff --git a/.gitignore b/.gitignore index afceb98c0..498d78edc 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ node_modules/ coverage/ +.idea/ dist/*.js dist/*.map @@ -9,3 +10,5 @@ dist/*.map yarn-error.log .npmrc token + +package-lock.json diff --git a/.vscode/settings.json b/.vscode/settings.json index be2305cbc..ee8fae482 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,5 +4,5 @@ "typescript.validate.enable": false, "javascript.validate.enable": false, "editor.formatOnSave": false, - "standard.enable": true + "editor.snippetSuggestions": "top" } diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..6e1c65ae3 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,98 @@ +# Contributing + +So you want to help? That's great! + +![Image of happy people jumping with excitement](https://media.giphy.com/media/BlVnrxJgTGsUw/giphy.gif) + +Here are a few things to know to get you started on the right path. + +## Committing code + +We make all changes via pull requests. As we have many pull requests from developers new to mermaid, the current approach is to have *knsv, Knut Sveidqvist* as a main reviewer of changes and merging pull requests. More precisely like this: + +* Large changes reviewed by knsv or other developer asked to review by knsv +* Smaller low-risk changes like dependecies, documentation etc can be merged by active collaborators +* documentation (updates to the docs folder is also allowed via direct commits) + +To commit code, create a branch, let it start with the type like feature or bug followed by the issue number for reference and some describing text. + +One example: + +`feature/945_state_diagrams` + +Another: + +`bug/123_nasty_bug_branch` + +## Committing documentation + +Less strict here, it is ok to commit directly in the develop branch if you are a collaborator. + +## Branching + +Going forward we will use a git flow inspired approach to branching. So development is done in develop, to do the development in the develop. + +Once development is done we branch a release branch from develop for testing. + +Once the release happens we merge the release branch to master and kill the release branch. + +This means... **branch off your pull request from develop** + +## Content of a pull request + +A new feature has been born. Great! But without the steps below it might just ... fade away ... + +### **Add unit tests for the parsing part** + +This is important so that, if someone else does a change to the grammar that does not know about this great feature, gets notified early on when that change breaks the parser. Another important aspect is that without proper parsing tests refactoring is pretty much impossible. + +### **Add e2e tests** + +This tests the rendering and visual apearance of the diagram. This ensures that the rendering of that feature in the e2e will be reviewed in the release process going forward. Less chance that it breaks! + +To start working with the e2e tests, run `yarn dev` to start the dev server, after that start cypress by running `cypress open` in the mermaid folder. (Make sure you have path to cypress in order, the binary is located in node_modules/.bin). + +The rendering tests are very straightforward to create. There is a function imgSnapshotTest. This function takes a diagram in text form, the mermaid options and renders that diagram in cypress. + +When running in ci it will take a snapshot of the rendered diagram and compare it with the snapshot from last build and flag for review it if it differs. + +This is what a rendering test looks like: +``` + it('should render forks and joins', () => { + imgSnapshotTest( + ` + stateDiagram + state fork_state <<fork>> + [*] --> fork_state + fork_state --> State2 + fork_state --> State3 + + state join_state <<join>> + State2 --> join_state + State3 --> join_state + join_state --> State4 + State4 --> [*] + `, + { logLevel: 0 } + ); + cy.get('svg'); + }); + ``` + + +### **Add documentation for it** + +Finally, if it is not in the documentation, no one will know about it and then **no one will use it**. Wouldn't that be sad? With all the effort that was put into the feature? + +The docs are located in the docs folder and are ofc written in markdown. Just pick the right section and start typing. If you want to add to the structure as in adding a new section and new file you do that via the _navbar.md. + +The changes in master is reflected in http://mermaid-js.github.io/mermaid/ once released the updates are commited to https://mermaid-js.github.io/#/ + +## Last words + +Don't get daunted if it is hard in the beginning. We have a great community with only encouraging words. So if you get stuck, ask for help and hints in the slack forum. If you want to show off something good, show it off there. + +[Join our slack community if you want closer contact!](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE) + + +![Image of superhero wishing you good luck](https://media.giphy.com/media/l49JHz7kJvl6MCj3G/giphy.gif) diff --git a/README.md b/README.md index 44a6a2c19..4fe123369 100644 --- a/README.md +++ b/README.md @@ -1,94 +1,89 @@ -[![Build Status](https://travis-ci.org/knsv/mermaid.svg?branch=master)](https://travis-ci.org/knsv/mermaid) -[![Coverage Status](https://coveralls.io/repos/github/knsv/mermaid/badge.svg?branch=master)](https://coveralls.io/github/knsv/mermaid?branch=master) -[![Join the chat at https://gitter.im/knsv/mermaid](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/knsv/mermaid?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -[![This project is using Percy.io for visual regression testing.](https://percy.io/static/images/percy-badge.svg)](https://percy.io/Mermaid/mermaid) + +| :mega: :mega: :mega: | +| :----: | +| * If you're upgrading from a version __< v8.2.0__, there are [non-backward-compatible changes](http://mermaid-js.github.io/mermaid/#/usage?id=to-enable-click-event-and-tags-in-nodes) related to security issues. Default behaviour of the library might have changed for your implementation.| + -# 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) [![This project is using Percy.io for visual regression testing.](https://percy.io/static/images/percy-badge.svg)](https://percy.io/Mermaid/mermaid) + +__Generate diagrams, charts, graphs or flows from markdown-like text via javascript.__ +See our [documentation](http://mermaid-js.github.io/mermaid/) and start simplifying yours. Play in our [live editor](https://mermaidjs.github.io/mermaid-live-editor/) or jump straight to the [installation and usage](http://mermaid-js.github.io/mermaid/#/usage). + -## Special note regarding version 8.2 +:trophy: _"The most exciting use of technology"_ - [JS Open Source Awards (2019)](https://osawards.com/javascript/#nominees) -In version 8.2 a security improvement was introduced. A securityLevel configuration was introduced which sets the level of trust to be used on the parsed diagrams. - -* **`strict`**: (default) tags in text are encoded, click functionality is disabled -* `loose`: tags in text are allowed, click functionality is enabled - -⚠️ **Note** : This changes the default behaviour of mermaid so that after upgrade to 8.2, if the securityLevel is not configured, tags in flowcharts are encoded as tags and clicking is prohibited. - -If your application is taking responsibility for the diagram source security you can set the securityLevel accordingly. By doing this clicks and tags are again allowed. - -```javascript -mermaidAPI.initialize({ - securityLevel: 'loose' -}); -``` - -**🖖 Keep a steady pulse: mermaid needs more Collaborators [#866](https://github.com/knsv/mermaid/issues/866)** - -![banner](./img/header.png) - -Generation of diagrams and flowcharts from text in a similar manner as markdown. - -Ever wanted to simplify documentation and avoid heavy tools like Visio when explaining your code? - -This is why mermaid was born, a simple markdown-like script language for generating charts from text via javascript. - -**Mermaid was nominated and won the JS Open Source Awards (2019) in the category _The most exciting use of technology_!!! Thanks to all involved, people committing pull requests, people answering questions and special thanks to Tyler Long who is helping me maintain the project.** - -### Flowchart - -``` -graph TD; - A-->B; - A-->C; - B-->D; - C-->D; -``` -![Flowchart](./img/flow.png) - - -### Sequence diagram - -``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Flow
+ [docs - live editor] +
+graph TD
+A[Hard] -->|Text| B(Round)
+B --> C{Decision}
+C -->|One| D[Result 1]
+C -->|Two| E[Result 2]
+    
+ +
+ Sequence
+ [docs - live editor] +
 sequenceDiagram
-    participant Alice
-    participant Bob
-    Alice->>John: Hello John, how are you?
-    loop Healthcheck
-        John->>John: Fight against hypochondria
-    end
-    Note right of John: Rational thoughts 
prevail! - John-->>Alice: Great! - John->>Bob: How about you? - Bob-->>John: Jolly good! -``` -![Sequence diagram](./img/sequence.png) - - -### Gantt diagram - -``` +Alice->>John: Hello John, how are you? +loop Healthcheck + John->>John: Fight against hypochondria +end +Note right of John: Rational thoughts! +John-->>Alice: Great! +John->>Bob: How about you? +Bob-->>John: Jolly good! +
+ +
+ Gantt
+ [docs - live editor] +
 gantt
-dateFormat  YYYY-MM-DD
-title Adding GANTT diagram to mermaid
-excludes weekdays 2014-01-10
-
-section A section
-Completed task            :done,    des1, 2014-01-06,2014-01-08
-Active task               :active,  des2, 2014-01-09, 3d
-Future task               :         des3, after des2, 5d
-Future task2              :         des4, after des3, 5d
-```
-![Gantt diagram](./img/gantt.png)
-
-
-### Class diagram - :exclamation: experimental
-
-```
+section Section
+Completed :done,    des1, 2014-01-06,2014-01-08
+Active        :active,  des2, 2014-01-07, 3d
+Parallel 1   :         des3, after des1, 1d
+Parallel 2   :         des4, after des1, 1d
+Parallel 3   :         des5, after des3, 1d
+Parallel 4   :         des6, after des4, 1d
+    
+ +
+ Class
+ [docs - live editor] +
 classDiagram
-Class01 <|-- AveryLongClass : Cool
-Class03 *-- Class04
-Class05 o-- Class06
-Class07 .. Class08
+Class01 <|-- AveryLongClass : Cool
+<<interface>> Class01
 Class09 --> C2 : Where am i?
 Class09 --* C3
 Class09 --|> Class07
@@ -97,128 +92,84 @@ Class07 : Object[] elementData
 Class01 : size()
 Class01 : int chimp
 Class01 : int gorilla
-Class08 <--> C2: Cool label
-```
-![Class diagram](./img/class.png)
-
-
-### Git graph - :exclamation: experimental
-
-```
-gitGraph:
-options
-{
-    "nodeSpacing": 150,
-    "nodeRadius": 10
+class Class10 {
+  <<service>>
+  int id
+  size()
 }
-end
-commit
-branch newbranch
-checkout newbranch
-commit
-commit
-checkout master
-commit
-commit
-merge newbranch
+
+ +
+ State
+ [docs - live editor] +
+stateDiagram
+[*] --> Still
+Still --> [*]
+Still --> Moving
+Moving --> Still
+Moving --> Crash
+Crash --> [*]
+
+ +
+ Pie
+ [docs - live editor] +
+pie
+"Dogs" : 386
+"Cats" : 85
+"Rats" : 15 
+
+ +
+ Git
+ [experimental - live editor] +
Coming soon!
-``` +## Related projects -![Git graph](./img/git.png) +- [Command Line Interface](https://github.com/mermaid-js/mermaid.cli) +- [Live Editor](https://github.com/mermaid-js/mermaid-live-editor) +# Contributors [![Help wanted](https://img.shields.io/github/labels/mermaid-js/mermaid/Help%20wanted!)](https://github.com/mermaid-js/mermaid/issues?q=is%3Aissue+is%3Aopen+label%3A%22Help+wanted%21%22) [![Contributors](https://img.shields.io/github/contributors/mermaid-js/mermaid)](https://github.com/mermaid-js/mermaid/graphs/contributors) [![Commits](https://img.shields.io/github/commit-activity/m/mermaid-js/mermaid)](https://github.com/mermaid-js/mermaid/graphs/contributors) -## Installation +Mermaid is a growing community and is always accepting new contributors. There's a lot of different ways to help out and we're always looking for extra hands! Look at [this issue](https://github.com/mermaid-js/mermaid/issues/866) if you want to know where to start helping out. -### CDN +Detailed information about how to contribute can be found in the [contribution guide](CONTRIBUTING.md) - https://unpkg.com/mermaid@/dist/ +# Appreciation +A quick note from Knut Sveidqvist: +>*Many thanks to the [d3](http://d3js.org/) and [dagre-d3](https://github.com/cpettitt/dagre-d3) projects for providing the graphical layout and drawing libraries!* +>*Thanks also to the [js-sequence-diagram](http://bramp.github.io/js-sequence-diagrams) project for usage of the grammar for the sequence diagrams. Thanks to Jessica Peter for inspiration and starting point for gantt rendering.* +>*Thank you to [Tyler Long](https://github.com/tylerlong) who has been a collaborator since April 2017.* +> +>*Thank you to the ever-growing list of [contributors](https://github.com/knsv/mermaid/graphs/contributors) that brought the project this far!* -Replace `` with expected version number. - -Example: https://unpkg.com/mermaid@7.1.0/dist/ - -### Node.js - - yarn add mermaid - - -## Documentation - -https://mermaidjs.github.io - - -## Sibling projects - -- [mermaid CLI](https://github.com/mermaidjs/mermaid.cli) -- [mermaid live editor](https://github.com/mermaidjs/mermaid-live-editor) -- [mermaid webpack demo](https://github.com/mermaidjs/mermaid-webpack-demo) -- [mermaid Parcel demo](https://github.com/mermaidjs/mermaid-parcel-demo) - - -# Request for assistance - -Things are piling up and I have hard time keeping up. To remedy this -it would be great if we could form a core team of developers to cooperate -with the future development mermaid. - -As part of this team you would get write access to the repository and would -represent the project when answering questions and issues. - -Together we could continue the work with things like: -* adding more types of diagrams like mindmaps, ert diagrams etc -* improving existing diagrams - -Don't hesitate to contact me if you want to get involved. - - -# For contributors - -## Setup - - yarn install - - -## Build - - yarn build:watch - - -## Lint - - yarn lint - -We use [JavaScript Standard Style](https://github.com/feross/standard). -We recommend you installing [editor plugins](https://github.com/feross/standard#are-there-text-editor-plugins) so you can get real time lint result. - - -## Test - - yarn test - -Manual test in browser: - - open dist/index.html - - -## Release - -For those who have the permission to do so: - -Update version number in `package.json`. - - npm publish - -Command above generates files into the `dist` folder and publishes them to npmjs.org. - - -# Credits - -Many thanks to the [d3](http://d3js.org/) and [dagre-d3](https://github.com/cpettitt/dagre-d3) projects for providing the graphical layout and drawing libraries! - -Thanks also to the [js-sequence-diagram](http://bramp.github.io/js-sequence-diagrams) project for usage of the grammar for the sequence diagrams. Thanks to Jessica Peter for inspiration and starting point for gantt rendering. +--- *Mermaid was created by Knut Sveidqvist for easier documentation.* - -*[Tyler Long](https://github.com/tylerlong) has became a collaborator since April 2017.* - -Here is the full list of the projects [contributors](https://github.com/knsv/mermaid/graphs/contributors). diff --git a/cypress/integration/other/interaction.spec.js b/cypress/integration/other/interaction.spec.js index 3c8c1c53e..cfd937e63 100644 --- a/cypress/integration/other/interaction.spec.js +++ b/cypress/integration/other/interaction.spec.js @@ -16,7 +16,7 @@ describe('Interaction', () => { cy.viewport(1440, 1024); cy.visit(url); cy.get('body') - .find('g#s1Function') + .find('g#mermaid-dom-id-1Function') .click(); cy.get('.created-by-click').should('have.text', 'Clicked By Flow'); @@ -38,7 +38,7 @@ describe('Interaction', () => { cy.viewport(1440, 1024); cy.visit(url); cy.get('body') - .find('g#s2URL') + .find('g#mermaid-dom-id-2URL') .click(); cy.location().should(location => { @@ -108,7 +108,7 @@ describe('Interaction', () => { cy.viewport(1440, 1024); cy.visit(url); cy.get('body') - .find('g#s1Function') + .find('g#mermaid-dom-id-1Function') .click(); cy.get('.created-by-click').should('not.have.text', 'Clicked By Flow'); @@ -130,7 +130,7 @@ describe('Interaction', () => { cy.viewport(1440, 1024); cy.visit(url); cy.get('body') - .find('g#s2URL') + .find('g#mermaid-dom-id-2URL') .click(); cy.location().should(location => { @@ -200,7 +200,7 @@ describe('Interaction', () => { cy.viewport(1440, 1024); cy.visit(url); cy.get('body') - .find('g#s1Function') + .find('g#mermaid-dom-id-1Function') .click(); cy.get('.created-by-click').should('not.have.text', 'Clicked By Flow'); diff --git a/cypress/integration/other/rerender.spec.js b/cypress/integration/other/rerender.spec.js new file mode 100644 index 000000000..d7b3d2b47 --- /dev/null +++ b/cypress/integration/other/rerender.spec.js @@ -0,0 +1,16 @@ +/* eslint-env jest */ +describe('Rerendering', () => { + + it('should be able to render and rerender a graph via API', () => { + const url = 'http://localhost:9000/rerender.html'; + cy.viewport(1440, 1024); + cy.visit(url); + cy.get('#graph #A').should('have.text', 'XMas'); + + cy.get('body') + .find('#rerender') + .click({ force: true }); + + cy.get('#graph #A').should('have.text', 'Saturday'); + }); +}); diff --git a/cypress/integration/rendering/classDiagram.spec.js b/cypress/integration/rendering/classDiagram.spec.js index b80f5d23c..1e4585149 100644 --- a/cypress/integration/rendering/classDiagram.spec.js +++ b/cypress/integration/rendering/classDiagram.spec.js @@ -1,12 +1,13 @@ /* eslint-env jest */ import { imgSnapshotTest } from '../../helpers/util'; -describe('Sequencediagram', () => { - it('should render a simple class diagrams', () => { +describe('Class diagram', () => { + it('should render a simple class diagram', () => { imgSnapshotTest( ` classDiagram Class01 <|-- AveryLongClass : Cool + <<interface>> Class01 Class03 *-- Class04 Class05 o-- Class06 Class07 .. Class08 @@ -19,9 +20,94 @@ describe('Sequencediagram', () => { Class01 : int chimp Class01 : int gorilla Class08 <--> C2: Cool label + class Class10 { + <<service>> + int id + test() + } `, {} ); cy.get('svg'); }); + it('should render a simple class diagrams with cardinality', () => { + imgSnapshotTest( + ` + classDiagram + Class01 "1" <|--|> "*" AveryLongClass : Cool + <<interface>> Class01 + Class03 "1" *-- "*" Class04 + Class05 "1" o-- "many" Class06 + Class07 "1" .. "*" Class08 + Class09 "1" --> "*" C2 : Where am i? + Class09 "*" --* "*" C3 + Class09 "1" --|> "1" Class07 + Class07 : equals() + Class07 : Object[] elementData + Class01 : size() + Class01 : int chimp + Class01 : int gorilla + Class08 "1" <--> "*" C2: Cool label + class Class10 { + <<service>> + int id + test() + } + `, + {} + ); + cy.get('svg'); + }); + it('should render multiple class diagrams', () => { + imgSnapshotTest( + [ + ` + classDiagram + Class01 "1" <|--|> "*" AveryLongClass : Cool + <<interface>> Class01 + Class03 "1" *-- "*" Class04 + Class05 "1" o-- "many" Class06 + Class07 "1" .. "*" Class08 + Class09 "1" --> "*" C2 : Where am i? + Class09 "*" --* "*" C3 + Class09 "1" --|> "1" Class07 + Class07 : equals() + Class07 : Object[] elementData + Class01 : size() + Class01 : int chimp + Class01 : int gorilla + Class08 "1" <--> "*" C2: Cool label + class Class10 { + <<service>> + int id + test() + } + `, + ` + classDiagram + Class01 "1" <|--|> "*" AveryLongClass : Cool + <<interface>> Class01 + Class03 "1" *-- "*" Class04 + Class05 "1" o-- "many" Class06 + Class07 "1" .. "*" Class08 + Class09 "1" --> "*" C2 : Where am i? + Class09 "*" --* "*" C3 + Class09 "1" --|> "1" Class07 + Class07 : equals() + Class07 : Object[] elementData + Class01 : size() + Class01 : int chimp + Class01 : int gorilla + Class08 "1" <--> "*" C2: Cool label + class Class10 { + <<service>> + int id + test() + } + `, + ], + {} + ); + cy.get('svg'); + }); }); diff --git a/cypress/integration/rendering/current.spec.js b/cypress/integration/rendering/current.spec.js new file mode 100644 index 000000000..1ed1c9d5c --- /dev/null +++ b/cypress/integration/rendering/current.spec.js @@ -0,0 +1,20 @@ +/* eslint-env jest */ +import { imgSnapshotTest } from '../../helpers/util'; + +describe('State diagram', () => { + it('should render a flowchart full of circles', () => { + imgSnapshotTest( + ` + stateDiagram + State1: The state with a note + note right of State1 + Important information! You\ncan write + notes with multiple lines... + Here is another line... + And another line... + end note + `, + {} + ); + }); +}); diff --git a/cypress/integration/rendering/flowchart.spec.js b/cypress/integration/rendering/flowchart.spec.js index 89ec06d76..5cf75f53e 100644 --- a/cypress/integration/rendering/flowchart.spec.js +++ b/cypress/integration/rendering/flowchart.spec.js @@ -2,7 +2,7 @@ import { imgSnapshotTest } from '../../helpers/util'; describe('Flowcart', () => { - it('should render a simple flowchart', () => { + it('1: should render a simple flowchart no htmlLabels', () => { imgSnapshotTest( `graph TD A[Christmas] -->|Get money| B(Go shopping) @@ -11,10 +11,22 @@ describe('Flowcart', () => { C -->|Two| E[iPhone] C -->|Three| F[fa:fa-car Car] `, - {} + { flowchart: { htmlLabels: false } } ); }); - it('should render a simple flowchart with line breaks', () => { + it('2: should render a simple flowchart with htmlLabels', () => { + imgSnapshotTest( + `graph TD + A[Christmas] -->|Get money| B(Go shopping) + B --> C{Let me think} + C -->|One| D[Laptop] + C -->|Two| E[iPhone] + C -->|Three| F[fa:fa-car Car] + `, + { flowchart: { htmlLabels: true } } + ); + }); + it('3: should render a simple flowchart with line breaks', () => { imgSnapshotTest( ` graph TD @@ -28,7 +40,7 @@ describe('Flowcart', () => { ); }); - it('should render a simple flowchart with trapezoid and inverse trapezoid vertex options.', () => { + it('4: should render a simple flowchart with trapezoid and inverse trapezoid vertex options.', () => { imgSnapshotTest( ` graph TD @@ -43,7 +55,7 @@ describe('Flowcart', () => { ); }); - it('should style nodes via a class.', () => { + it('4: should style nodes via a class.', () => { imgSnapshotTest( ` graph TD @@ -59,7 +71,7 @@ describe('Flowcart', () => { ); }); - it('should render a flowchart full of circles', () => { + it('5: should render a flowchart full of circles', () => { imgSnapshotTest( ` graph LR @@ -87,7 +99,7 @@ describe('Flowcart', () => { {} ); }); - it('should render a flowchart full of icons', () => { + it('6: should render a flowchart full of icons', () => { imgSnapshotTest( ` graph TD @@ -158,7 +170,7 @@ describe('Flowcart', () => { ); }); - it('should render labels with numbers at the start', () => { + it('7: should render labels with numbers at the start', () => { imgSnapshotTest( ` graph TB;subgraph "number as labels";1;end; @@ -166,7 +178,7 @@ describe('Flowcart', () => { {} ); }); - it('should render subgraphs', () => { + it('8: should render subgraphs', () => { imgSnapshotTest( ` graph TB @@ -178,7 +190,7 @@ describe('Flowcart', () => { ); }); - it('should render subgraphs with a title startign with a digit', () => { + it('9: should render subgraphs with a title startign with a digit', () => { imgSnapshotTest( ` graph TB @@ -190,7 +202,7 @@ describe('Flowcart', () => { ); }); - it('should render styled subgraphs', () => { + it('10: should render styled subgraphs', () => { imgSnapshotTest( ` graph TB @@ -225,7 +237,7 @@ describe('Flowcart', () => { ); }); - it('should render a flowchart with ling sames and class definitoins', () => { + it('11: should render a flowchart with ling sames and class definitoins', () => { imgSnapshotTest( `graph LR sid-B3655226-6C29-4D00-B685-3D5C734DC7E1[" @@ -327,7 +339,7 @@ describe('Flowcart', () => { ); }); - it('should render color of styled nodes', () => { + it('12: should render color of styled nodes', () => { imgSnapshotTest( ` graph LR @@ -344,4 +356,25 @@ describe('Flowcart', () => { } ); }); + it('13: should render hexagons', () => { + imgSnapshotTest( + ` + graph TD + A[Christmas] -->|Get money| B(Go shopping) + B --> C{{Let me think...
Do I want something for work,
something to spend every free second with,
or something to get around?}} + C -->|One| D[Laptop] + C -->|Two| E[iPhone] + C -->|Three| F[Car] + click A "index.html#link-clicked" "link test" + click B testClick "click test" + classDef someclass fill:#f96; + class A someclass; + `, + { + listUrl: false, + listId: 'color styling', + logLevel: 0 + } + ); + }); }); diff --git a/cypress/integration/rendering/gantt.spec.js b/cypress/integration/rendering/gantt.spec.js index faba97d9c..c1bdee040 100644 --- a/cypress/integration/rendering/gantt.spec.js +++ b/cypress/integration/rendering/gantt.spec.js @@ -19,7 +19,7 @@ describe('Sequencediagram', () => { section Critical tasks Completed task in the critical line :crit, done, 2014-01-06,24h - Implement parser and jison :crit, done, after des1, 2d + Implement parser and jison :crit, done, after des1, 2d Create tests for parser :crit, active, 3d Future task in critical line :crit, 5d Create tests for renderer :2d diff --git a/cypress/integration/rendering/gitGraph.spec.js b/cypress/integration/rendering/gitGraph.spec.js index c36f635b4..0a72cdee2 100644 --- a/cypress/integration/rendering/gitGraph.spec.js +++ b/cypress/integration/rendering/gitGraph.spec.js @@ -6,12 +6,6 @@ describe('Sequencediagram', () => { imgSnapshotTest( ` gitGraph: - options - { - "nodeSpacing": 150, - "nodeRadius": 10 - } - end commit branch newbranch checkout newbranch @@ -20,9 +14,8 @@ describe('Sequencediagram', () => { checkout master commit commit - merge newbranch - `, - {} + merge newbranch`, + { logLevel: 0 } ); }); }); diff --git a/cypress/integration/rendering/pie.spec.js b/cypress/integration/rendering/pie.spec.js index f930ac246..b69aad631 100644 --- a/cypress/integration/rendering/pie.spec.js +++ b/cypress/integration/rendering/pie.spec.js @@ -12,5 +12,29 @@ describe('Pie Chart', () => { `, {} ); + cy.get('svg'); + }); + it('should render a simple pie diagram with long labels', () => { + imgSnapshotTest( + ` + pie title NETFLIX + "Time spent looking for movie" : 90 + "Time spent watching it" : 10 + `, + {} + ); + cy.get('svg'); + }); + it('should render a simple pie diagram with capital letters for labels', () => { + imgSnapshotTest( + ` + pie title What Voldemort doesn't have? + "FRIENDS" : 2 + "FAMILY" : 3 + "NOSE" : 45 + `, + {} + ); + cy.get('svg'); }); }); diff --git a/cypress/integration/rendering/stateDiagram.spec.js b/cypress/integration/rendering/stateDiagram.spec.js new file mode 100644 index 000000000..e4231261e --- /dev/null +++ b/cypress/integration/rendering/stateDiagram.spec.js @@ -0,0 +1,279 @@ +/* eslint-env jest */ +import { imgSnapshotTest } from '../../helpers/util'; + +describe('State diagram', () => { + it('should render a simple state diagrams', () => { + imgSnapshotTest( + ` + stateDiagram + [*] --> State1 + State1 --> [*] + `, + { logLevel: 0 } + ); + cy.get('svg'); + }); + it('should render a long descriptions instead of id when available', () => { + imgSnapshotTest( + ` + stateDiagram + + [*] --> S1 + state "Some long name" as S1 + `, + { logLevel: 0 } + ); + cy.get('svg'); + }); + it('should render a long descriptions with additional descriptions', () => { + imgSnapshotTest( + ` + stateDiagram + + [*] --> S1 + state "Some long name" as S1: The description + `, + { logLevel: 0 } + ); + cy.get('svg'); + }); + it('should render a single state with short descr', () => { + imgSnapshotTest( + ` + stateDiagram + state "A long long name" as long1 + state "A" as longlonglongid + `, + { logLevel: 0 } + ); + cy.get('svg'); + }); + it('should render a transition descrions with new lines', () => { + imgSnapshotTest( + ` + stateDiagram + + [*] --> S1 + S1 --> S2: long line using
should work + S1 --> S3: long line using
should work + S1 --> S4: long line using \\nshould work + `, + { logLevel: 0 } + ); + cy.get('svg'); + }); + it('should render a state with a note', () => { + imgSnapshotTest( + ` + stateDiagram + State1: The state with a note + note right of State1 + Important information! You can write + notes. + end note + `, + { logLevel: 0 } + ); + cy.get('svg'); + }); + it('should render a state with on the left side when so specified', () => { + imgSnapshotTest( + ` + stateDiagram + State1: The state with a note with minus - and plus + in it + note left of State1 + Important information! You can write + notes with . and in them. + end note + `, + { logLevel: 0 } + ); + cy.get('svg'); + }); + it('should render a state with a note together with another state', () => { + imgSnapshotTest( + ` + stateDiagram + State1: The state with a note +,- + note right of State1 + Important information! You can write +,- + notes. + end note + State1 --> State2 : With +,- + note left of State2 : This is the note +,-
+ `, + { logLevel: 0 } + ); + cy.get('svg'); + }); + it('should render a states with descriptions including multi-line descriptions', () => { + imgSnapshotTest( + ` + stateDiagram + State1: This a a single line description + State2: This a a multi line description + State2: here comes the multi part + [*] --> State1 + State1 --> State2 + State2 --> [*] + `, + { logLevel: 0 } + ); + cy.get('svg'); + }); + it('should render a simple state diagrams', () => { + imgSnapshotTest( + ` + stateDiagram + [*] --> State1 + State1 --> State2 + State1 --> State3 + State1 --> [*] + `, + { logLevel: 0 } + ); + cy.get('svg'); + }); + it('should render a simple state diagrams with labels', () => { + imgSnapshotTest( + ` + stateDiagram + [*] --> State1 + State1 --> State2 : Transition 1 + State1 --> State3 : Transition 2 + State1 --> State4 : Transition 3 + State1 --> State5 : Transition 4 + State2 --> State3 : Transition 5 + State1 --> [*] + `, + { logLevel: 0 } + ); + cy.get('svg'); + }); + it('should render state descriptions', () => { + imgSnapshotTest( + ` + stateDiagram + state "Long state description" as XState1 + state "Another Long state description" as XState2 + XState2 : New line + XState1 --> XState2 + `, + { logLevel: 0 } + ); + cy.get('svg'); + }); + it('should render composit states', () => { + imgSnapshotTest( + ` + stateDiagram + [*] --> NotShooting: Pacifist + NotShooting --> A + NotShooting --> B + NotShooting --> C + + state NotShooting { + [*] --> Idle: Yet another long long öong öong öong label + Idle --> Configuring : EvConfig + Configuring --> Idle : EvConfig EvConfig EvConfig EvConfig EvConfig + } + `, + { logLevel: 0 } + ); + cy.get('svg'); + }); + it('should render multiple composit states', () => { + imgSnapshotTest( + ` + stateDiagram + [*]-->TV + + state TV { + [*] --> Off: Off to start with + On --> Off : Turn off + Off --> On : Turn on + } + + TV--> Console + + state Console { + [*] --> Off2: Off to start with + On2--> Off2 : Turn off + Off2 --> On2 : Turn on + On2-->Playing + + state Playing { + Alive --> Dead + Dead-->Alive + } + } + `, + { logLevel: 0 } + ); + }); + it('should render forks in composit states', () => { + imgSnapshotTest( + ` + stateDiagram + [*]-->TV + + state TV { + state fork_state <<fork>> + [*] --> fork_state + fork_state --> State2 + fork_state --> State3 + + state join_state <<join>> + State2 --> join_state + State3 --> join_state + join_state --> State4 + State4 --> [*] + } + `, + { logLevel: 0 } + ); + }); + it('should render forks and joins', () => { + imgSnapshotTest( + ` + stateDiagram + state fork_state <<fork>> + [*] --> fork_state + fork_state --> State2 + fork_state --> State3 + + state join_state <<join>> + State2 --> join_state + State3 --> join_state + join_state --> State4 + State4 --> [*] + `, + { logLevel: 0 } + ); + cy.get('svg'); + }); + it('should render conurrency states', () => { + imgSnapshotTest( + ` + stateDiagram + [*] --> Active + + state Active { + [*] --> NumLockOff + NumLockOff --> NumLockOn : EvNumLockPressed + NumLockOn --> NumLockOff : EvNumLockPressed + -- + [*] --> CapsLockOff + CapsLockOff --> CapsLockOn : EvCapsLockPressed + CapsLockOn --> CapsLockOff : EvCapsLockPressed + -- + [*] --> ScrollLockOff + ScrollLockOff --> ScrollLockOn : EvCapsLockPressed + ScrollLockOn --> ScrollLockOff : EvCapsLockPressed + } + `, + { logLevel: 0 } + ); + cy.get('svg'); + }); +}); diff --git a/cypress/platform/e2e.html b/cypress/platform/e2e.html index 498b374d2..4384fd0ec 100644 --- a/cypress/platform/e2e.html +++ b/cypress/platform/e2e.html @@ -1,11 +1,26 @@ - - + + @@ -15,6 +30,10 @@ 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' }); diff --git a/cypress/platform/rerender.html b/cypress/platform/rerender.html new file mode 100644 index 000000000..8a9c0424c --- /dev/null +++ b/cypress/platform/rerender.html @@ -0,0 +1,33 @@ + + + + + + Mermaid Quick Test Page + + + +
+
+ + + + + + + diff --git a/cypress/platform/viewer.js b/cypress/platform/viewer.js index b33c76502..004f0282c 100644 --- a/cypress/platform/viewer.js +++ b/cypress/platform/viewer.js @@ -1,50 +1,95 @@ -import { Base64 } from 'js-base64' -import mermaid2 from '../../src/mermaid' +import { Base64 } from 'js-base64'; +import mermaid2 from '../../src/mermaid'; /** * ##contentLoaded * Callback function that is called when page is loaded. This functions fetches configuration for mermaid rendering and * calls init for rendering the mermaid diagrams on the page. */ -const contentLoaded = function () { - let pos = document.location.href.indexOf('?graph=') +const contentLoaded = function() { + let pos = document.location.href.indexOf('?graph='); if (pos > 0) { - pos = pos + 7 - const graphBase64 = document.location.href.substr(pos) - const graphObj = JSON.parse(Base64.decode(graphBase64)) + pos = pos + 7; + const graphBase64 = document.location.href.substr(pos); + const graphObj = JSON.parse(Base64.decode(graphBase64)); // const graph = 'hello' - console.log(graphObj) - const div = document.createElement('div') - div.id = 'block' - div.className = 'mermaid' - div.innerHTML = graphObj.code - document.getElementsByTagName('body')[0].appendChild(div) - global.mermaid.initialize(graphObj.mermaid) + console.log(graphObj); + if (Array.isArray(graphObj.code)) { + const numCodes = graphObj.code.length; + for (let i = 0; i < numCodes; i++) { + const div = document.createElement('div'); + div.id = 'block' + i; + div.className = 'mermaid'; + div.innerHTML = graphObj.code[i]; + document.getElementsByTagName('body')[0].appendChild(div); + } + } else { + const div = document.createElement('div'); + div.id = 'block'; + div.className = 'mermaid'; + div.innerHTML = graphObj.code; + document.getElementsByTagName('body')[0].appendChild(div); + } + global.mermaid.initialize(graphObj.mermaid); // console.log('graphObj.mermaid', graphObj.mermaid) - global.mermaid.init() + global.mermaid.init(); } -} -const contentLoadedApi = function () { - let pos = document.location.href.indexOf('?graph=') +}; +const contentLoadedApi = function() { + let pos = document.location.href.indexOf('?graph='); if (pos > 0) { - pos = pos + 7 - const graphBase64 = document.location.href.substr(pos) - const graphObj = JSON.parse(Base64.decode(graphBase64)) + pos = pos + 7; + const graphBase64 = document.location.href.substr(pos); + const graphObj = JSON.parse(Base64.decode(graphBase64)); // const graph = 'hello' - const div = document.createElement('div') - div.id = 'block' - div.className = 'mermaid' - // div.innerHTML = graphObj.code - document.getElementsByTagName('body')[0].appendChild(div) - global.mermaid.initialize(graphObj.mermaid) + if (Array.isArray(graphObj.code)) { + const numCodes = graphObj.code.length; + const divs = []; + let div; + for (let i = 0; i < numCodes; i++) { + div = document.createElement('div'); + div.id = 'block' + i; + div.className = 'mermaid'; + // div.innerHTML = graphObj.code + document.getElementsByTagName('body')[0].appendChild(div); + divs[i] = div; + } - mermaid2.render('newid', graphObj.code, (svgCode, bindFunctions) => { - div.innerHTML = svgCode + global.mermaid.initialize(graphObj.mermaid); - bindFunctions(div) - }, div) + for (let i = 0; i < numCodes; i++) { + mermaid2.render( + 'newid' + i, + graphObj.code[i], + (svgCode, bindFunctions) => { + div.innerHTML = svgCode; + + bindFunctions(div); + }, + divs[i] + ); + } + } else { + const div = document.createElement('div'); + div.id = 'block'; + div.className = 'mermaid'; + // div.innerHTML = graphObj.code + document.getElementsByTagName('body')[0].appendChild(div); + global.mermaid.initialize(graphObj.mermaid); + + mermaid2.render( + 'newid', + graphObj.code, + (svgCode, bindFunctions) => { + div.innerHTML = svgCode; + + if (bindFunctions) bindFunctions(div); + }, + div + ); + } } -} +}; if (typeof document !== 'undefined') { /*! @@ -52,15 +97,15 @@ if (typeof document !== 'undefined') { */ window.addEventListener( 'load', - function () { + function() { if (this.location.href.match('xss.html')) { - this.console.log('Using api') - contentLoadedApi() + this.console.log('Using api'); + contentLoadedApi(); } else { - this.console.log('Not using api') - contentLoaded() + this.console.log('Not using api'); + contentLoaded(); } }, false - ) + ); } diff --git a/dist/index.html b/dist/index.html index f94119e13..73f6ff154 100644 --- a/dist/index.html +++ b/dist/index.html @@ -291,7 +291,7 @@ graph TB
graph TD A[Christmas] -->|Get money| B(Go shopping) -B --> C{Let me think} +B --> C{{Let me think...
Do I want something for work,
something to spend every free second with,
or something to get around?}} C -->|One| D[Laptop] C -->|Two| E[iPhone] C -->|Three| F[Car] @@ -399,6 +399,7 @@ merge newbranch
classDiagram Class01 <|-- AveryLongClass : Cool +<<interface>> Class01 Class03 "0" *-- "0..n" Class04 Class05 "1" o-- "many" Class06 Class07 .. Class08 @@ -411,7 +412,38 @@ Class01 : size() Class01 : int chimp Class01 : int gorilla Class08 <--> C2: Cool label +class Class10 { + <<service>> + int id + size() +}
+
+ stateDiagram + State1 +
+ +
+
+ stateDiagram + [*] --> First + state First { + [*] --> second + second --> [*] + } +
+
+ stateDiagram + State1: The state with a note + note right of State1 + Important information! You can write + notes. + end note + State1 --> State2 + note left of State2 : This is the note to the left. +
+ + + diff --git a/docs/README.md b/docs/README.md index 312064f2c..409d4f40c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -4,12 +4,20 @@ # mermaid +## New diagrams in 8.4 + +With version 8.4 class diagrams has got some new features, bug fixes and documentation. Another new feature in 8.4 is the new diagram +type, state diagrams. + +![Image show the two new diagram types](./img/new-diagrams.png) + + ## Special note regarding version 8.2 In version 8.2 a security improvement was introduced. A securityLevel configuration was introduced wich sets the level of trust to be used on the parsed diagrams. * **true**: (default) tags in text are encoded, click functionality is disabled -* false: tags in text are allowed, click functionality is enabledClosed issues: +* false: tags in text are allowed, click functionality is enabledClosed issues: ⚠️ **Note** : This changes the default behaviour of mermaid so that after upgrade to 8.2, if the securityLevel is not configured, tags in flowcharts are encoded as tags and clicking is prohibited. @@ -190,8 +198,9 @@ Don't hesitate to contact me if you want to get involved. yarn lint -We use [JavaScript Standard Style](https://github.com/feross/standard). -We recommend you installing [editor plugins](https://github.com/feross/standard#are-there-text-editor-plugins) so you can get real time lint result. +We use [eslint](https://eslint.org/). +We recommend you installing [editor plugins](https://eslint.org/docs/user-guide/integrations) so you can get real time lint result. + ## Test diff --git a/docs/_sidebar.md b/docs/_sidebar.md index 7c8e954fe..8bf4b1d33 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -10,6 +10,8 @@ - [Flowchart](flowchart.md) - [Sequence diagram](sequenceDiagram.md) + - [Class Diagram](classDiagram.md) + - [State Diagram](stateDiagram.md) - [Gantt](gantt.md) - [Pie Chart](pie.md) - Guide diff --git a/docs/classDiagram.md b/docs/classDiagram.md new file mode 100644 index 000000000..057618d4a --- /dev/null +++ b/docs/classDiagram.md @@ -0,0 +1,444 @@ +# Class diagrams + +> "In software engineering, a class diagram in the Unified Modeling Language (UML) is a type of static structure diagram that describes the structure of a system by showing the system's classes, their attributes, operations (or methods), and the relationships among objects." + Wikipedia + +The class diagram is the main building block of object-oriented modeling. It is used for general conceptual modeling of the structure of the application, and for detailed modeling translating the models into programming code. Class diagrams can also be used for data modeling. The classes in a class diagram represent both the main elements, interactions in the application, and the classes to be programmed. + +Mermaid can render class diagrams. + +``` + classDiagram + Animal <|-- Duck + Animal <|-- Fish + Animal <|-- Zebra + Animal : +int age + Animal : +String gender + Animal: +isMammal() + Animal: +mate() + class Duck{ + +String beakColor + +swim() + +quack() + } + class Fish{ + -int sizeInFeet + -canEat() + } + class Zebra{ + +bool is_wild + +run() + } + +``` +```mermaid + classDiagram + Animal <|-- Duck + Animal <|-- Fish + Animal <|-- Zebra + Animal : +int age + Animal : +String gender + Animal: +isMammal() + Animal: +mate() + class Duck{ + +String beakColor + +swim() + +quack() + } + class Fish{ + -int sizeInFeet + -canEat() + } + class Zebra{ + +bool is_wild + +run() + } + +``` + +## Syntax + +### Class + +UML provides mechanisms to represent class members, such as attributes and methods, and additional information about them. +A single instance of a class in the diagram contains three compartments: + - The top compartment contains the name of the class. It is printed in bold and centered, and the first letter is capitalized. It may also contain optional annotation text describing the nature of the class. + - The middle compartment contains the attributes of the class. They are left-aligned and the first letter is lowercase. + - The bottom compartment contains the operations the class can execute. They are also left-aligned and the first letter is lowercase. + +``` +classDiagram + class BankAccount + BankAccount : +String owner + BankAccount : +Bigdecimal balance + BankAccount : +deposit(amount) + BankAccount : +withdrawl(amount) +``` +```mermaid +classDiagram + class BankAccount + BankAccount : +String owner + BankAccount : +BigDecimal balance + BankAccount : +deposit(amount) + BankAccount : +withdrawl(amount) +``` +## Define a class + +There are two ways to define a class: +- Explicitly defining a class using keyword **class** like `class Animal`. This defines the Animal class +- Define two classes via a **relationship** between them `Vehicle <|-- Car`. This defines two classes Vehicle and Car along with their relationship. + +``` +classDiagram + class Animal + Vehicle <|-- Car +``` +```mermaid +classDiagram + class Animal + Vehicle <|-- Car +``` + +Naming convention: a class name should be composed of alphanumeric (unicode allowed) and underscore characters. + +## Defining Members of a class + +UML provides mechanisms to represent class members, such as attributes and methods, and additional information about them. + +#### Visibility +To specify the visibility of a class member (i.e. any attribute or method), these notations may be placed before the member's name, but is it optional: + +- `+` Public +- `-` Private +- `#` Protected +- `~` Package + +Mermaid distinguishes between attributes and functions/methods based on if the **parenthesis** `()` are present or not. The one with `()` are treated as functions/methods, and others as attributes. + +There are two ways to define the members of a class, and regardless of the whichever syntax is used to define the members, the output will still be same. The two different ways are : +- Associate a member of a class using **:** (colon) followed by member name, useful to define one member at a time. For example: + + ``` + class BankAccount + BankAccount : +String owner + BankAccount : +BigDecimal balance + BankAccount : +deposit(amount) + BankAccount : +withdrawl(amount) + ``` + ```mermaid + classDiagram + class BankAccount + BankAccount : +String owner + BankAccount : +BigDecimal balance + BankAccount : +deposit(amount) + BankAccount : +withdrawl(amount) +``` + +- Associate members of a class using **{}** brackets, where members are grouped within curly brackets. Suitable for defining multiple members at once. For example: +``` +class BankAccount{ + +String owner + +BigDecimal balance + +deposit(amount) + +withdrawl(amount) +} +``` +```mermaid + classDiagram + class BankAccount{ + +String owner + +BigDecimal balance + +deposit(amount) + +withdrawl(amount) +}``` + +## Defining Relationship +A relationship is a general term covering the specific types of logical connections found on class and object diagrams. +``` +[classA][Arrow][ClassB]:LabelText +``` + +There are different types of relations defined for classes under UML which are currently supported: + +Type | Description +--- | --- +<\|--| Inheritance +*-- | Composition +o-- | Aggregation +--> | Association +-- | Link + + +``` +classDiagram +classA <|-- classB +classC *-- classD +classE o-- classF +classG <-- classH +classI <.. classJ +classK .. classL + +``` + +```mermaid +classDiagram +classA <|-- classB +classC *-- classD +classE o-- classF +classG <-- classH +classI <.. classJ +classK .. classL + +``` +We can use the arrowheads in opposite directions as well : +``` +classDiagram +classA --|> classB +classC --* classD +classE --o classF +classG <--> classH +classI ..> classJ +classK .. classL + +``` + +```mermaid +classDiagram +classA --|> classB +classC --* classD +classE --o classF +classG <--> classH +classI ..> classJ +classK .. classL + + +``` +## Labels on Relations + +It is possible to add a label text to a relation: +``` +[classA][Arrow][ClassB]:LabelText +``` +``` +classDiagram +classA <|-- classB : implements +classC *-- classD : composition +classE o-- classF : association +``` +```mermaid +classDiagram +classA <|-- classB : implements +classE o-- classF : association + +``` +## Cardinality / Multiplicity on relations +Multiplicity or cardinality in class diagrams indicates the number of instances of one class linked to one instance of the other class. For example, one company will have one or more employees, but each employee works for just one company. + +Multiplicity notations are placed near the ends of an association. + +The different cardinality options are : +- `0..1` Zero or one +- `1` Only 1 +- `0..1` Zero or One +- `1..*` One or more +- `*` Many +- `n` n {where n>1} +- `0..n` zeor to n {where n>1} +- `1..n` one to n {where n>1} + +Cardinality can be easily defined by placing cardinality text within qoutes `"` before(optional) and after(optional) a given arrow. +``` +[classA] "cardinality1" [Arrow] "cardinality2" [ClassB]:LabelText +``` +``` +classDiagram + Customer "1" --> "*" Ticket + Student "1" --> "1..*" Course + Galaxy --> "many" Star : Contains +``` +```mermaid +classDiagram + Customer "1" --> "*" Ticket + Student "1" --> "1..*" Course + Galaxy --> "many" Star : Contains +``` +## Annotations on classes + +It is possible to annotate classes with a specific marker text which is like meta-data for the class, giving a clear indication about its nature. Some common annotations examples could be: +- `<>` To represent an Interface class +- `<>` To represent an abstract class +- `<>` To represent a service class +- `<>` To represent an enum + +Annotations are defined within the opening `<<` and closing `>>`. There are two ways to add an annotation to a class and regardless of the syntax used output will be same. The two ways are : +- In a ***separate line*** after a class is defined. For example: +``` +classDiagram +class Shape +<> Shape +``` + +```mermaid +classDiagram +class Shape +<> Shape +Shape : noOfVertices +Shape : draw() +``` +- In a ***nested structure*** along with class definition. For example: + +``` +classDiagram +class Shape{ + <> + noOfVertices + draw() +} +class Color{ + <> + RED + BLUE + GREEN + WHITE + BLACK +} + +``` + +```mermaid +classDiagram +class Shape{ + <> + noOfVertices + draw() +} +class Color{ + <> + RED + BLUE + GREEN + WHITE + BLACK +} +``` + + + +## Styling + +Styling of the class diagram is done by defining a number of css classes. During rendering these classes are extracted from the file located at src/themes/class.scss + +### Styling Classes used + +Class | Description +--- | --- +g.classGroup text | Styles for general class text +classGroup .title | Styles for general class title +g.classGroup rect | Styles for class diagram rectangle +g.classGroup line | Styles for class diagram line +.classLabel .box | Styles for class label box +.classLabel .label | Styles for class label text +composition | Styles for componsition arrow head and arrow line +aggregation | Styles for aggregation arrow head and arrow line(dashed or solid) +dependency | Styles for dependency arrow head and arrow line + + + +### Sample stylesheet + + +```css +body { + background: white; +} + +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; + } +} + +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; +} + +@mixin composition { + fill: $nodeBorder; + stroke: $nodeBorder; + stroke-width: 1; +} + +#compositionStart { + @include composition; +} + +#compositionEnd { + @include composition; +} + +@mixin aggregation { + fill: $nodeBkg; + stroke: $nodeBorder; + stroke-width: 1; +} + +#aggregationStart { + @include aggregation; +} + +#aggregationEnd { + @include aggregation; +} + +#dependencyStart { + @include composition; +} + +#dependencyEnd { + @include composition; +} + +#extensionStart { + @include composition; +} + +#extensionEnd { + @include composition; +} + +``` + + +## Configuration +`Coming soon` + diff --git a/docs/examples.md b/docs/examples.md index c17693549..02985474d 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -1,3 +1,27 @@ +## Basic Pie Chart + +``` +pie title NETFLIX + "Time spent looking for movie" : 90 + "Time spent watching it" : 10 +``` +``` mermaid +pie title NETFLIX + "Time spent looking for movie" : 90 + "Time spent watching it" : 10 +``` +``` +pie title What Voldemort doesn't have? + "FRIENDS" : 2 + "FAMILY" : 3 + "NOSE" : 45 +``` +```mermaid +pie title What Voldemort doesn't have? + "FRIENDS" : 2 + "FAMILY" : 3 + "NOSE" : 45 +``` ## Basic sequence diagram ``` diff --git a/docs/flowchart.md b/docs/flowchart.md index 3ec4aaed1..c0fe7ad6e 100644 --- a/docs/flowchart.md +++ b/docs/flowchart.md @@ -4,7 +4,7 @@ This statement declares a new graph and the direction of the graph layout. -This declares a graph oriented from top to bottom. +This declares a graph oriented from top to bottom (`TD` or `TB`). ``` graph TD @@ -15,7 +15,16 @@ graph TD Start --> Stop ``` -This declares a graph oriented from left to right. +This declares a graph oriented from left to right (`LR`). + +``` +graph LR + Start --> Stop +``` +```mermaid +graph LR + Start --> Stop +``` Possible directions are: @@ -26,14 +35,6 @@ Possible directions are: * TD - same as TB -``` -graph LR - Start --> Stop -``` -```mermaid -graph LR - Start --> Stop -``` ## Nodes & shapes @@ -111,14 +112,55 @@ graph LR id1{This is the text in the box} ``` +### A hexagon node + +``` +graph LR + id1{{This is the text in the box}} +``` +```mermaid +graph LR + id1{{This is the text in the box}} +``` + +### Parallelogram + +``` +graph TD + id1[/This is the text in the box/] +``` +```mermaid +graph TD + id1[/This is the text in the box/] +``` + +### Parallelogram alt + +``` +graph TD + id1[\This is the text in the box\] +``` +```mermaid +graph TD + id1[\This is the text in the box\] +``` + ### Trapezoid +``` +graph TD + A[/Christmas\] +``` ```mermaid graph TD A[/Christmas\] ``` ### Trapezoid alt +``` +graph TD + B[\Go shopping/] +``` ```mermaid graph TD B[\Go shopping/] @@ -238,6 +280,19 @@ graph LR A == text ==> B ``` +### Chaining of links + +It is possible declare many links in the same line as per below: +``` +graph LR + A -- text --> B -- text2 --> C +``` +```mermaid +graph LR + A -- text --> B -- text2 --> C +``` + + ## Special characters that break syntax It is possible to put text within quotes in order to render more troublesome characters. As in the example below: @@ -349,7 +404,7 @@ Beginners tip, a full example using interactive links in a html context: click A callback "Tooltip" click B "http://www.github.com" "This is a link"
- + diff --git a/docs/gantt.md b/docs/gantt.md index 9d498a684..6363011d7 100755 --- a/docs/gantt.md +++ b/docs/gantt.md @@ -26,8 +26,6 @@ gantt Task in sec :2014-01-12 , 12d another task : 24d ``` - - ## Syntax ``` @@ -106,7 +104,11 @@ Tbd ### Date format -Tbd +The default date format is YYYY-MM-DD. You can define your ``dateFormat``. For example: + +``` +dateFormat YYYY MM DD +``` ### Diagram definition diff --git a/docs/img/header.png b/docs/img/header.png index 06159b2c9..6db8635c9 100644 Binary files a/docs/img/header.png and b/docs/img/header.png differ diff --git a/docs/img/new-diagrams.png b/docs/img/new-diagrams.png new file mode 100644 index 000000000..dd9d0f14e Binary files /dev/null and b/docs/img/new-diagrams.png differ diff --git a/docs/index.html b/docs/index.html index 45e9ef4a8..207568bee 100644 --- a/docs/index.html +++ b/docs/index.html @@ -7,8 +7,8 @@ - - + +