First take on grammar

This commit is contained in:
Knut Sveidqvist 2022-07-21 16:07:18 +02:00
parent 8681e78e50
commit 6029c5371e
8 changed files with 382 additions and 96 deletions

View File

@ -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: {

View File

@ -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);
});
});

View File

@ -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
};

View 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 ()');
});
});
});

View 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
};

View File

@ -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); }
;
%%

View 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) }; }
;
%%