Skip to content

Commit

Permalink
Merge pull request #3240 from mermaid-js/3061_refactoring_and_modular…
Browse files Browse the repository at this point in the history
…isation

Using diagram api to add gitGraph
  • Loading branch information
knsv committed Jul 20, 2022
2 parents ce1507c + e1de087 commit 8e02438
Show file tree
Hide file tree
Showing 27 changed files with 922 additions and 672 deletions.
5 changes: 4 additions & 1 deletion cypress/platform/knsv.html
Expand Up @@ -64,7 +64,7 @@
commit
commit
</div>
<div class="mermaid2" style="width: 50%;">
<div class="mermaid" style="width: 50%;">
sequenceDiagram
title: My Sequence Diagram Title
accTitle: My Acc Sequence Diagram
Expand Down Expand Up @@ -283,6 +283,9 @@
class: {
// defaultRenderer: 'dagre-d3',
htmlLabels: true,
},
sequence: {
mirrorActors: false,
},
// gantt: { axisFormat: '%m/%d/%Y' },
// sequence: {
Expand Down
11 changes: 9 additions & 2 deletions docs/Setup.md
Expand Up @@ -1401,6 +1401,15 @@ This sets the auto-wrap padding for the diagram (sides only)

**Notes:** Default value: 0.

## parse

### Parameters

- `text`
- `dia`

Returns **any**

## setSiteConfig

## setSiteConfig
Expand Down Expand Up @@ -1524,8 +1533,6 @@ Pushes in a directive to the configuration

## reset

## reset

| Function | Description | Type | Required | Values |
| -------- | ---------------------------- | ----------- | -------- | ------ |
| reset | Resets currentConfig to conf | Put Request | Required | None |
Expand Down
218 changes: 43 additions & 175 deletions src/Diagram.js
@@ -1,198 +1,66 @@
import c4Db from './diagrams/c4/c4Db';
import c4Renderer from './diagrams/c4/c4Renderer';
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 classParser from './diagrams/class/parser/classDiagram';
import erDb from './diagrams/er/erDb';
import erRenderer from './diagrams/er/erRenderer';
import erParser from './diagrams/er/parser/erDiagram';
import flowDb from './diagrams/flowchart/flowDb';
import flowRenderer from './diagrams/flowchart/flowRenderer';
import flowRendererV2 from './diagrams/flowchart/flowRenderer-v2';
import flowParser from './diagrams/flowchart/parser/flow';
import ganttDb from './diagrams/gantt/ganttDb';
import ganttRenderer from './diagrams/gantt/ganttRenderer';
import ganttParser from './diagrams/gantt/parser/gantt';
import gitGraphAst from './diagrams/git/gitGraphAst';
import gitGraphRenderer from './diagrams/git/gitGraphRenderer';
import gitGraphParser from './diagrams/git/parser/gitGraph';
import infoDb from './diagrams/info/infoDb';
import infoRenderer from './diagrams/info/infoRenderer';
import infoParser from './diagrams/info/parser/info';
import pieParser from './diagrams/pie/parser/pie';
import pieDb from './diagrams/pie/pieDb';
import pieRenderer from './diagrams/pie/pieRenderer';
import requirementParser from './diagrams/requirement/parser/requirementDiagram';
import requirementDb from './diagrams/requirement/requirementDb';
import requirementRenderer from './diagrams/requirement/requirementRenderer';
import sequenceParser from './diagrams/sequence/parser/sequenceDiagram';
import sequenceDb from './diagrams/sequence/sequenceDb';
import sequenceRenderer from './diagrams/sequence/sequenceRenderer';
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 journeyDb from './diagrams/user-journey/journeyDb';
import journeyRenderer from './diagrams/user-journey/journeyRenderer';
import journeyParser from './diagrams/user-journey/parser/journey';
import utils from './utils';
import * as configApi from './config';
import { log } from './logger';

