diff --git a/src/diagram-api/diagramAPI.js b/src/diagram-api/diagramAPI.js index 62c884368..e8339ca37 100644 --- a/src/diagram-api/diagramAPI.js +++ b/src/diagram-api/diagramAPI.js @@ -35,6 +35,14 @@ import journeyDb from '../diagrams/user-journey/journeyDb'; import journeyRenderer from '../diagrams/user-journey/journeyRenderer'; import journeyParser from '../diagrams/user-journey/parser/journey'; 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 = { c4: { diff --git a/src/diagrams/mindmap/info.spc.js b/src/diagrams/mindmap/info.spc.js deleted file mode 100644 index 69a969fb1..000000000 --- a/src/diagrams/mindmap/info.spc.js +++ /dev/null @@ -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); - }); -}); diff --git a/src/diagrams/mindmap/infoDb.js b/src/diagrams/mindmap/infoDb.js deleted file mode 100644 index 5a324fbb4..000000000 --- a/src/diagrams/mindmap/infoDb.js +++ /dev/null @@ -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 -}; diff --git a/src/diagrams/mindmap/mindmap.spec.js b/src/diagrams/mindmap/mindmap.spec.js new file mode 100644 index 000000000..a29aaec8f --- /dev/null +++ b/src/diagrams/mindmap/mindmap.spec.js @@ -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 ()'); + }); + }); +}); diff --git a/src/diagrams/mindmap/mindmapDb.js b/src/diagrams/mindmap/mindmapDb.js new file mode 100644 index 000000000..8aed2dd2e --- /dev/null +++ b/src/diagrams/mindmap/mindmapDb.js @@ -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 +}; diff --git a/src/diagrams/mindmap/infoRenderer.js b/src/diagrams/mindmap/mindmapRenderer.js similarity index 100% rename from src/diagrams/mindmap/infoRenderer.js rename to src/diagrams/mindmap/mindmapRenderer.js diff --git a/src/diagrams/mindmap/parser/mindamap.jison b/src/diagrams/mindmap/parser/mindamap.jison deleted file mode 100644 index 473b63fcf..000000000 --- a/src/diagrams/mindmap/parser/mindamap.jison +++ /dev/null @@ -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'; -<> 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); } - ; - -%% diff --git a/src/diagrams/mindmap/parser/mindmap.jison b/src/diagrams/mindmap/parser/mindmap.jison new file mode 100644 index 000000000..7ebb8b570 --- /dev/null +++ b/src/diagrams/mindmap/parser/mindmap.jison @@ -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'); } +.+ { return 'CLASS';this.popState(); } +\n { this.popState();} +[\n\s]*"::icon(" { this.begin('ICON'); } +[^\)]+ { return '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 */ ; +<> return 'EOF'; +["] { console.log('Starting NSTR');this.begin("NSTR");} +[^"]+ { console.log('description:', yytext); return "NODE_DESCR";} +["] {this.popState();} +[\)] {this.popState();console.log('node end');return "NODE_DEND";} +[\]] {this.popState();console.log('node end');return "NODE_DEND";} +[^\)\]]+ { 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) }; } + ; +%%