mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-14 12:59:46 +02:00
First take on grammar
This commit is contained in:
@@ -35,6 +35,14 @@ import journeyDb from '../diagrams/user-journey/journeyDb';
|
|||||||
import journeyRenderer from '../diagrams/user-journey/journeyRenderer';
|
import journeyRenderer from '../diagrams/user-journey/journeyRenderer';
|
||||||
import journeyParser from '../diagrams/user-journey/parser/journey';
|
import journeyParser from '../diagrams/user-journey/parser/journey';
|
||||||
import { addDetector } from './detectType';
|
import { addDetector } from './detectType';
|
||||||
|
import { sanitizeText as _sanitizeText } from '../diagrams/common/common';
|
||||||
|
import { getConfig as _getConfig } from '../config';
|
||||||
|
let title = '';
|
||||||
|
let diagramTitle = '';
|
||||||
|
let description = '';
|
||||||
|
|
||||||
|
export const getConfig = _getConfig;
|
||||||
|
export const sanitizeText = (txt) => _sanitizeText(txt, getConfig());
|
||||||
|
|
||||||
const diagrams = {
|
const diagrams = {
|
||||||
c4: {
|
c4: {
|
||||||
|
@@ -1,14 +0,0 @@
|
|||||||
describe('when parsing an info graph it', function () {
|
|
||||||
var ex;
|
|
||||||
beforeEach(function () {
|
|
||||||
ex = require('./parser/info').parser;
|
|
||||||
ex.yy = require('./infoDb');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should handle an info definition', function () {
|
|
||||||
var str = `info
|
|
||||||
showInfo`;
|
|
||||||
|
|
||||||
ex.parse(str);
|
|
||||||
});
|
|
||||||
});
|
|
@@ -1,34 +0,0 @@
|
|||||||
/** Created by knut on 15-01-14. */
|
|
||||||
import { log } from '../../logger';
|
|
||||||
|
|
||||||
var message = '';
|
|
||||||
var info = false;
|
|
||||||
|
|
||||||
export const setMessage = (txt) => {
|
|
||||||
log.debug('Setting message to: ' + txt);
|
|
||||||
message = txt;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getMessage = () => {
|
|
||||||
return message;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const setInfo = (inf) => {
|
|
||||||
info = inf;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getInfo = () => {
|
|
||||||
return info;
|
|
||||||
};
|
|
||||||
|
|
||||||
// export const parseError = (err, hash) => {
|
|
||||||
// global.mermaidAPI.parseError(err, hash)
|
|
||||||
// }
|
|
||||||
|
|
||||||
export default {
|
|
||||||
setMessage,
|
|
||||||
getMessage,
|
|
||||||
setInfo,
|
|
||||||
getInfo,
|
|
||||||
// parseError
|
|
||||||
};
|
|
201
src/diagrams/mindmap/mindmap.spec.js
Normal file
201
src/diagrams/mindmap/mindmap.spec.js
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
import mindmapDB from './mindmapDb';
|
||||||
|
|
||||||
|
describe('when parsing a mindmap ', function () {
|
||||||
|
var mindmap;
|
||||||
|
beforeEach(function () {
|
||||||
|
mindmap = require('./parser/mindmap').parser;
|
||||||
|
mindmap.yy = require('./mindmapDb');
|
||||||
|
mindmap.yy.clear();
|
||||||
|
});
|
||||||
|
describe('hiearchy', function () {
|
||||||
|
it('should handle a simple root definition', function () {
|
||||||
|
var str = `mindmap
|
||||||
|
root`;
|
||||||
|
|
||||||
|
mindmap.parse(str);
|
||||||
|
// console.log('Time for checks', mindmap.yy.getMindmap().descr);
|
||||||
|
expect(mindmap.yy.getMindmap().descr).toEqual('root');
|
||||||
|
});
|
||||||
|
it('should handle a hierachial mindmap definition', function () {
|
||||||
|
var str = `mindmap
|
||||||
|
root
|
||||||
|
child1
|
||||||
|
child2
|
||||||
|
`;
|
||||||
|
|
||||||
|
mindmap.parse(str);
|
||||||
|
const mm = mindmap.yy.getMindmap();
|
||||||
|
expect(mm.descr).toEqual('root');
|
||||||
|
expect(mm.children.length).toEqual(2);
|
||||||
|
expect(mm.children[0].descr).toEqual('child1');
|
||||||
|
expect(mm.children[1].descr).toEqual('child2');
|
||||||
|
});
|
||||||
|
it('should handle a hierachial mindmap definition', function () {
|
||||||
|
var str = `mindmap
|
||||||
|
root
|
||||||
|
child1
|
||||||
|
leaf1
|
||||||
|
child2`;
|
||||||
|
|
||||||
|
mindmap.parse(str);
|
||||||
|
const mm = mindmap.yy.getMindmap();
|
||||||
|
expect(mm.descr).toEqual('root');
|
||||||
|
expect(mm.children.length).toEqual(2);
|
||||||
|
expect(mm.children[0].descr).toEqual('child1');
|
||||||
|
expect(mm.children[0].children[0].descr).toEqual('leaf1');
|
||||||
|
expect(mm.children[1].descr).toEqual('child2');
|
||||||
|
});
|
||||||
|
it('Multiple roots are illegal', function () {
|
||||||
|
var str = `mindmap
|
||||||
|
root
|
||||||
|
fakeRoot`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
mindmap.parse(str);
|
||||||
|
// Fail test if above expression doesn't throw anything.
|
||||||
|
expect(true).toBe(false);
|
||||||
|
} catch (e) {
|
||||||
|
expect(e.message).toBe(
|
||||||
|
'There can be only one root. No parent could be found for ("fakeRoot")'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
it('real root in wrong place', function () {
|
||||||
|
var str = `mindmap
|
||||||
|
root
|
||||||
|
fakeRoot
|
||||||
|
realRootWrongPlace`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
mindmap.parse(str);
|
||||||
|
// Fail test if above expression doesn't throw anything.
|
||||||
|
expect(true).toBe(false);
|
||||||
|
} catch (e) {
|
||||||
|
expect(e.message).toBe(
|
||||||
|
'There can be only one root. No parent could be found for ("fakeRoot")'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('nodes', function () {
|
||||||
|
it('should handle an id and type for a node definition', function () {
|
||||||
|
var str = `mindmap
|
||||||
|
root[The root]
|
||||||
|
`;
|
||||||
|
|
||||||
|
mindmap.parse(str);
|
||||||
|
const mm = mindmap.yy.getMindmap();
|
||||||
|
expect(mm.id).toEqual('root');
|
||||||
|
expect(mm.descr).toEqual('The root');
|
||||||
|
expect(mm.type).toEqual(mindmap.yy.nodeType.RECT);
|
||||||
|
});
|
||||||
|
it('should handle an id and type for a node definition', function () {
|
||||||
|
var str = `mindmap
|
||||||
|
root
|
||||||
|
theId(child1)`;
|
||||||
|
|
||||||
|
mindmap.parse(str);
|
||||||
|
const mm = mindmap.yy.getMindmap();
|
||||||
|
expect(mm.descr).toEqual('root');
|
||||||
|
expect(mm.children.length).toEqual(1);
|
||||||
|
const child = mm.children[0];
|
||||||
|
expect(child.descr).toEqual('child1');
|
||||||
|
expect(child.id).toEqual('theId');
|
||||||
|
expect(child.type).toEqual(mindmap.yy.nodeType.ROUNDED_RECT);
|
||||||
|
});
|
||||||
|
it('should handle an id and type for a node definition', function () {
|
||||||
|
var str = `mindmap
|
||||||
|
root
|
||||||
|
theId(child1)`;
|
||||||
|
|
||||||
|
mindmap.parse(str);
|
||||||
|
const mm = mindmap.yy.getMindmap();
|
||||||
|
expect(mm.descr).toEqual('root');
|
||||||
|
expect(mm.children.length).toEqual(1);
|
||||||
|
const child = mm.children[0];
|
||||||
|
expect(child.descr).toEqual('child1');
|
||||||
|
expect(child.id).toEqual('theId');
|
||||||
|
expect(child.type).toEqual(mindmap.yy.nodeType.ROUNDED_RECT);
|
||||||
|
});
|
||||||
|
it('mutiple types (circle)', function () {
|
||||||
|
var str = `mindmap
|
||||||
|
root((the root))
|
||||||
|
`;
|
||||||
|
|
||||||
|
mindmap.parse(str);
|
||||||
|
const mm = mindmap.yy.getMindmap();
|
||||||
|
expect(mm.descr).toEqual('the root');
|
||||||
|
expect(mm.children.length).toEqual(0);
|
||||||
|
expect(mm.type).toEqual(mindmap.yy.nodeType.CIRCLE);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('decorations', function () {
|
||||||
|
it('should be possible to set an icon for the node', function () {
|
||||||
|
var str = `mindmap
|
||||||
|
root[The root]
|
||||||
|
::icon(bomb)
|
||||||
|
`;
|
||||||
|
// ::class1 class2
|
||||||
|
|
||||||
|
mindmap.parse(str);
|
||||||
|
const mm = mindmap.yy.getMindmap();
|
||||||
|
expect(mm.id).toEqual('root');
|
||||||
|
expect(mm.descr).toEqual('The root');
|
||||||
|
expect(mm.type).toEqual(mindmap.yy.nodeType.RECT);
|
||||||
|
expect(mm.icon).toEqual('bomb');
|
||||||
|
});
|
||||||
|
it('should be possible to set classes for the node', function () {
|
||||||
|
var str = `mindmap
|
||||||
|
root[The root]
|
||||||
|
:::m-4 p-8
|
||||||
|
`;
|
||||||
|
// ::class1 class2
|
||||||
|
|
||||||
|
mindmap.parse(str);
|
||||||
|
const mm = mindmap.yy.getMindmap();
|
||||||
|
expect(mm.id).toEqual('root');
|
||||||
|
expect(mm.descr).toEqual('The root');
|
||||||
|
expect(mm.type).toEqual(mindmap.yy.nodeType.RECT);
|
||||||
|
expect(mm.class).toEqual('m-4 p-8');
|
||||||
|
});
|
||||||
|
it('should be possible to set both classes and icon for the node', function () {
|
||||||
|
var str = `mindmap
|
||||||
|
root[The root]
|
||||||
|
:::m-4 p-8
|
||||||
|
::icon(bomb)
|
||||||
|
`;
|
||||||
|
// ::class1 class2
|
||||||
|
|
||||||
|
mindmap.parse(str);
|
||||||
|
const mm = mindmap.yy.getMindmap();
|
||||||
|
expect(mm.id).toEqual('root');
|
||||||
|
expect(mm.descr).toEqual('The root');
|
||||||
|
expect(mm.type).toEqual(mindmap.yy.nodeType.RECT);
|
||||||
|
expect(mm.class).toEqual('m-4 p-8');
|
||||||
|
expect(mm.icon).toEqual('bomb');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('descriptions', function () {
|
||||||
|
it('should be possible to use node syntax in the descriptions', function () {
|
||||||
|
var str = `mindmap
|
||||||
|
root["String containing []"]
|
||||||
|
`;
|
||||||
|
mindmap.parse(str);
|
||||||
|
const mm = mindmap.yy.getMindmap();
|
||||||
|
expect(mm.id).toEqual('root');
|
||||||
|
expect(mm.descr).toEqual('String containing []');
|
||||||
|
});
|
||||||
|
it('should be possible to use node syntax in the descriptions in children', function () {
|
||||||
|
var str = `mindmap
|
||||||
|
root["String containing []"]
|
||||||
|
child1["String containing ()"]
|
||||||
|
`;
|
||||||
|
mindmap.parse(str);
|
||||||
|
const mm = mindmap.yy.getMindmap();
|
||||||
|
expect(mm.id).toEqual('root');
|
||||||
|
expect(mm.descr).toEqual('String containing []');
|
||||||
|
expect(mm.children.length).toEqual(1);
|
||||||
|
expect(mm.children[0].descr).toEqual('String containing ()');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
94
src/diagrams/mindmap/mindmapDb.js
Normal file
94
src/diagrams/mindmap/mindmapDb.js
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
/** Created by knut on 15-01-14. */
|
||||||
|
import { log } from '../../logger';
|
||||||
|
import { sanitizeText } from '../../diagram-api/diagramAPI';
|
||||||
|
|
||||||
|
var message = '';
|
||||||
|
var info = false;
|
||||||
|
const root = {};
|
||||||
|
let nodes = [];
|
||||||
|
|
||||||
|
export const clear = () => {
|
||||||
|
nodes = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
const getParent = function (level) {
|
||||||
|
for (let i = nodes.length - 1; i >= 0; i--) {
|
||||||
|
if (nodes[i].level < level) {
|
||||||
|
return nodes[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// No parent found
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getMindmap = () => {
|
||||||
|
console.log('getMindmap', nodes[0]);
|
||||||
|
return nodes.length > 0 ? nodes[0] : null;
|
||||||
|
};
|
||||||
|
export const addNode = (level, id, descr, type) => {
|
||||||
|
const node = { id: sanitizeText(id), level, descr: sanitizeText(descr), type, children: [] };
|
||||||
|
const parent = getParent(level);
|
||||||
|
if (parent) {
|
||||||
|
parent.children.push(node);
|
||||||
|
// Keep all nodes in the list
|
||||||
|
nodes.push(node);
|
||||||
|
} else {
|
||||||
|
if (nodes.length === 0) {
|
||||||
|
// First node, the root
|
||||||
|
nodes.push(node);
|
||||||
|
} else {
|
||||||
|
// Syntax error ... there can only bee one root
|
||||||
|
let error = new Error(
|
||||||
|
'There can be only one root. No parent could be found for ("' + node.descr + '")'
|
||||||
|
);
|
||||||
|
error.hash = {
|
||||||
|
text: 'branch ' + name,
|
||||||
|
token: 'branch ' + name,
|
||||||
|
line: '1',
|
||||||
|
loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
|
||||||
|
expected: ['"checkout ' + name + '"'],
|
||||||
|
};
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const nodeType = {
|
||||||
|
DEFAULT: 0,
|
||||||
|
NO_BORDER: 0,
|
||||||
|
ROUNDED_RECT: 1,
|
||||||
|
RECT: 2,
|
||||||
|
CIRCLE: 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getTypeFromStart = (str) => {
|
||||||
|
switch (str) {
|
||||||
|
case '[':
|
||||||
|
return nodeType.RECT;
|
||||||
|
case '(':
|
||||||
|
return nodeType.ROUNDED_RECT;
|
||||||
|
case '((':
|
||||||
|
return nodeType.CIRCLE;
|
||||||
|
default:
|
||||||
|
return nodeType.DEFAULT;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
export const decorateNode = (decoration) => {
|
||||||
|
console.log('decorateNode', decoration);
|
||||||
|
const node = nodes[nodes.length - 1];
|
||||||
|
if (decoration && decoration.icon) {
|
||||||
|
node.icon = sanitizeText(decoration.icon);
|
||||||
|
}
|
||||||
|
if (decoration && decoration.class) {
|
||||||
|
node.class = sanitizeText(decoration.class);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
export default {
|
||||||
|
getMindmap,
|
||||||
|
addNode,
|
||||||
|
clear,
|
||||||
|
nodeType,
|
||||||
|
getTypeFromStart,
|
||||||
|
decorateNode,
|
||||||
|
// parseError
|
||||||
|
};
|
@@ -1,48 +0,0 @@
|
|||||||
/** mermaid
|
|
||||||
* https://knsv.github.io/mermaid
|
|
||||||
* (c) 2015 Knut Sveidqvist
|
|
||||||
* MIT license.
|
|
||||||
*/
|
|
||||||
%lex
|
|
||||||
|
|
||||||
%options case-insensitive
|
|
||||||
|
|
||||||
%{
|
|
||||||
// Pre-lexer code can go here
|
|
||||||
%}
|
|
||||||
|
|
||||||
%%
|
|
||||||
|
|
||||||
"info" return 'info' ;
|
|
||||||
[\s\n\r]+ return 'NL' ;
|
|
||||||
[\s]+ return 'space';
|
|
||||||
"showInfo" return 'showInfo';
|
|
||||||
<<EOF>> return 'EOF' ;
|
|
||||||
. return 'TXT' ;
|
|
||||||
|
|
||||||
/lex
|
|
||||||
|
|
||||||
%start start
|
|
||||||
|
|
||||||
%% /* language grammar */
|
|
||||||
|
|
||||||
start
|
|
||||||
// %{ : info document 'EOF' { return yy; } }
|
|
||||||
: info document 'EOF' { return yy; }
|
|
||||||
;
|
|
||||||
|
|
||||||
document
|
|
||||||
: /* empty */
|
|
||||||
| document line
|
|
||||||
;
|
|
||||||
|
|
||||||
line
|
|
||||||
: statement { }
|
|
||||||
| 'NL'
|
|
||||||
;
|
|
||||||
|
|
||||||
statement
|
|
||||||
: showInfo { yy.setInfo(true); }
|
|
||||||
;
|
|
||||||
|
|
||||||
%%
|
|
79
src/diagrams/mindmap/parser/mindmap.jison
Normal file
79
src/diagrams/mindmap/parser/mindmap.jison
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
/** mermaid
|
||||||
|
* https://knsv.github.io/mermaid
|
||||||
|
* (c) 2015 Knut Sveidqvist
|
||||||
|
* MIT license.
|
||||||
|
*/
|
||||||
|
%lex
|
||||||
|
|
||||||
|
%options case-insensitive
|
||||||
|
|
||||||
|
%{
|
||||||
|
// Pre-lexer code can go here
|
||||||
|
%}
|
||||||
|
%x NODE
|
||||||
|
%x NSTR
|
||||||
|
%x ICON
|
||||||
|
%x CLASS
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
"mindmap" return 'MINDMAP';
|
||||||
|
":::" { this.begin('CLASS'); }
|
||||||
|
<CLASS>.+ { return 'CLASS';this.popState(); }
|
||||||
|
<CLASS>\n { this.popState();}
|
||||||
|
[\n\s]*"::icon(" { this.begin('ICON'); }
|
||||||
|
<ICON>[^\)]+ { return 'ICON'; }
|
||||||
|
<ICON>\) {this.popState();}
|
||||||
|
"((" { this.begin('NODE');return 'NODE_DSTART'; }
|
||||||
|
"(" { this.begin('NODE');return 'NODE_DSTART'; }
|
||||||
|
"[" { this.begin('NODE');return 'NODE_DSTART'; }
|
||||||
|
[^\(\[\n]+ return 'NODE_ID';
|
||||||
|
[\s]+ return 'SPACELIST' /* skip all whitespace */ ;
|
||||||
|
<<EOF>> return 'EOF';
|
||||||
|
<NODE>["] { console.log('Starting NSTR');this.begin("NSTR");}
|
||||||
|
<NSTR>[^"]+ { console.log('description:', yytext); return "NODE_DESCR";}
|
||||||
|
<NSTR>["] {this.popState();}
|
||||||
|
<NODE>[\)] {this.popState();console.log('node end');return "NODE_DEND";}
|
||||||
|
<NODE>[\]] {this.popState();console.log('node end');return "NODE_DEND";}
|
||||||
|
<NODE>[^\)\]]+ { console.log('Long description:', yytext); return 'NODE_DESCR';}
|
||||||
|
|
||||||
|
[\n]+ /* return 'NL'; */
|
||||||
|
// [\[] return 'NODE_START';
|
||||||
|
// .+ return 'TXT' ;
|
||||||
|
|
||||||
|
/lex
|
||||||
|
|
||||||
|
%start start
|
||||||
|
|
||||||
|
%% /* language grammar */
|
||||||
|
|
||||||
|
start
|
||||||
|
// %{ : info document 'EOF' { return yy; } }
|
||||||
|
: MINDMAP document { return yy; }
|
||||||
|
;
|
||||||
|
|
||||||
|
document
|
||||||
|
: document line
|
||||||
|
| line
|
||||||
|
;
|
||||||
|
|
||||||
|
line
|
||||||
|
: statement { }
|
||||||
|
;
|
||||||
|
|
||||||
|
statement
|
||||||
|
: node
|
||||||
|
| SPACELIST node { yy.addNode($1.length, $2.id, $2.descr, $2.type); }
|
||||||
|
| SPACELIST EOF
|
||||||
|
| SPACELIST ICON { yy.decorateNode({icon: $2}); }
|
||||||
|
| ICON { yy.decorateNode({icon: $1}); }
|
||||||
|
| SPACELIST CLASS { yy.decorateNode({class: $2}); }
|
||||||
|
| CLASS { yy.decorateNode({class: $1}); }
|
||||||
|
| EOF
|
||||||
|
;
|
||||||
|
node
|
||||||
|
: NODE_ID { $$ = { id: $1, descr: $1, type: yy.nodeType.DEFAULT }; }
|
||||||
|
| NODE_ID NODE_DSTART NODE_DESCR NODE_DEND
|
||||||
|
{ $$ = { id: $1, descr: $3, type: yy.getTypeFromStart($2) }; }
|
||||||
|
;
|
||||||
|
%%
|
Reference in New Issue
Block a user