import { getDiagrams } from './diagram-api/diagramAPI';
import detectType from './diagram-api/detectType';
class Diagram {
type = 'graph';
parser;
renderer;
db;
constructor(txt) {
const diagrams = getDiagrams();
const cnf = configApi.getConfig();
this.txt = txt;
this.type = utils.detectType(txt, cnf);
this.type = detectType(txt, cnf);
log.debug('Type ' + this.type);
switch (this.type) {
case 'c4':
this.parser = c4Parser;
this.parser.parser.yy = c4Db;
this.db = c4Db;
this.renderer = c4Renderer;
this.renderer.setConf(cnf.c4);
break;
case 'gitGraph':
this.parser = gitGraphParser;
this.parser.parser.yy = gitGraphAst;
this.db = gitGraphAst;
this.renderer = gitGraphRenderer;
this.txt = this.txt + '\n';
break;
case 'flowchart':
flowRenderer.setConf(cnf.flowchart);
cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
flowDb.clear();
flowDb.setGen('gen-1');
this.parser = flowParser;
this.parser.parser.yy = flowDb;
this.db = flowDb;
this.renderer = flowRenderer;
break;
case 'flowchart-v2':
flowRendererV2.setConf(cnf.flowchart);
cnf.flowchart.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
flowDb.clear();
flowDb.setGen('gen-2');
this.parser = flowParser;
this.parser.parser.yy = flowDb;
this.db = flowDb;
this.renderer = flowRendererV2;
break;
case 'sequenceDiagram':
case 'sequence':
cnf.sequence.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
if (cnf.sequenceDiagram) {
// backwards compatibility
sequenceRenderer.setConf(Object.assign(cnf.sequence, cnf.sequenceDiagram));
console.error(
'`mermaid config.sequenceDiagram` has been renamed to `config.sequence`. Please update your mermaid config.'
);
}
this.parser = sequenceParser;
this.parser.parser.yy = sequenceDb;
this.db = sequenceDb;
this.db.setWrap(cnf.wrap);
this.renderer = sequenceRenderer;
this.renderer.setConf(cnf.sequence);
this.txt = this.txt + '\n';
break;
case 'gantt':
cnf.gantt.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
this.parser = ganttParser;
this.parser.parser.yy = ganttDb;
this.db = ganttDb;
this.renderer = ganttRenderer;
ganttRenderer.setConf(cnf.gantt);
break;
case 'class':
cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
this.parser = classParser;
this.parser.parser.yy = classDb;
this.db = classDb;
this.db.clear();
this.renderer = classRenderer;
break;
case 'classDiagram':
cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
this.parser = classParser;
this.parser.parser.yy = classDb;
this.db = classDb;
this.db.clear();
this.renderer = classRendererV2;
break;
case 'state':
cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
this.parser = stateParser;
this.parser.parser.yy = stateDb;
this.db = stateDb;
this.db.clear();
this.renderer = stateRenderer;
break;
case 'stateDiagram':
cnf.class.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
this.parser = stateParser;
this.parser.parser.yy = stateDb;
this.db = stateDb;
this.db.clear();
this.renderer = stateRendererV2;
break;
case 'info':
log.debug('info info info');
this.parser = infoParser;
this.parser.parser.yy = infoDb;
this.db = infoDb;
this.renderer = infoRenderer;
break;
case 'pie':
log.debug('pie');
this.parser = pieParser;
this.parser.parser.yy = pieDb;
this.db = pieDb;
this.renderer = pieRenderer;
break;
case 'er':
log.debug('er');
this.parser = erParser;
this.parser.parser.yy = erDb;
this.db = erDb;
this.renderer = erRenderer;
break;
case 'journey':
log.debug('Journey');
journeyRenderer.setConf(cnf.journey);
this.parser = journeyParser;
this.parser.parser.yy = journeyDb;
this.db = journeyDb;
this.db.clear();
this.renderer = journeyRenderer;
break;
case 'requirement':
case 'requirementDiagram':
log.debug('RequirementDiagram');
this.parser = requirementParser;
this.parser.parser.yy = requirementDb;
this.db = requirementDb;
this.renderer = requirementRenderer;
break;
default:
log.error('Unkown graphtype');
throw new Error('Unkown graphtype');

// console.log('this.type', this.type, diagrams[this.type]);
// Setup diagram
this.db = diagrams[this.type].db;
this.renderer = diagrams[this.type].renderer;
this.parser = diagrams[this.type].parser;
this.parser.parser.yy = this.db;
if (typeof diagrams[this.type].init === 'function') {
diagrams[this.type].init(cnf);
log.debug('Initialized diagram ' + this.type, cnf);
}
this.txt = this.txt + '\n';

this.parser.parser.yy.graphType = this.type;
this.parser.parser.yy.parseError = (str, hash) => {
const error = { str, hash };
throw error;
};
this.parser.parse(this.txt);
}
parse(text) {
var parseEncounteredException = false;
try {
text = text + '\n';
this.db.clear();

this.parser.parse(text);
} catch (error) {
parseEncounteredException = true;
// Is this the correct way to access mermiad's parseError()
// method ? (or global.mermaid.parseError()) ?
if (global.mermaid.parseError) {
if (error.str != undefined) {
// handle case where error string and hash were
// wrapped in object like`const error = { str, hash };`
global.mermaid.parseError(error.str, error.hash);
} else {
// assume it is just error string and pass it on
global.mermaid.parseError(error);
}
} else {
// No mermaid.parseError() handler defined, so re-throw it
throw error;
}
}
return !parseEncounteredException;
}
getParser() {
return this.parser;
}
Expand Down
74 changes: 74 additions & 0 deletions src/assignWithDepth.js
@@ -0,0 +1,74 @@
/**
* @function assignWithDepth Extends the functionality of {@link ObjectConstructor.assign} with the
* ability to merge arbitrary-depth objects For each key in src with path `k` (recursively)
* performs an Object.assign(dst[`k`], src[`k`]) with a slight change from the typical handling of
* undefined for dst[`k`]: instead of raising an error, dst[`k`] is auto-initialized to {} and
* effectively merged with src[`k`]<p> Additionally, dissimilar types will not clobber unless the
* config.clobber parameter === true. Example:
*
* ```js
* let config_0 = { foo: { bar: 'bar' }, bar: 'foo' };
* let config_1 = { foo: 'foo', bar: 'bar' };
* let result = assignWithDepth(config_0, config_1);
* console.log(result);
* //-> result: { foo: { bar: 'bar' }, bar: 'bar' }
* ```
*
* Traditional Object.assign would have clobbered foo in config_0 with foo in config_1. If src is a
* destructured array of objects and dst is not an array, assignWithDepth will apply each element
* of src to dst in order.
* @param dst
* @param src
* @param config
* @param dst
* @param src
* @param config
* @param dst
* @param src
* @param config
* @param {any} dst - The destination of the merge
* @param {any} src - The source object(s) to merge into destination
* @param {{ depth: number; clobber: boolean }} [config={ depth: 2, clobber: false }] - Depth: depth
* to traverse within src and dst for merging - clobber: should dissimilar types clobber (default:
* { depth: 2, clobber: false }). Default is `{ depth: 2, clobber: false }`
* @returns {any}
*/
const assignWithDepth = function (dst, src, config) {
const { depth, clobber } = Object.assign({ depth: 2, clobber: false }, config);
if (Array.isArray(src) && !Array.isArray(dst)) {
src.forEach((s) => assignWithDepth(dst, s, config));
return dst;
} else if (Array.isArray(src) && Array.isArray(dst)) {
src.forEach((s) => {
if (dst.indexOf(s) === -1) {
dst.push(s);
}
});
return dst;
}
if (typeof dst === 'undefined' || depth <= 0) {
if (dst !== undefined && dst !== null && typeof dst === 'object' && typeof src === 'object') {
return Object.assign(dst, src);
} else {
return src;
}
}
if (typeof src !== 'undefined' && typeof dst === 'object' && typeof src === 'object') {
Object.keys(src).forEach((key) => {
if (
typeof src[key] === 'object' &&
(dst[key] === undefined || typeof dst[key] === 'object')
) {
if (dst[key] === undefined) {
dst[key] = Array.isArray(src[key]) ? [] : {};
}
dst[key] = assignWithDepth(dst[key], src[key], { depth: depth - 1, clobber });
} else if (clobber || (typeof dst[key] !== 'object' && typeof src[key] !== 'object')) {
dst[key] = src[key];
}
});
}
return dst;
};

export default assignWithDepth;
2 changes: 1 addition & 1 deletion src/config.js
@@ -1,4 +1,4 @@
import { assignWithDepth } from './utils';
import assignWithDepth from './assignWithDepth';
import { log } from './logger';
import theme from './themes';
import config from './defaultConfig';
Expand Down

0 comments on commit 8e02438

Please sign in to comment.