Merge branch 'develop' into sidv/esbuildFail

* develop: (40 commits)
  chore(deps-dev): bump typescript from 4.8.2 to 4.8.3 (#3446)
  chore(deps): bump actions/checkout from 2 to 3 (#3449)
  change wording of console log message (use comma)
  Moving out tests from mermaid.spec.js
  Fix for issue with setting the loglevel via numbers
  chore: update browsers list
  Limiting the interaction between the mermaid diagram and Mermaid to the diagramAPI
  Fix for broken tests
  chore(docs): Remove edit this page
  fix(git): support unusual prefixes in branch name
  formatting
  eslint fixes
  Creating detectors and moving out diagram specific code from the diagramAPI
  add eslint-disable no-console for file
  fix: Run precommit hook for doc.mts changes too
  chore: Updated doc files
  fix: Formatting issue
  (formatting only) sort imports just to force a new CI lint check
  ci: re-enable coveralls coverage upload
  build(dev-deps): remove unused `coveralls`
  ...
This commit is contained in:
Sidharth Vinod 2022-09-13 15:59:18 +05:30
commit a7f0b2ba21
No known key found for this signature in database
GPG Key ID: FB5CCD378D3907CD
78 changed files with 880 additions and 541 deletions

View File

@ -14,7 +14,7 @@ jobs:
name: check tests
if: github.repository_owner == 'mermaid-js'
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: testomatio/check-tests@stable

View File

@ -36,3 +36,9 @@ jobs:
run: yarn e2e
env:
CYPRESS_CACHE_FOLDER: .cache/Cypress
- name: Upload Coverage to Coveralls
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
flag-name: e2e

View File

@ -32,3 +32,12 @@ jobs:
- name: Run Unit Tests
run: |
yarn ci --coverage
- name: Upload Coverage to Coveralls
# it feels a bit weird to use @master, but that's what the docs use
# (coveralls also doesn't publish a @v1 we can use)
# https://github.com/marketplace/actions/coveralls-github-action
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
flag-name: unit

View File

@ -38,7 +38,7 @@
</style>
</head>
<body>
<pre class="mermaid2" style="width: 50%">
<pre class="mermaid" style="width: 50%">
flowchart LR
classDef aPID stroke:#4e4403,fill:#fdde29,color:#4e4403,rx:5px,ry:5px;
classDef crm stroke:#333333,fill:#DCDCDC,color:#333333,rx:5px,ry:5px;
@ -99,7 +99,7 @@ flowchart TD
class A someclass;
class C someclass;
</pre>
<pre class="mermaid2" style="width: 50%">
<pre class="mermaid" style="width: 50%">
sequenceDiagram
title: My Sequence Diagram Title
accTitle: My Acc Sequence Diagram
@ -109,14 +109,14 @@ flowchart TD
John-->>Alice: Great!
Alice-)John: See you later!
</pre>
<pre class="mermaid2" style="width: 50%">
<pre class="mermaid" style="width: 50%">
graph TD
A -->|000| B
B -->|111| C
linkStyle 1 stroke:#ff3,stroke-width:4px,color:red;
</pre>
<pre class="mermaid2" style="width: 100%">
<pre class="mermaid" style="width: 100%">
journey
accTitle: My User Journey Diagram
accDescr: My User Journey Diagram Description
@ -130,10 +130,10 @@ graph TD
Go downstairs: 5: Me
Sit down: 5: Me
</pre>
<pre class="mermaid2" style="width: 100%">
<pre class="mermaid" style="width: 100%">
info
</pre>
<pre class="mermaid2" style="width: 100%">
<pre class="mermaid" style="width: 100%">
requirementDiagram
accTitle: My req Diagram
accDescr: My req Diagram Description
@ -174,7 +174,7 @@ requirementDiagram
test_req - contains -> test_req3
test_req <- copies - test_entity2
</pre>
<pre class="mermaid2" style="width: 100%">
<pre class="mermaid" style="width: 100%">
gantt
dateFormat YYYY-MM-DD
title Adding GANTT diagram functionality to mermaid
@ -206,7 +206,7 @@ gantt
Add gantt diagram to demo page :20h
Add another diagram to demo page :48h
</pre>
<pre class="mermaid2" style="width: 100%">
<pre class="mermaid" style="width: 100%">
stateDiagram
state Active {
Idle
@ -234,7 +234,7 @@ stateDiagram
end
B ->> A: Return
</pre>
<pre class="mermaid2" style="width: 100%">
<pre class="mermaid" style="width: 100%">
classDiagram
accTitle: My class diagram
accDescr: My class diagram Description
@ -259,7 +259,7 @@ class Class10 {
A->>Bob: Hola
Bob-->A: Pasten !
</pre>
<pre class="mermaid2" style="width: 100%">
<pre class="mermaid" style="width: 100%">
gitGraph
commit id: "ZERO"
branch develop
@ -288,7 +288,7 @@ flowchart TD
C -->|Two| E[iPhone]
C -->|Three| F[fa:fa-car Car]
</pre>
<pre class="mermaid2" style="width: 100%">
<pre class="mermaid" style="width: 100%">
classDiagram
Animal "1" <|-- Duck
Animal <|-- Fish
@ -311,7 +311,7 @@ flowchart TD
+run()
}
</pre>
<pre class="mermaid2" style="width: 100%">
<pre class="mermaid" style="width: 100%">
erDiagram
CAR ||--o{ NAMED-DRIVER : allows
CAR {

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# Version 8.6.0 Changes

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# Change Log

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# Configuration

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# About Mermaid

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# Summary

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# Tutorials

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
- Getting started

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
- 📔 Introduction

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# Accessibility Options

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# Breaking changes

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# C4 Diagrams

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# Class diagrams

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# Configuration

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# Development and Contribution 🙌

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
---

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# Directives

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# Entity Relationship Diagrams

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# Examples

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# Frequently Asked Questions

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# Flowcharts - Basic Syntax

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# Gantt diagrams

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# Gitgraph Diagrams

View File

@ -1,6 +1,6 @@
<!DOCTYPE html>
<html lang="en">
<head>
<!--# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.--><head>
<meta charset="UTF-8" />
<title>
mermaid - Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams,

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# Integrations

View File

@ -1 +1 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.

View File

@ -1,6 +1,6 @@
<!DOCTYPE html>
<html lang="en">
<head>
<!--# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.--><head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
@ -64,7 +64,7 @@
using Mermaid.js.
</p>
<a
href="https://www.amazon.com/Official-Guide-Mermaid-js-beautiful-flowcharts-dp-1801078025/dp/1801078025/ref=mt_other?_encoding=UTF8&me=&qid=1628153965"
href="https://www.amazon.com/Official-Guide-Mermaid-js-beautiful-flowcharts-dp-1801078025/dp/1801078025/ref=mt_other?_encoding=UTF8&amp;me=&amp;qid=1628153965"
>
<button
style="background: #ffa41c; border: 1px solid #ff8f00"
@ -322,7 +322,7 @@
</p>
</h3>
<a
href="https://www.amazon.com/Official-Guide-Mermaid-js-beautiful-flowcharts-dp-1801078025/dp/1801078025/ref=mt_other?_encoding=UTF8&me=&qid=1628153965"
href="https://www.amazon.com/Official-Guide-Mermaid-js-beautiful-flowcharts-dp-1801078025/dp/1801078025/ref=mt_other?_encoding=UTF8&amp;me=&amp;qid=1628153965"
>
<button
style="background: #ffa41c; border: 1px solid #ff8f00"

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# mermaid CLI

View File

@ -1,9 +1,7 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# Mindmap
**Edit this Page** [![N|Solid](img/GitHub-Mark-32px.png)](https://github.com/mermaid-js/mermaid/blob/develop/src/docs/mindmap.md)
> Mindmap: This is an experimental diagram for now. The syntax and properties can change in future releases. The syntax is stabel except for the icon integration which is the experimental part.
"A mind map is a diagram used to visually organize information into a hierarchy, showing relationships among pieces of the whole. It is often created around a single concept, drawn as an image in the center of a blank page, to which associated representations of ideas such as images, words and parts of words are added. Major ideas are connected directly to the central concept, and other ideas branch out from those major ideas." Wikipedia

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# Advanced n00b mermaid (Coming soon..)

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# A Mermaid User-Guide for Beginners

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# Overview for Beginners

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# Diagram Syntax

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# Adding a New Diagram/Chart 📊

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# Pie chart diagrams

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# Requirement Diagram

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# Security

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# Sequence diagrams

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# State diagrams

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# Theme Configuration

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# Upgrading

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# Usage

View File

@ -1,4 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.
# User Journey Diagram

View File

@ -12,6 +12,10 @@ module.exports = {
{ 'token-stack': true },
],
},
coveragePathIgnorePatterns: [
'/node_modules/',
'^.+\\.jison$', // might be able to fix in future if .jison adds source-map support
],
transformIgnorePatterns: ['/node_modules/(?!dagre-d3-renderer/lib|khroma).*\\.js'],
testPathIgnorePatterns: ['/node_modules/', '.cache', './cypress'],
moduleNameMapper: {

View File

@ -1,26 +1,12 @@
import { MermaidConfig } from '../config.type';
export type DiagramDetector = (text: string) => boolean;
export type DiagramDetector = (text: string, config?: MermaidConfig) => boolean;
const directive =
/[%]{2}[{]\s*(?:(?:(\w+)\s*:|(\w+))\s*(?:(?:(\w+))|((?:(?![}][%]{2}).|\r?\n)*))?\s*)(?:[}][%]{2})?/gi;
const anyComment = /\s*%%.*\n/gm;
const detectors: Record<string, DiagramDetector> = {};
const diagramMatchers: Record<string, RegExp> = {
c4: /^\s*C4Context|C4Container|C4Component|C4Dynamic|C4Deployment/,
sequence: /^\s*sequenceDiagram/,
gantt: /^\s*gantt/,
classDiagram: /^\s*classDiagram-v2/,
stateDiagram: /^\s*stateDiagram-v2/,
'flowchart-v2': /^\s*flowchart/, // Might need to add |graph to fix #3391
info: /^\s*info/,
pie: /^\s*pie/,
er: /^\s*erDiagram/,
journey: /^\s*journey/,
// gitGraph: /^\s*gitGraph/,
requirement: /^\s*requirement(Diagram)?/,
};
/**
* @function detectType Detects the type of the graph text. Takes into consideration the possible
@ -47,28 +33,9 @@ const diagramMatchers: Record<string, RegExp> = {
*/
export const detectType = function (text: string, config?: MermaidConfig): string {
text = text.replace(directive, '').replace(anyComment, '\n');
for (const [diagram, matcher] of Object.entries(diagramMatchers)) {
if (text.match(matcher)) {
return diagram;
}
}
if (text.match(/^\s*classDiagram/)) {
if (config?.class?.defaultRenderer === 'dagre-wrapper') return 'classDiagram';
return 'class';
}
if (text.match(/^\s*stateDiagram/)) {
if (config?.state?.defaultRenderer === 'dagre-wrapper') return 'stateDiagram';
return 'state';
}
if (config?.flowchart?.defaultRenderer === 'dagre-wrapper') {
return 'flowchart-v2';
}
for (const [key, detector] of Object.entries(detectors)) {
if (detector(text)) {
if (detector(text, config)) {
return key;
}
}

View File

@ -1,20 +1,310 @@
import { registerDiagram } from './diagramAPI';
import * as mindmapDb from '../diagrams/mindmap/mindmapDb';
import mindmapRenderer from '../diagrams/mindmap/mindmapRenderer';
// @ts-ignore: TODO Fix ts errors
import mindmapParser from '../diagrams/mindmap/parser/mindmap';
import * as mindmapDb from '../diagrams/mindmap/mindmapDb';
import { mindmapDetector } from '../diagrams/mindmap/mindmapDetector';
import mindmapRenderer from '../diagrams/mindmap/mindmapRenderer';
import mindmapStyles from '../diagrams/mindmap/styles';
import gitGraphDb from '../diagrams/git/gitGraphAst';
import gitGraphRenderer from '../diagrams/git/gitGraphRenderer';
// @ts-ignore: TODO Fix ts errors
import gitGraphParser from '../diagrams/git/parser/gitGraph';
import { gitGraphDetector } from '../diagrams/git/gitGraphDetector';
import gitGraphDb from '../diagrams/git/gitGraphAst';
import gitGraphRenderer from '../diagrams/git/gitGraphRenderer';
import gitGraphStyles from '../diagrams/git/styles';
// @ts-ignore: TODO Fix ts errors
import c4Parser from '../diagrams/c4/parser/c4Diagram';
import { c4Detector } from '../diagrams/c4/c4Detector';
import c4Db from '../diagrams/c4/c4Db';
import c4Renderer from '../diagrams/c4/c4Renderer';
import c4Styles from '../diagrams/c4/styles';
// @ts-ignore: TODO Fix ts errors
import classParser from '../diagrams/class/parser/classDiagram';
import { classDetector } from '../diagrams/class/classDetector';
import { classDetectorV2 } from '../diagrams/class/classDetector-V2';
import classDb from '../diagrams/class/classDb';
import classRenderer from '../diagrams/class/classRenderer';
import classRendererV2 from '../diagrams/class/classRenderer-v2';
import classStyles from '../diagrams/class/styles';
// @ts-ignore: TODO Fix ts errors
import erParser from '../diagrams/er/parser/erDiagram';
import { erDetector } from '../diagrams/er/erDetector';
import erDb from '../diagrams/er/erDb';
import erRenderer from '../diagrams/er/erRenderer';
import erStyles from '../diagrams/er/styles';
// @ts-ignore: TODO Fix ts errors
import flowParser from '../diagrams/flowchart/parser/flow';
import { flowDetector } from '../diagrams/flowchart/flowDetector';
import { flowDetectorV2 } from '../diagrams/flowchart/flowDetector-v2';
import flowDb from '../diagrams/flowchart/flowDb';
import flowRenderer from '../diagrams/flowchart/flowRenderer';
import flowRendererV2 from '../diagrams/flowchart/flowRenderer-v2';
import flowStyles from '../diagrams/flowchart/styles';
// @ts-ignore: TODO Fix ts errors
import ganttParser from '../diagrams/gantt/parser/gantt';
import { ganttDetector } from '../diagrams/gantt/ganttDetector';
import ganttDb from '../diagrams/gantt/ganttDb';
import ganttRenderer from '../diagrams/gantt/ganttRenderer';
import ganttStyles from '../diagrams/gantt/styles';
// @ts-ignore: TODO Fix ts errors
import infoParser from '../diagrams/info/parser/info';
import infoDb from '../diagrams/info/infoDb';
import infoRenderer from '../diagrams/info/infoRenderer';
import { infoDetector } from '../diagrams/info/infoDetector';
import infoStyles from '../diagrams/info/styles';
// @ts-ignore: TODO Fix ts errors
import pieParser from '../diagrams/pie/parser/pie';
import { pieDetector } from '../diagrams/pie/pieDetector';
import pieDb from '../diagrams/pie/pieDb';
import pieRenderer from '../diagrams/pie/pieRenderer';
import pieStyles from '../diagrams/pie/styles';
// @ts-ignore: TODO Fix ts errors
import requirementParser from '../diagrams/requirement/parser/requirementDiagram';
import { requirementDetector } from '../diagrams/requirement/requirementDetector';
import requirementDb from '../diagrams/requirement/requirementDb';
import requirementRenderer from '../diagrams/requirement/requirementRenderer';
import requirementStyles from '../diagrams/requirement/styles';
// @ts-ignore: TODO Fix ts errors
import sequenceParser from '../diagrams/sequence/parser/sequenceDiagram';
import { sequenceDetector } from '../diagrams/sequence/sequenceDetector';
import sequenceDb from '../diagrams/sequence/sequenceDb';
import sequenceRenderer from '../diagrams/sequence/sequenceRenderer';
import sequenceStyles from '../diagrams/sequence/styles';
// @ts-ignore: TODO Fix ts errors
import stateParser from '../diagrams/state/parser/stateDiagram';
import { stateDetector } from '../diagrams/state/stateDetector';
import { stateDetectorV2 } from '../diagrams/state/stateDetector-V2';
import stateDb from '../diagrams/state/stateDb';
import stateRenderer from '../diagrams/state/stateRenderer';
import stateRendererV2 from '../diagrams/state/stateRenderer-v2';
import stateStyles from '../diagrams/state/styles';
// @ts-ignore: TODO Fix ts errors
import journeyParser from '../diagrams/user-journey/parser/journey';
import { journeyDetector } from '../diagrams/user-journey/journeyDetector';
import journeyDb from '../diagrams/user-journey/journeyDb';
import journeyRenderer from '../diagrams/user-journey/journeyRenderer';
import journeyStyles from '../diagrams/user-journey/styles';
export const addDiagrams = () => {
// Register mindmap and other built-in diagrams
registerDiagram(
'c4',
{
parser: c4Parser,
db: c4Db,
renderer: c4Renderer,
styles: c4Styles,
init: (cnf) => {
c4Renderer.setConf(cnf.c4);
},
},
c4Detector
);
registerDiagram(
'class',
{
parser: classParser,
db: classDb,
renderer: classRenderer,
styles: classStyles,
init: (cnf) => {
if (!cnf.class) {
cnf.class = {};
}
cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
classDb.clear();
},
},
classDetector
);
registerDiagram(
'classDiagram',
{
parser: classParser,
db: classDb,
renderer: classRendererV2,
styles: classStyles,
init: (cnf) => {
if (!cnf.class) {
cnf.class = {};
}
cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
classDb.clear();
},
},
classDetectorV2
);
registerDiagram(
'er',
{
parser: erParser,
db: erDb,
renderer: erRenderer,
styles: erStyles,
},
erDetector
);
registerDiagram(
'gantt',
{
parser: ganttParser,
db: ganttDb,
renderer: ganttRenderer,
styles: ganttStyles,
},
ganttDetector
);
registerDiagram(
'info',
{
parser: infoParser,
db: infoDb,
renderer: infoRenderer,
styles: infoStyles,
},
infoDetector
);
registerDiagram(
'pie',
{
parser: pieParser,
db: pieDb,
renderer: pieRenderer,
styles: pieStyles,
},
pieDetector
);
registerDiagram(
'requirement',
{
parser: requirementParser,
db: requirementDb,
renderer: requirementRenderer,
styles: requirementStyles,
},
requirementDetector
);
registerDiagram(
'sequence',
{
parser: sequenceParser,
db: sequenceDb,
renderer: sequenceRenderer,
styles: sequenceStyles,
init: (cnf) => {
if (!cnf.sequence) {
cnf.sequence = {};
}
cnf.sequence.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
if ('sequenceDiagram' in cnf) {
throw new Error(
'`mermaid config.sequenceDiagram` has been renamed to `config.sequence`. Please update your mermaid config.'
);
}
sequenceDb.setWrap(cnf.wrap);
sequenceRenderer.setConf(cnf.sequence);
},
},
sequenceDetector
);
registerDiagram(
'state',
{
parser: stateParser,
db: stateDb,
renderer: stateRenderer,
styles: stateStyles,
init: (cnf) => {
if (!cnf.state) {
cnf.state = {};
}
cnf.state.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
stateDb.clear();
},
},
stateDetector
);
registerDiagram(
'stateDiagram',
{
parser: stateParser,
db: stateDb,
renderer: stateRendererV2,
styles: stateStyles,
init: (cnf) => {
if (!cnf.state) {
cnf.state = {};
}
cnf.state.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
stateDb.clear();
},
},
stateDetectorV2
);
registerDiagram(
'journey',
{
parser: journeyParser,
db: journeyDb,
renderer: journeyRenderer,
styles: journeyStyles,
init: (cnf) => {
journeyRenderer.setConf(cnf.journey);
journeyDb.clear();
},
},
journeyDetector
);
registerDiagram(
'flowchart',
{
parser: flowParser,
db: flowDb,
renderer: flowRendererV2,
styles: flowStyles,
init: (cnf) => {
flowRenderer.setConf(cnf.flowchart);
if (!cnf.flowchart) {
cnf.flowchart = {};
}
cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
flowDb.clear();
flowDb.setGen('gen-1');
},
},
flowDetector
);
registerDiagram(
'flowchart-v2',
{
parser: flowParser,
db: flowDb,
renderer: flowRendererV2,
styles: flowStyles,
init: (cnf) => {
flowRendererV2.setConf(cnf.flowchart);
if (!cnf.flowchart) {
cnf.flowchart = {};
}
cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
flowDb.clear();
flowDb.setGen('gen-2');
},
},
flowDetectorV2
);
registerDiagram(
'gitGraph',
{ parser: gitGraphParser, db: gitGraphDb, renderer: gitGraphRenderer, styles: gitGraphStyles },

View File

@ -1,5 +1,8 @@
import { detectType } from './detectType';
import { getDiagram, registerDiagram } from './diagramAPI';
import { addDiagrams } from './diagram-orchestration';
addDiagrams();
describe('DiagramAPI', () => {
it('should return default diagrams', () => {

View File

@ -1,70 +1,23 @@
import c4Db from '../diagrams/c4/c4Db';
import c4Renderer from '../diagrams/c4/c4Renderer';
import c4Styles from '../diagrams/c4/styles';
// @ts-ignore: TODO Fix ts errors
import c4Parser from '../diagrams/c4/parser/c4Diagram';
import classDb from '../diagrams/class/classDb';
import classRenderer from '../diagrams/class/classRenderer';
import classRendererV2 from '../diagrams/class/classRenderer-v2';
import classStyles from '../diagrams/class/styles';
// @ts-ignore: TODO Fix ts errors
import classParser from '../diagrams/class/parser/classDiagram';
import erDb from '../diagrams/er/erDb';
import erRenderer from '../diagrams/er/erRenderer';
// @ts-ignore: TODO Fix ts errors
import erParser from '../diagrams/er/parser/erDiagram';
import erStyles from '../diagrams/er/styles';
import flowDb from '../diagrams/flowchart/flowDb';
import flowRenderer from '../diagrams/flowchart/flowRenderer';
import flowRendererV2 from '../diagrams/flowchart/flowRenderer-v2';
import flowStyles from '../diagrams/flowchart/styles';
// @ts-ignore: TODO Fix ts errors
import flowParser from '../diagrams/flowchart/parser/flow';
import ganttDb from '../diagrams/gantt/ganttDb';
import ganttRenderer from '../diagrams/gantt/ganttRenderer';
// @ts-ignore: TODO Fix ts errors
import ganttParser from '../diagrams/gantt/parser/gantt';
import ganttStyles from '../diagrams/gantt/styles';
import infoDb from '../diagrams/info/infoDb';
import infoRenderer from '../diagrams/info/infoRenderer';
// @ts-ignore: TODO Fix ts errors
import infoParser from '../diagrams/info/parser/info';
import infoStyles from '../diagrams/info/styles';
// @ts-ignore: TODO Fix ts errors
import pieParser from '../diagrams/pie/parser/pie';
import pieDb from '../diagrams/pie/pieDb';
import pieRenderer from '../diagrams/pie/pieRenderer';
import pieStyles from '../diagrams/pie/styles';
// @ts-ignore: TODO Fix ts errors
import requirementParser from '../diagrams/requirement/parser/requirementDiagram';
import requirementDb from '../diagrams/requirement/requirementDb';
import requirementRenderer from '../diagrams/requirement/requirementRenderer';
import requirementStyles from '../diagrams/requirement/styles';
// @ts-ignore: TODO Fix ts errors
import sequenceParser from '../diagrams/sequence/parser/sequenceDiagram';
import sequenceDb from '../diagrams/sequence/sequenceDb';
import sequenceRenderer from '../diagrams/sequence/sequenceRenderer';
import sequenceStyles from '../diagrams/sequence/styles';
// @ts-ignore: TODO Fix ts errors
import stateParser from '../diagrams/state/parser/stateDiagram';
import stateDb from '../diagrams/state/stateDb';
import stateRenderer from '../diagrams/state/stateRenderer';
import stateRendererV2 from '../diagrams/state/stateRenderer-v2';
import stateStyles from '../diagrams/state/styles';
import journeyDb from '../diagrams/user-journey/journeyDb';
import journeyRenderer from '../diagrams/user-journey/journeyRenderer';
import journeyStyles from '../diagrams/user-journey/styles';
// @ts-ignore: TODO Fix ts errors
import journeyParser from '../diagrams/user-journey/parser/journey';
import { addDetector, DiagramDetector } from './detectType';
import { log as _log } from '../logger';
import { addDetector, DiagramDetector as _DiagramDetector } from './detectType';
import { log as _log, setLogLevel as _setLogLevel } from '../logger';
import { getConfig as _getConfig } from '../config';
import { sanitizeText as _sanitizeText } from '../diagrams/common/common';
import { MermaidConfig } from '../config.type';
import { setupGraphViewbox as _setupGraphViewbox } from '../setupGraphViewbox';
import { addStylesForDiagram } from '../styles';
/*
Packaging and exposing resources for externa diagrams so that they can import
diagramAPI and have access to selct parts of mermaid common code reqiored to
create diagrams worling like the internal diagrams.
*/
export const log = _log;
export const setLogLevel = _setLogLevel;
export type DiagramDetector = _DiagramDetector;
export const getConfig = _getConfig;
export const sanitizeText = (text: string) => _sanitizeText(text, getConfig());
export const setupGraphViewbox = _setupGraphViewbox;
export interface DiagramDefinition {
db: any;
renderer: any;
@ -73,158 +26,7 @@ export interface DiagramDefinition {
init?: (config: MermaidConfig) => void;
}
const diagrams: Record<string, DiagramDefinition> = {
c4: {
db: c4Db,
renderer: c4Renderer,
parser: c4Parser,
init: (cnf) => {
c4Renderer.setConf(cnf.c4);
},
styles: c4Styles,
},
class: {
db: classDb,
renderer: classRenderer,
parser: classParser,
init: (cnf) => {
if (!cnf.class) {
cnf.class = {};
}
cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
classDb.clear();
},
styles: classStyles,
},
classDiagram: {
db: classDb,
renderer: classRendererV2,
parser: classParser,
init: (cnf) => {
if (!cnf.class) {
cnf.class = {};
}
cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
classDb.clear();
},
styles: classStyles,
},
er: {
db: erDb,
renderer: erRenderer,
parser: erParser,
styles: erStyles,
},
flowchart: {
db: flowDb,
renderer: flowRenderer,
parser: flowParser,
init: (cnf) => {
flowRenderer.setConf(cnf.flowchart);
if (!cnf.flowchart) {
cnf.flowchart = {};
}
cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
flowDb.clear();
flowDb.setGen('gen-1');
},
styles: flowStyles,
},
'flowchart-v2': {
db: flowDb,
renderer: flowRendererV2,
parser: flowParser,
init: (cnf) => {
flowRendererV2.setConf(cnf.flowchart);
if (!cnf.flowchart) {
cnf.flowchart = {};
}
cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
flowDb.clear();
flowDb.setGen('gen-2');
},
styles: flowStyles,
},
gantt: {
db: ganttDb,
renderer: ganttRenderer,
parser: ganttParser,
styles: ganttStyles,
},
info: {
db: infoDb,
renderer: infoRenderer,
parser: infoParser,
styles: infoStyles,
},
pie: {
db: pieDb,
renderer: pieRenderer,
parser: pieParser,
styles: pieStyles,
},
requirement: {
db: requirementDb,
renderer: requirementRenderer,
parser: requirementParser,
styles: requirementStyles,
},
sequence: {
db: sequenceDb,
renderer: sequenceRenderer,
parser: sequenceParser,
init: (cnf) => {
if (!cnf.sequence) {
cnf.sequence = {};
}
cnf.sequence.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
if ('sequenceDiagram' in cnf) {
throw new Error(
'`mermaid config.sequenceDiagram` has been renamed to `config.sequence`. Please update your mermaid config.'
);
}
sequenceDb.setWrap(cnf.wrap);
sequenceRenderer.setConf(cnf.sequence);
},
styles: sequenceStyles,
},
state: {
db: stateDb,
renderer: stateRenderer,
parser: stateParser,
init: (cnf) => {
if (!cnf.state) {
cnf.state = {};
}
cnf.state.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
stateDb.clear();
},
styles: stateStyles,
},
stateDiagram: {
db: stateDb,
renderer: stateRendererV2,
parser: stateParser,
init: (cnf) => {
if (!cnf.state) {
cnf.state = {};
}
cnf.state.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
stateDb.clear();
},
styles: stateStyles,
},
journey: {
db: journeyDb,
renderer: journeyRenderer,
parser: journeyParser,
init: (cnf) => {
journeyRenderer.setConf(cnf.journey);
journeyDb.clear();
},
styles: journeyStyles,
},
};
const diagrams: Record<string, DiagramDefinition> = {};
export const registerDiagram = (
id: string,
@ -245,8 +47,3 @@ export const getDiagram = (name: string): DiagramDefinition => {
}
throw new Error(`Diagram ${name} not found.`);
};
export const log = _log;
export const getConfig = _getConfig;
export const sanitizeText = (text: string) => _sanitizeText(text, getConfig());
export const setupGraphViewbox = _setupGraphViewbox;

View File

@ -0,0 +1,5 @@
import type { DiagramDetector } from '../../diagram-api/detectType';
export const c4Detector: DiagramDetector = (txt) => {
return txt.match(/^\s*C4Context|C4Container|C4Component|C4Dynamic|C4Deployment/) !== null;
};

View File

@ -0,0 +1,9 @@
import type { DiagramDetector } from '../../diagram-api/detectType';
export const classDetectorV2: DiagramDetector = (txt, config) => {
// If we have confgured to use dagre-wrapper then we should return true in this function for classDiagram code thus making it use the new class diagram
if (txt.match(/^\s*classDiagram/) !== null && config?.class?.defaultRenderer === 'dagre-wrapper')
return true;
// We have not opted to use the new renderer so we should return true if we detect a class diagram
return txt.match(/^\s*classDiagram-v2/) !== null;
};

View File

@ -0,0 +1,8 @@
import type { DiagramDetector } from '../../diagram-api/detectType';
export const classDetector: DiagramDetector = (txt, config) => {
// If we have confgured to use dagre-wrapper then we should never return true in this function
if (config?.class?.defaultRenderer === 'dagre-wrapper') return false;
// We have not opted to use the new renderer so we should return true if we detect a class diagram
return txt.match(/^\s*classDiagram/) !== null;
};

View File

@ -0,0 +1,5 @@
import type { DiagramDetector } from '../../diagram-api/detectType';
export const erDetector: DiagramDetector = (txt) => {
return txt.match(/^\s*erDiagram/) !== null;
};

View File

@ -0,0 +1,8 @@
import type { DiagramDetector } from '../../diagram-api/detectType';
export const flowDetectorV2: DiagramDetector = (txt, config) => {
// If we have confgured to use dagre-wrapper then we should return true in this function for graph code thus making it use the new flowchart diagram
if (config?.flowchart?.defaultRenderer === 'dagre-wrapper' && txt.match(/^\s*graph/) !== null)
return true;
return txt.match(/^\s*flowchart/) !== null;
};

View File

@ -0,0 +1,8 @@
import type { DiagramDetector } from '../../diagram-api/detectType';
export const flowDetector: DiagramDetector = (txt, config) => {
// If we have confired to only use new flow charts this function shohuld always return false
// as in not signalling true for a legacy flowchart
if (config?.flowchart?.defaultRenderer === 'dagre-wrapper') return false;
return txt.match(/^\s*graph/) !== null;
};

View File

@ -0,0 +1,154 @@
import flowDb from './flowDb';
import flowParser from './parser/flow';
import flowRenderer from './flowRenderer';
import Diagram from '../../Diagram';
import { addDiagrams } from '../../diagram-api/diagram-orchestration';
addDiagrams();
afterEach(() => {
jest.restoreAllMocks();
});
describe('when using mermaid and ', function () {
describe('when calling addEdges ', function () {
beforeEach(function () {
flowParser.parser.yy = flowDb;
flowDb.clear();
flowDb.setGen('gen-2');
});
it('should handle edges with text', function () {
const diag = new Diagram('graph TD;A-->|text ex|B;');
diag.db.getVertices();
const edges = diag.db.getEdges();
const mockG = {
setEdge: function (start, end, options) {
expect(start).toContain('flowchart-A-');
expect(end).toContain('flowchart-B-');
expect(options.arrowhead).toBe('normal');
expect(options.label.match('text ex')).toBeTruthy();
},
};
flowRenderer.addEdges(edges, mockG, diag);
});
it('should handle edges without text', function () {
const diag = new Diagram('graph TD;A-->B;');
diag.db.getVertices();
const edges = diag.db.getEdges();
const mockG = {
setEdge: function (start, end, options) {
expect(start).toContain('flowchart-A-');
expect(end).toContain('flowchart-B-');
expect(options.arrowhead).toBe('normal');
},
};
flowRenderer.addEdges(edges, mockG, diag);
});
it('should handle open-ended edges', function () {
const diag = new Diagram('graph TD;A---B;');
diag.db.getVertices();
const edges = diag.db.getEdges();
const mockG = {
setEdge: function (start, end, options) {
expect(start).toContain('flowchart-A-');
expect(end).toContain('flowchart-B-');
expect(options.arrowhead).toBe('none');
},
};
flowRenderer.addEdges(edges, mockG, diag);
});
it('should handle edges with styles defined', function () {
const diag = new Diagram('graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2;');
diag.db.getVertices();
const edges = diag.db.getEdges();
const mockG = {
setEdge: function (start, end, options) {
expect(start).toContain('flowchart-A-');
expect(end).toContain('flowchart-B-');
expect(options.arrowhead).toBe('none');
expect(options.style).toBe('stroke:val1;stroke-width:val2;fill:none;');
},
};
flowRenderer.addEdges(edges, mockG, diag);
});
it('should handle edges with interpolation defined', function () {
const diag = new Diagram('graph TD;A---B; linkStyle 0 interpolate basis');
diag.db.getVertices();
const edges = diag.db.getEdges();
const mockG = {
setEdge: function (start, end, options) {
expect(start).toContain('flowchart-A-');
expect(end).toContain('flowchart-B-');
expect(options.arrowhead).toBe('none');
expect(options.curve).toBe('basis'); // mocked as string
},
};
flowRenderer.addEdges(edges, mockG, diag);
});
it('should handle edges with text and styles defined', function () {
const diag = new Diagram(
'graph TD;A---|the text|B; linkStyle 0 stroke:val1,stroke-width:val2;'
);
diag.db.getVertices();
const edges = diag.db.getEdges();
const mockG = {
setEdge: function (start, end, options) {
expect(start).toContain('flowchart-A-');
expect(end).toContain('flowchart-B-');
expect(options.arrowhead).toBe('none');
expect(options.label.match('the text')).toBeTruthy();
expect(options.style).toBe('stroke:val1;stroke-width:val2;fill:none;');
},
};
flowRenderer.addEdges(edges, mockG, diag);
});
it('should set fill to "none" by default when handling edges', function () {
const diag = new Diagram('graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2;');
diag.db.getVertices();
const edges = diag.db.getEdges();
const mockG = {
setEdge: function (start, end, options) {
expect(start).toContain('flowchart-A-');
expect(end).toContain('flowchart-B');
expect(options.arrowhead).toBe('none');
expect(options.style).toBe('stroke:val1;stroke-width:val2;fill:none;');
},
};
flowRenderer.addEdges(edges, mockG, diag);
});
it('should not set fill to none if fill is set in linkStyle', function () {
const diag = new Diagram(
'graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2,fill:blue;'
);
diag.db.getVertices();
const edges = diag.db.getEdges();
const mockG = {
setEdge: function (start, end, options) {
expect(start).toContain('flowchart-A-');
expect(end).toContain('flowchart-B-');
expect(options.arrowhead).toBe('none');
expect(options.style).toBe('stroke:val1;stroke-width:val2;fill:blue;');
},
};
flowRenderer.addEdges(edges, mockG, diag);
});
});
});

View File

@ -0,0 +1,5 @@
import type { DiagramDetector } from '../../diagram-api/detectType';
export const ganttDetector: DiagramDetector = (txt) => {
return txt.match(/^\s*gantt/) !== null;
};

View File

@ -363,6 +363,34 @@ describe('when parsing a gitGraph', function () {
expect(Object.keys(parser.yy.getBranches()).length).toBe(2);
});
it('should allow branch names starting with unusual prefixes', function () {
const str = `gitGraph:
commit
%% branch names starting with numbers are not recommended, but are supported by git
branch branch01
branch checkout02
branch cherry-pick03
branch branch/example-branch
branch merge/test_merge
`;
parser.parse(str);
const commits = parser.yy.getCommits();
expect(Object.keys(commits).length).toBe(1);
expect(parser.yy.getCurrentBranch()).toBe('merge/test_merge');
expect(parser.yy.getDirection()).toBe('LR');
expect(Object.keys(parser.yy.getBranches()).length).toBe(6);
expect(Object.keys(parser.yy.getBranches())).toEqual(
expect.arrayContaining([
'branch01',
'checkout02',
'cherry-pick03',
'branch/example-branch',
'merge/test_merge',
])
);
});
it('should handle new branch checkout', function () {
const str = `gitGraph:
commit

View File

@ -36,7 +36,7 @@ accDescr\s*"{"\s* { this.begin("ac
\#[^\n]* /* skip comments */
\%%[^\n]* /* skip comments */
"gitGraph" return 'GG';
"commit" return 'COMMIT';
commit(?=\s|$) return 'COMMIT';
"id:" return 'COMMIT_ID';
"type:" return 'COMMIT_TYPE';
"msg:" return 'COMMIT_MSG';
@ -44,12 +44,12 @@ accDescr\s*"{"\s* { this.begin("ac
"REVERSE" return 'REVERSE';
"HIGHLIGHT" return 'HIGHLIGHT';
"tag:" return 'COMMIT_TAG';
"branch" return 'BRANCH';
branch(?=\s|$) return 'BRANCH';
"order:" return 'ORDER';
"merge" return 'MERGE';
"cherry-pick" return 'CHERRY_PICK';
merge(?=\s|$) return 'MERGE';
cherry-pick(?=\s|$) return 'CHERRY_PICK';
// "reset" return 'RESET';
"checkout" return 'CHECKOUT';
checkout(?=\s|$) return 'CHECKOUT';
"LR" return 'DIR';
"BT" return 'DIR';
":" return ':';

View File

@ -0,0 +1,5 @@
import type { DiagramDetector } from '../../diagram-api/detectType';
export const infoDetector: DiagramDetector = (txt) => {
return txt.match(/^\s*info/) !== null;
};

View File

@ -1,6 +1,6 @@
import { parser as mindmap } from './parser/mindmap';
import * as mindmapDB from './mindmapDb';
import { setLogLevel } from '../../logger';
import { setLogLevel } from '../../diagram-api/diagramAPI';
describe('when parsing a mindmap ', function () {
beforeEach(function () {

View File

@ -1,6 +1,5 @@
/** Created by knut on 15-01-14. */
import { sanitizeText, getConfig } from '../../diagram-api/diagramAPI';
import { log as _log } from '../../logger';
import { sanitizeText, getConfig, log as _log } from '../../diagram-api/diagramAPI';
let nodes = [];
let cnt = 0;

View File

@ -1,4 +1,3 @@
const lineBreakRegex = /<br\s*\/?>/gi;
import { select } from 'd3';
import * as db from './mindmapDb';
@ -15,7 +14,6 @@ function wrap(text, width) {
.reverse(),
word,
line = [],
lineNumber = 0,
lineHeight = 1.1, // ems
y = text.attr('y'),
dy = parseFloat(text.attr('dy')),

View File

@ -0,0 +1,5 @@
import type { DiagramDetector } from '../../diagram-api/detectType';
export const pieDetector: DiagramDetector = (txt) => {
return txt.match(/^\s*pie/) !== null;
};

View File

@ -0,0 +1,5 @@
import type { DiagramDetector } from '../../diagram-api/detectType';
export const requirementDetector: DiagramDetector = (txt) => {
return txt.match(/^\s*requirement(Diagram)?/) !== null;
};

View File

@ -0,0 +1,5 @@
import type { DiagramDetector } from '../../diagram-api/detectType';
export const sequenceDetector: DiagramDetector = (txt) => {
return txt.match(/^\s*sequenceDiagram/) !== null;
};

View File

@ -1,12 +1,8 @@
// import sequence from './parser/sequenceDiagram';
// import sequenceDb from './sequenceDb';
import * as configApi from '../../config';
// import renderer from './sequenceRenderer';
import mermaidAPI from '../../mermaidAPI';
// import '../../diagram-api/diagramAPI';
import Diagram from '../../Diagram';
// console.log('sequenceDiagram', sequenceDb);
import { addDiagrams } from '../../diagram-api/diagram-orchestration';
addDiagrams();
/**
* @param conf
* @param key

View File

@ -0,0 +1,8 @@
import type { DiagramDetector } from '../../diagram-api/detectType';
export const stateDetectorV2: DiagramDetector = (text, config) => {
if (text.match(/^\s*stateDiagram-v2/) !== null) return true;
if (text.match(/^\s*stateDiagram/) && config?.state?.defaultRenderer === 'dagre-wrapper')
return true;
return false;
};

View File

@ -0,0 +1,8 @@
import type { DiagramDetector } from '../../diagram-api/detectType';
export const stateDetector: DiagramDetector = (txt, config) => {
// If we have confired to only use new state diagrams this function should always return false
// as in not signalling true for a legacy state diagram
if (config?.state?.defaultRenderer === 'dagre-wrapper') return false;
return txt.match(/^\s*stateDiagram/) !== null;
};

View File

@ -0,0 +1,5 @@
import type { DiagramDetector } from '../../diagram-api/detectType';
export const journeyDetector: DiagramDetector = (txt) => {
return txt.match(/^\s*journey/) !== null;
};

View File

@ -1,42 +1,152 @@
/* eslint-disable no-console */
import { remark } from 'remark';
import type { Code, Root } from 'mdast';
/**
* @file Transform documentation source files into files suitable for publishing
* and optionally copy the transformed files from the source directory to the
* directory used for the final, published documentation directory. The list
* of files transformed and copied to final documentation directory are logged
* to the console. If a file in the source directory has the same contents in
* the final directory, nothing is done (the final directory is up-to-date).
* @example
* docs
* Run with no option flags
*
* @example
* docs --verify
* If the --verify option is used, it only _verifies_ that the final directory has been updated with the transformed files in the source directory.
* No files will be copied to the final documentation directory, but the list of files to be changed is shown on the console.
* If the final documentation directory does not have the transformed files from source directory
* - a message to the console will show that this command should be run without the --verify flag so that the final directory is updated, and
* - it will return a fail exit code (1)
*
* @example
* docs --git
* If the --git option is used, the command `git add docs` will be run after all transformations (and/or verifications) have completed successfully
* If not files were transformed, the git command is not run.
*
* @todo Ensure that the documentation source and final paths are correct by
* using process.cwd() to get their absolute paths. Ensures that the location
* of those 2 directories is not dependent on where this file resides.
*
* @todo Write a test file for this. (Will need to be able to deal .mts file.
* Jest has trouble with it.)
*/
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs';
// @ts-ignore: no typings
import flatmap from 'unist-util-flatmap';
import { globby } from 'globby';
import { join, dirname } from 'path';
import { exec } from 'child_process';
import { globby } from 'globby';
import { JSDOM } from 'jsdom';
import type { Code, Root } from 'mdast';
import { join, dirname } from 'path';
import prettier from 'prettier';
import { remark } from 'remark';
// @ts-ignore No typescript declaration file
import flatmap from 'unist-util-flatmap';
const verify = process.argv.includes('--verify');
const git = process.argv.includes('--git');
let fileChanged = false;
// Possible Improvement: combine with lint-staged to only copy files that have changed
const prepareOutFile = (file: string): string => {
const outFile = join('docs', file.replace('src/docs/', ''));
mkdirSync(dirname(outFile), { recursive: true });
return outFile;
const SOURCE_DOCS_DIR = 'src/docs';
const FINAL_DOCS_DIR = 'docs';
const AUTOGENERATED_TEXT = `# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in ${SOURCE_DOCS_DIR}.`;
const LOGMSG_TRANSFORMED = 'transformed';
const LOGMSG_TO_BE_TRANSFORMED = 'to be transformed';
const LOGMSG_COPIED = `, and copied to ${FINAL_DOCS_DIR}`;
const WARN_DOCSDIR_DOESNT_MATCH = `Changed files were transformed in ${SOURCE_DOCS_DIR} but do not match the files in ${FINAL_DOCS_DIR}. Please run yarn docs:build after making changes to ${SOURCE_DOCS_DIR} to update the ${FINAL_DOCS_DIR} directory with the transformed files.`;
const verifyOnly: boolean = process.argv.includes('--verify');
const git: boolean = process.argv.includes('--git');
// TODO: Read from .prettierrc?
const prettierConfig: prettier.Config = {
useTabs: false,
tabWidth: 2,
endOfLine: 'auto',
printWidth: 100,
singleQuote: true,
};
const verifyAndCopy = (file: string, content?: string) => {
const outFile = prepareOutFile(file);
const existingBuffer = existsSync(outFile) ? readFileSync(outFile) : Buffer.from('#NEW FILE#');
const newBuffer = content ? Buffer.from(content) : readFileSync(file);
let filesWereTransformed = false;
/**
* Given a source file name and path, return the documentation destination full
* path and file name Create the destination path if it does not already exist.
*
* @param {string} file - Name of the file (including full path)
* @returns {string} Name of the file with the path changed from the source
* directory to final documentation directory
* @todo Possible Improvement: combine with lint-staged to only copy files that
* have changed
*/
const changeToFinalDocDir = (file: string): string => {
const newDir = file.replace(SOURCE_DOCS_DIR, FINAL_DOCS_DIR);
mkdirSync(dirname(newDir), { recursive: true });
return newDir;
};
/**
* Log messages to the console showing if the transformed file copied to the
* final documentation directory or still needs to be copied.
*
* @param {string} filename Name of the file that was transformed
* @param {boolean} wasCopied Whether or not the file was copied
*/
const logWasOrShouldBeTransformed = (filename: string, wasCopied: boolean) => {
const changeMsg = wasCopied ? LOGMSG_TRANSFORMED : LOGMSG_TO_BE_TRANSFORMED;
let logMsg: string;
logMsg = ` File ${changeMsg}: ${filename}`;
if (wasCopied) {
logMsg += LOGMSG_COPIED;
}
console.log(logMsg);
};
/**
* If the file contents were transformed, set the _filesWereTransformed_ flag to
* true and copy the transformed contents to the final documentation directory
* if the doCopy flag is true. Log messages to the console.
*
* @param {string} filename Name of the file that will be verified
* @param {boolean} [doCopy=false] Whether we should copy that
* transformedContents to the final documentation directory. Default is
* `false`. Default is `false`
* @param {string} [transformedContent] New contents for the file
*/
const copyTransformedContents = (filename: string, doCopy = false, transformedContent?: string) => {
const fileInFinalDocDir = changeToFinalDocDir(filename);
const existingBuffer = existsSync(fileInFinalDocDir)
? readFileSync(fileInFinalDocDir)
: Buffer.from('#NEW FILE#');
const newBuffer = transformedContent ? Buffer.from(transformedContent) : readFileSync(filename);
if (existingBuffer.equals(newBuffer)) {
// Files are same, skip.
return;
return; // Files are same, skip.
}
console.log(`File changed: ${outFile}`);
fileChanged = true;
if (!verify) {
writeFileSync(outFile, newBuffer);
filesWereTransformed = true;
if (doCopy) {
writeFileSync(fileInFinalDocDir, newBuffer);
}
logWasOrShouldBeTransformed(fileInFinalDocDir, doCopy);
};
const transform = (file: string) => {
const doc = readFileSync(file, 'utf8');
const readSyncedUTF8file = (filename: string): string => {
return readFileSync(filename, 'utf8');
};
/**
* Transform a markdown file and write the transformed file to the directory for
* published documentation
*
* 1. Add a `mermaid-example` block before every `mermaid` or `mmd` block On the
* docsify site (one place where the documentation is published), this will
* show the code used for the mermaid diagram
* 2. Add the text that says the file is automatically generated
* 3. Use prettier to format the file Verify that the file has been changed and
* write out the changes
*
* @param file {string} name of the file that will be verified
*/
const transformMarkdown = (file: string) => {
const doc = readSyncedUTF8file(file);
const ast: Root = remark.parse(doc);
const out = flatmap(ast, (c: Code) => {
if (c.type !== 'code' || !c.lang?.startsWith('mermaid')) {
@ -48,38 +158,82 @@ const transform = (file: string) => {
return [c, Object.assign({}, c, { lang: 'mermaid' })];
});
const transformed = `# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit corresponding file in src/docs.\n${remark.stringify(
out
)}`;
verifyAndCopy(
file,
prettier.format(transformed, {
parser: 'markdown',
useTabs: false,
tabWidth: 2,
endOfLine: 'auto',
printWidth: 100,
singleQuote: true,
})
);
// Add the AUTOGENERATED_TEXT to the start of the file
const transformed = `${AUTOGENERATED_TEXT}\n${remark.stringify(out)}`;
const formatted = prettier.format(transformed, {
parser: 'markdown',
...prettierConfig,
});
copyTransformedContents(file, !verifyOnly, formatted);
};
(async () => {
const mdFiles = await globby(['./src/docs/**/*.md'], { dot: true });
mdFiles.forEach(transform);
const nonMDFiles = await globby(['src/docs/**', '!**/*.md'], { dot: true });
nonMDFiles.forEach((file) => {
verifyAndCopy(file);
/**
* Transform an HTML file and write the transformed file to the directory for
* published documentation
*
* - Add the text that says the file is automatically generated Verify that the
* file has been changed and write out the changes
*
* @param filename {string} name of the HTML file to transform
*/
const transformHtml = (filename: string) => {
/**
* Insert the '...auto generated...' comment into an HTML file after the<html> element
*
* @param fileName {string} file name that should have the comment inserted
* @returns {string} The contents of the file with the comment inserted
*/
const insertAutoGeneratedComment = (fileName: string): string => {
const fileContents = readSyncedUTF8file(fileName);
const jsdom = new JSDOM(fileContents);
const htmlDoc = jsdom.window.document;
const autoGeneratedComment = jsdom.window.document.createComment(AUTOGENERATED_TEXT);
const rootElement = htmlDoc.documentElement;
rootElement.prepend(autoGeneratedComment);
return jsdom.serialize();
};
const transformedHTML = insertAutoGeneratedComment(filename);
const formattedHTML = prettier.format(transformedHTML, {
parser: 'html',
...prettierConfig,
});
if (fileChanged) {
if (verify) {
console.log(
"Changes detected in files in `docs`. Please run `yarn docs:build` after making changes to 'src/docs' to update the `docs` folder."
);
copyTransformedContents(filename, !verifyOnly, formattedHTML);
};
/** Main method (entry point) */
(async () => {
const sourceDirGlob = join('.', SOURCE_DOCS_DIR, '**');
const includeFilesStartingWithDot = true;
console.log('Transforming markdown files...');
const mdFiles = await globby([join(sourceDirGlob, '*.md')], {
dot: includeFilesStartingWithDot,
});
mdFiles.forEach(transformMarkdown);
console.log('Transforming html files...');
const htmlFiles = await globby([join(sourceDirGlob, '*.html')], {
dot: includeFilesStartingWithDot,
});
htmlFiles.forEach(transformHtml);
console.log('Transforming all other files...');
const otherFiles = await globby([sourceDirGlob, '!**/*.md', '!**/*.html'], {
dot: includeFilesStartingWithDot,
});
otherFiles.forEach((file: string) => {
copyTransformedContents(file, !verifyOnly); // no transformation
});
if (filesWereTransformed) {
if (verifyOnly) {
console.log(WARN_DOCSDIR_DOESNT_MATCH);
process.exit(1);
}
if (git) {
console.log('Adding changes in docs folder to git');
console.log('Adding changes in ${FINAL_DOCS_DIR} folder to git');
exec('git add docs');
}
}

View File

@ -1,7 +1,5 @@
# Mindmap
**Edit this Page** [![N|Solid](img/GitHub-Mark-32px.png)](https://github.com/mermaid-js/mermaid/blob/develop/src/docs/mindmap.md)
> Mindmap: This is an experimental diagram for now. The syntax and properties can change in future releases. The syntax is stabel except for the icon integration which is the experimental part.
"A mind map is a diagram used to visually organize information into a hierarchy, showing relationships among pieces of the whole. It is often created around a single concept, drawn as an image in the center of a blank page, to which associated representations of ideas such as images, words and parts of words are added. Major ideas are connected directly to the central concept, and other ideas branch out from those major ideas." Wikipedia

View File

@ -36,6 +36,8 @@ export const setLogLevel = function (level: keyof typeof LEVELS | number | strin
if (level in LEVELS) {
numericLevel = LEVELS[level as keyof typeof LEVELS];
}
} else if (typeof level === 'number') {
numericLevel = level;
}
log.trace = () => {};
log.debug = () => {};

View File

@ -9,8 +9,6 @@ const { mermaidAPI } = require('./mermaidAPI');
const { default: flowDb } = require('./diagrams/flowchart/flowDb');
import flowParser from './diagrams/flowchart/parser/flow';
import flowRenderer from './diagrams/flowchart/flowRenderer';
import Diagram from './Diagram';
const spyOn = jest.spyOn;
@ -64,149 +62,6 @@ describe('when using mermaid and ', function () {
});
});
describe('when calling addEdges ', function () {
beforeEach(function () {
flowParser.parser.yy = flowDb;
flowDb.clear();
flowDb.setGen('gen-2');
});
it('should handle edges with text', function () {
const diag = new Diagram('graph TD;A-->|text ex|B;');
diag.db.getVertices();
const edges = diag.db.getEdges();
const mockG = {
setEdge: function (start, end, options) {
expect(start).toContain('flowchart-A-');
expect(end).toContain('flowchart-B-');
expect(options.arrowhead).toBe('normal');
expect(options.label.match('text ex')).toBeTruthy();
},
};
flowRenderer.addEdges(edges, mockG, diag);
});
it('should handle edges without text', function () {
const diag = new Diagram('graph TD;A-->B;');
diag.db.getVertices();
const edges = diag.db.getEdges();
const mockG = {
setEdge: function (start, end, options) {
expect(start).toContain('flowchart-A-');
expect(end).toContain('flowchart-B-');
expect(options.arrowhead).toBe('normal');
},
};
flowRenderer.addEdges(edges, mockG, diag);
});
it('should handle open-ended edges', function () {
const diag = new Diagram('graph TD;A---B;');
diag.db.getVertices();
const edges = diag.db.getEdges();
const mockG = {
setEdge: function (start, end, options) {
expect(start).toContain('flowchart-A-');
expect(end).toContain('flowchart-B-');
expect(options.arrowhead).toBe('none');
},
};
flowRenderer.addEdges(edges, mockG, diag);
});
it('should handle edges with styles defined', function () {
const diag = new Diagram('graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2;');
diag.db.getVertices();
const edges = diag.db.getEdges();
const mockG = {
setEdge: function (start, end, options) {
expect(start).toContain('flowchart-A-');
expect(end).toContain('flowchart-B-');
expect(options.arrowhead).toBe('none');
expect(options.style).toBe('stroke:val1;stroke-width:val2;fill:none;');
},
};
flowRenderer.addEdges(edges, mockG, diag);
});
it('should handle edges with interpolation defined', function () {
const diag = new Diagram('graph TD;A---B; linkStyle 0 interpolate basis');
diag.db.getVertices();
const edges = diag.db.getEdges();
const mockG = {
setEdge: function (start, end, options) {
expect(start).toContain('flowchart-A-');
expect(end).toContain('flowchart-B-');
expect(options.arrowhead).toBe('none');
expect(options.curve).toBe('basis'); // mocked as string
},
};
flowRenderer.addEdges(edges, mockG, diag);
});
it('should handle edges with text and styles defined', function () {
const diag = new Diagram(
'graph TD;A---|the text|B; linkStyle 0 stroke:val1,stroke-width:val2;'
);
diag.db.getVertices();
const edges = diag.db.getEdges();
const mockG = {
setEdge: function (start, end, options) {
expect(start).toContain('flowchart-A-');
expect(end).toContain('flowchart-B-');
expect(options.arrowhead).toBe('none');
expect(options.label.match('the text')).toBeTruthy();
expect(options.style).toBe('stroke:val1;stroke-width:val2;fill:none;');
},
};
flowRenderer.addEdges(edges, mockG, diag);
});
it('should set fill to "none" by default when handling edges', function () {
const diag = new Diagram('graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2;');
diag.db.getVertices();
const edges = diag.db.getEdges();
const mockG = {
setEdge: function (start, end, options) {
expect(start).toContain('flowchart-A-');
expect(end).toContain('flowchart-B');
expect(options.arrowhead).toBe('none');
expect(options.style).toBe('stroke:val1;stroke-width:val2;fill:none;');
},
};
flowRenderer.addEdges(edges, mockG, diag);
});
it('should not set fill to none if fill is set in linkStyle', function () {
const diag = new Diagram(
'graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2,fill:blue;'
);
diag.db.getVertices();
const edges = diag.db.getEdges();
const mockG = {
setEdge: function (start, end, options) {
expect(start).toContain('flowchart-A-');
expect(end).toContain('flowchart-B-');
expect(options.arrowhead).toBe('none');
expect(options.style).toBe('stroke:val1;stroke-width:val2;fill:blue;');
},
};
flowRenderer.addEdges(edges, mockG, diag);
});
});
describe('checking validity of input ', function () {
beforeEach(function () {
flowParser.parser.yy = flowDb;

View File

@ -1,8 +0,0 @@
/**
*
*/
function apa() {
// comment's
const a = 1;
return 'apa' + a;
}