Merge pull request #251 from gibson042/gh-247

Properly handle "rest of line" statements
This commit is contained in:
Knut Sveidqvist 2015-11-06 07:23:23 +01:00
commit ecca3588bc
3 changed files with 150 additions and 95 deletions

View File

@ -19,7 +19,7 @@ var funs = [];
* @param style * @param style
*/ */
exports.addClass = function (id) { exports.addClass = function (id) {
console.log('Adding: '+id); log.log('Adding: '+id);
if(typeof classes.get(id) === 'undefined'){ if(typeof classes.get(id) === 'undefined'){
classes.set(id, { classes.set(id, {
id:id, id:id,
@ -46,7 +46,7 @@ module.exports.getRelations = function () {
}; };
exports.addRelation = function (relation) { exports.addRelation = function (relation) {
console.log('Adding relation: ' + JSON.stringify(relation)); log.log('Adding relation: ' + JSON.stringify(relation));
exports.addClass(relation.id1); exports.addClass(relation.id1);
exports.addClass(relation.id2); exports.addClass(relation.id2);
@ -76,4 +76,4 @@ exports.relationType = {
EXTENSION:1, EXTENSION:1,
COMPOSITION:2, COMPOSITION:2,
DEPENDENCY:3 DEPENDENCY:3
}; };

View File

@ -12,26 +12,23 @@
%options case-insensitive %options case-insensitive
%{ // A special state for grabbing text up to the first comment/newline
// Pre-lexer code can go here %x LINE
%}
%% %%
[\n]+ return 'NL'; [\n]+ return 'NL';
[\-][x] { return 'SOLID_CROSS';} \s+ /* skip all whitespace */
[\-][\-][x] { return 'DOTTED_CROSS';} <LINE>((?!\n)\s)+ /* skip same-line whitespace */
[\-][>][>] { return 'SOLID_ARROW';} <INITIAL,LINE>\#[^\n]* /* skip comments */
[\-][\-][>][>] { return 'DOTTED_ARROW';} \%%[^\n]* /* skip comments */
\s+ /* skip whitespace */
\#[^\n]* /* skip comments */
\%%[^\n]* /* skip comments */
"participant" return 'participant'; "participant" return 'participant';
"opt" return 'opt'; "loop" { this.begin('LINE'); return 'loop'; }
"loop" return 'loop'; "opt" { this.begin('LINE'); return 'opt'; }
"alt" return 'alt'; "alt" { this.begin('LINE'); return 'alt'; }
"else" return 'else'; "else" { this.begin('LINE'); return 'else'; }
"end" return 'end'; <LINE>[^#\n;]* { this.popState(); return 'restOfLine'; }
"end" return 'end';
"left of" return 'left_of'; "left of" return 'left_of';
"right of" return 'right_of'; "right of" return 'right_of';
"over" return 'over'; "over" return 'over';
@ -40,12 +37,14 @@
"sequenceDiagram" return 'SD'; "sequenceDiagram" return 'SD';
"," return ','; "," return ',';
";" return 'NL'; ";" return 'NL';
[^\->:\n,;]+ return 'ACTOR'; [^\->:\n,;]+ return 'ACTOR';
"->" return 'SOLID_OPEN_ARROW'; "->>" return 'SOLID_ARROW';
"-->" return 'DOTTED_OPEN_ARROW';
"->>" return 'SOLID_ARROW';
"-->>" return 'DOTTED_ARROW'; "-->>" return 'DOTTED_ARROW';
":"[^#\n;]+ return 'TXT'; "->" return 'SOLID_OPEN_ARROW';
"-->" return 'DOTTED_OPEN_ARROW';
\-[x] return 'SOLID_CROSS';
\-\-[x] return 'DOTTED_CROSS';
":"[^#\n;]+ return 'TXT';
<<EOF>> return 'EOF'; <<EOF>> return 'EOF';
. return 'INVALID'; . return 'INVALID';
@ -78,23 +77,23 @@ statement
| signal 'NL' | signal 'NL'
| note_statement 'NL' | note_statement 'NL'
| 'title' SPACE text 'NL' | 'title' SPACE text 'NL'
| 'loop' actor document end | 'loop' restOfLine document end
{ {
$3.unshift({type: 'loopStart', loopText:$2.actor, signalType: yy.LINETYPE.LOOP_START}); $3.unshift({type: 'loopStart', loopText:$2, signalType: yy.LINETYPE.LOOP_START});
$3.push({type: 'loopEnd', loopText:$2, signalType: yy.LINETYPE.LOOP_END}); $3.push({type: 'loopEnd', loopText:$2, signalType: yy.LINETYPE.LOOP_END});
$$=$3;} $$=$3;}
| opt actor document end | opt restOfLine document end
{ {
$3.unshift({type: 'optStart', optText:$2.actor, signalType: yy.LINETYPE.OPT_START}); $3.unshift({type: 'optStart', optText:$2, signalType: yy.LINETYPE.OPT_START});
$3.push({type: 'optEnd', optText:$2.actor, signalType: yy.LINETYPE.OPT_END}); $3.push({type: 'optEnd', optText:$2, signalType: yy.LINETYPE.OPT_END});
$$=$3;} $$=$3;}
| alt actor document else actor document end | alt restOfLine document else restOfLine document end
{ {
// Alt start // Alt start
$3.unshift({type: 'altStart', altText:$2.actor, signalType: yy.LINETYPE.ALT_START}); $3.unshift({type: 'altStart', altText:$2, signalType: yy.LINETYPE.ALT_START});
// Content in alt is already in $3 // Content in alt is already in $3
// Else // Else
$3.push({type: 'else', altText:$5.actor, signalType: yy.LINETYPE.ALT_ELSE}); $3.push({type: 'else', altText:$5, signalType: yy.LINETYPE.ALT_ELSE});
// Content in other alt // Content in other alt
$3 = $3.concat($6); $3 = $3.concat($6);
// End // End
@ -145,4 +144,4 @@ signaltype
text2: TXT {$$ = $1.substring(1).trim().replace(/\\n/gm, "\n");} ; text2: TXT {$$ = $1.substring(1).trim().replace(/\\n/gm, "\n");} ;
%% %%

View File

@ -29,7 +29,6 @@ describe('when parsing a sequenceDiagram',function() {
//}; //};
//sq.yy.parseError = parseError; //sq.yy.parseError = parseError;
}); });
it('it should handle a sequenceDiagram defintion', function () { it('it should handle a sequenceDiagram defintion', function () {
str = 'sequenceDiagram\n' + str = 'sequenceDiagram\n' +
'Alice->Bob:Hello Bob, how are you?\n' + 'Alice->Bob:Hello Bob, how are you?\n' +
@ -44,7 +43,6 @@ describe('when parsing a sequenceDiagram',function() {
var messages = sq.yy.getMessages(); var messages = sq.yy.getMessages();
expect(messages.length).toBe(3); expect(messages.length).toBe(3);
expect(messages[0].from).toBe('Alice'); expect(messages[0].from).toBe('Alice');
expect(messages[2].from).toBe('Bob'); expect(messages[2].from).toBe('Bob');
}); });
@ -61,7 +59,6 @@ describe('when parsing a sequenceDiagram',function() {
var messages = sq.yy.getMessages(); var messages = sq.yy.getMessages();
expect(messages.length).toBe(2); expect(messages.length).toBe(2);
expect(messages[0].from).toBe('Alice'); expect(messages[0].from).toBe('Alice');
expect(messages[1].from).toBe('Bob'); expect(messages[1].from).toBe('Bob');
}); });
@ -71,15 +68,12 @@ describe('when parsing a sequenceDiagram',function() {
sq.parse(str); sq.parse(str);
var actors = sq.yy.getActors(); var actors = sq.yy.getActors();
//log.debug(actors);
expect(actors.Alice.description).toBe('Alice'); expect(actors.Alice.description).toBe('Alice');
expect(actors.Bob.description).toBe('Bob'); expect(actors.Bob.description).toBe('Bob');
var messages = sq.yy.getMessages(); var messages = sq.yy.getMessages();
expect(messages.length).toBe(1); expect(messages.length).toBe(1);
expect(messages[0].type).toBe(sq.yy.LINETYPE.SOLID_CROSS); expect(messages[0].type).toBe(sq.yy.LINETYPE.SOLID_CROSS);
}); });
it('it should handle in async dotted messages', function () { it('it should handle in async dotted messages', function () {
@ -88,15 +82,12 @@ describe('when parsing a sequenceDiagram',function() {
sq.parse(str); sq.parse(str);
var actors = sq.yy.getActors(); var actors = sq.yy.getActors();
//log.debug(actors);
expect(actors.Alice.description).toBe('Alice'); expect(actors.Alice.description).toBe('Alice');
expect(actors.Bob.description).toBe('Bob'); expect(actors.Bob.description).toBe('Bob');
var messages = sq.yy.getMessages(); var messages = sq.yy.getMessages();
expect(messages.length).toBe(1); expect(messages.length).toBe(1);
expect(messages[0].type).toBe(sq.yy.LINETYPE.DOTTED_CROSS); expect(messages[0].type).toBe(sq.yy.LINETYPE.DOTTED_CROSS);
}); });
it('it should handle in arrow messages', function () { it('it should handle in arrow messages', function () {
@ -109,11 +100,8 @@ describe('when parsing a sequenceDiagram',function() {
expect(actors.Bob.description).toBe('Bob'); expect(actors.Bob.description).toBe('Bob');
var messages = sq.yy.getMessages(); var messages = sq.yy.getMessages();
//log.debug(messages);
expect(messages.length).toBe(1); expect(messages.length).toBe(1);
expect(messages[0].type).toBe(sq.yy.LINETYPE.SOLID); expect(messages[0].type).toBe(sq.yy.LINETYPE.SOLID);
}); });
it('it should handle in arrow messages', function () { it('it should handle in arrow messages', function () {
@ -126,11 +114,8 @@ describe('when parsing a sequenceDiagram',function() {
expect(actors.Bob.description).toBe('Bob'); expect(actors.Bob.description).toBe('Bob');
var messages = sq.yy.getMessages(); var messages = sq.yy.getMessages();
//log.debug(messages);
expect(messages.length).toBe(1); expect(messages.length).toBe(1);
expect(messages[0].type).toBe(sq.yy.LINETYPE.DOTTED); expect(messages[0].type).toBe(sq.yy.LINETYPE.DOTTED);
}); });
it('it should handle comments in a sequenceDiagram', function () { it('it should handle comments in a sequenceDiagram', function () {
@ -148,11 +133,9 @@ describe('when parsing a sequenceDiagram',function() {
var messages = sq.yy.getMessages(); var messages = sq.yy.getMessages();
expect(messages.length).toBe(3); expect(messages.length).toBe(3);
expect(messages[0].from).toBe('Alice'); expect(messages[0].from).toBe('Alice');
expect(messages[2].from).toBe('Bob'); expect(messages[2].from).toBe('Bob');
}); });
it('it should handle new lines in a sequenceDiagram', function () { it('it should handle new lines in a sequenceDiagram', function () {
str = 'sequenceDiagram\n' + str = 'sequenceDiagram\n' +
'Alice->Bob: Hello Bob, how are you?\n\n' + 'Alice->Bob: Hello Bob, how are you?\n\n' +
@ -168,11 +151,26 @@ describe('when parsing a sequenceDiagram',function() {
var messages = sq.yy.getMessages(); var messages = sq.yy.getMessages();
expect(messages.length).toBe(3); expect(messages.length).toBe(3);
expect(messages[0].from).toBe('Alice'); expect(messages[0].from).toBe('Alice');
expect(messages[2].from).toBe('Bob'); expect(messages[2].from).toBe('Bob');
}); });
it('it should handle semicolons', function () {
str = 'sequenceDiagram;' +
'Alice->Bob: Hello Bob, how are you?;' +
'Note right of Bob: Bob thinks;' +
'Bob-->Alice: I am good thanks!;';
sq.parse(str);
var actors = sq.yy.getActors();
expect(actors.Alice.description).toBe('Alice');
actors.Bob.description = 'Bob';
var messages = sq.yy.getMessages();
expect(messages.length).toBe(3);
expect(messages[0].from).toBe('Alice');
expect(messages[2].from).toBe('Bob');
});
it('it should handle one leading space in lines in a sequenceDiagram', function () { it('it should handle one leading space in lines in a sequenceDiagram', function () {
str = 'sequenceDiagram\n' + str = 'sequenceDiagram\n' +
' Alice->Bob: Hello Bob, how are you?\n\n' + ' Alice->Bob: Hello Bob, how are you?\n\n' +
@ -188,7 +186,6 @@ describe('when parsing a sequenceDiagram',function() {
var messages = sq.yy.getMessages(); var messages = sq.yy.getMessages();
expect(messages.length).toBe(3); expect(messages.length).toBe(3);
expect(messages[0].from).toBe('Alice'); expect(messages[0].from).toBe('Alice');
expect(messages[2].from).toBe('Bob'); expect(messages[2].from).toBe('Bob');
}); });
@ -207,7 +204,6 @@ describe('when parsing a sequenceDiagram',function() {
var messages = sq.yy.getMessages(); var messages = sq.yy.getMessages();
expect(messages.length).toBe(3); expect(messages.length).toBe(3);
expect(messages[0].from).toBe('Alice'); expect(messages[0].from).toBe('Alice');
expect(messages[2].from).toBe('Bob'); expect(messages[2].from).toBe('Bob');
}); });
@ -232,11 +228,9 @@ describe('when parsing a sequenceDiagram',function() {
var messages = sq.yy.getMessages(); var messages = sq.yy.getMessages();
expect(messages.length).toBe(8); expect(messages.length).toBe(8);
expect(messages[0].from).toBe('Alice'); expect(messages[0].from).toBe('Alice');
expect(messages[2].from).toBe('John'); expect(messages[2].from).toBe('John');
}); });
it('it should handle loop statements a sequenceDiagram', function () { it('it should handle loop statements a sequenceDiagram', function () {
var str = 'sequenceDiagram\n' + var str = 'sequenceDiagram\n' +
'Alice->Bob: Hello Bob, how are you?\n\n' + 'Alice->Bob: Hello Bob, how are you?\n\n' +
@ -248,20 +242,15 @@ describe('when parsing a sequenceDiagram',function() {
sq.parse(str); sq.parse(str);
var actors = sq.yy.getActors(); var actors = sq.yy.getActors();
//log.debug(actors);
expect(actors.Alice.description).toBe('Alice'); expect(actors.Alice.description).toBe('Alice');
actors.Bob.description = 'Bob'; actors.Bob.description = 'Bob';
var messages = sq.yy.getMessages(); var messages = sq.yy.getMessages();
//log.debug(messages);
expect(messages.length).toBe(5); expect(messages.length).toBe(5);
expect(messages[0].from).toBe('Alice'); expect(messages[0].from).toBe('Alice');
expect(messages[1].from).toBe('Bob'); expect(messages[1].from).toBe('Bob');
}); });
it('it should handle opt statements a sequenceDiagram', function () { it('it should handle opt statements a sequenceDiagram', function () {
var str = 'sequenceDiagram\n' + var str = 'sequenceDiagram\n' +
'Alice->Bob: Hello Bob, how are you?\n\n' + 'Alice->Bob: Hello Bob, how are you?\n\n' +
@ -273,39 +262,15 @@ describe('when parsing a sequenceDiagram',function() {
sq.parse(str); sq.parse(str);
var actors = sq.yy.getActors(); var actors = sq.yy.getActors();
//log.debug(actors);
expect(actors.Alice.description).toBe('Alice'); expect(actors.Alice.description).toBe('Alice');
actors.Bob.description = 'Bob'; actors.Bob.description = 'Bob';
var messages = sq.yy.getMessages(); var messages = sq.yy.getMessages();
//log.debug(messages);
expect(messages.length).toBe(5); expect(messages.length).toBe(5);
expect(messages[0].from).toBe('Alice'); expect(messages[0].from).toBe('Alice');
expect(messages[1].from).toBe('Bob'); expect(messages[1].from).toBe('Bob');
}); });
it('it should handle opt statements a sequenceDiagram', function () {
var str = 'sequenceDiagram;Alice->Bob: Hello Bob, how are you?;opt Perhaps a happy response;Bob-->Alice: I am good thanks!;end;';
sq.parse(str);
var actors = sq.yy.getActors();
//log.debug(actors);
expect(actors.Alice.description).toBe('Alice');
actors.Bob.description = 'Bob';
var messages = sq.yy.getMessages();
//log.debug(messages);
expect(messages.length).toBe(4);
expect(messages[0].from).toBe('Alice');
expect(messages[1].type).toBe(sq.yy.LINETYPE.OPT_START);
expect(messages[2].from).toBe('Bob');
});
it('it should handle alt statements a sequenceDiagram', function () { it('it should handle alt statements a sequenceDiagram', function () {
var str = 'sequenceDiagram\n' + var str = 'sequenceDiagram\n' +
'Alice->Bob: Hello Bob, how are you?\n\n' + 'Alice->Bob: Hello Bob, how are you?\n\n' +
@ -324,14 +289,113 @@ describe('when parsing a sequenceDiagram',function() {
actors.Bob.description = 'Bob'; actors.Bob.description = 'Bob';
var messages = sq.yy.getMessages(); var messages = sq.yy.getMessages();
//log.debug(messages);
expect(messages.length).toBe(7); expect(messages.length).toBe(7);
expect(messages[0].from).toBe('Alice'); expect(messages[0].from).toBe('Alice');
expect(messages[1].from).toBe('Bob'); expect(messages[1].from).toBe('Bob');
});
it('it should handle special characters in signals', function () {
var str = 'sequenceDiagram\n' +
'Alice->Bob: -:<>,;# comment';
sq.parse(str);
});}); var messages = sq.yy.getMessages();
expect(messages[0].message).toBe('-:<>,');
});
it('it should handle special characters in notes', function () {
var str = 'sequenceDiagram\n' +
'Alice->Bob: Hello Bob, how are you?\n' +
'Note right of Bob: -:<>,;# comment';
sq.parse(str);
var messages = sq.yy.getMessages();
expect(messages[1].message).toBe('-:<>,');
});
it('it should handle special characters in loop', function () {
var str = 'sequenceDiagram\n' +
'Alice->Bob: Hello Bob, how are you?\n' +
'loop -:<>,;# comment\n' +
'Bob-->Alice: I am good thanks!\n' +
'end';
sq.parse(str);
var messages = sq.yy.getMessages();
expect(messages[1].message).toBe('-:<>,');
});
it('it should handle special characters in opt', function () {
var str = 'sequenceDiagram\n' +
'Alice->Bob: Hello Bob, how are you?\n' +
'opt -:<>,;# comment\n' +
'Bob-->Alice: I am good thanks!\n' +
'end';
sq.parse(str);
var messages = sq.yy.getMessages();
expect(messages[1].message).toBe('-:<>,');
});
it('it should handle special characters in alt', function () {
var str = 'sequenceDiagram\n' +
'Alice->Bob: Hello Bob, how are you?\n' +
'alt -:<>,;# comment\n' +
'Bob-->Alice: I am good thanks!\n' +
'else ,<>:-#; comment\n' +
'Bob-->Alice: I am good thanks!\n' +
'end';
sq.parse(str);
var messages = sq.yy.getMessages();
expect(messages[1].message).toBe('-:<>,');
expect(messages[3].message).toBe(',<>:-');
});
it('it should handle no-label loop', function () {
var str = 'sequenceDiagram\n' +
'Alice->Bob: Hello Bob, how are you?\n' +
'loop\n' +
'Bob-->Alice: I am good thanks!\n' +
'end';
sq.parse(str);
var messages = sq.yy.getMessages();
expect(messages[1].message).toBe('');
expect(messages[2].message).toBe('I am good thanks!');
});
it('it should handle no-label opt', function () {
var str = 'sequenceDiagram\n' +
'Alice->Bob: Hello Bob, how are you?\n' +
'opt # comment\n' +
'Bob-->Alice: I am good thanks!\n' +
'end';
sq.parse(str);
var messages = sq.yy.getMessages();
expect(messages[1].message).toBe('');
expect(messages[2].message).toBe('I am good thanks!');
});
it('it should handle no-label alt', function () {
var str = 'sequenceDiagram\n' +
'Alice->Bob: Hello Bob, how are you?\n' +
'alt;' +
'Bob-->Alice: I am good thanks!\n' +
'else # comment\n' +
'Bob-->Alice: I am good thanks!\n' +
'end';
sq.parse(str);
var messages = sq.yy.getMessages();
expect(messages[1].message).toBe('');
expect(messages[2].message).toBe('I am good thanks!');
expect(messages[3].message).toBe('');
expect(messages[4].message).toBe('I am good thanks!');
});
});
describe('when checking the bounds in a sequenceDiagram',function() { describe('when checking the bounds in a sequenceDiagram',function() {
var conf; var conf;
@ -398,7 +462,6 @@ describe('when checking the bounds in a sequenceDiagram',function() {
expect(bounds.stopy ).toBe(400); expect(bounds.stopy ).toBe(400);
}); });
it('it should handle a loop without expanding the area', function () { it('it should handle a loop without expanding the area', function () {
sd.bounds.init(); sd.bounds.init();
@ -422,8 +485,6 @@ describe('when checking the bounds in a sequenceDiagram',function() {
expect(bounds.stopx ).toBe(300); expect(bounds.stopx ).toBe(300);
expect(bounds.stopy ).toBe(400); expect(bounds.stopy ).toBe(400);
}); });
it('it should handle multiple loops withtout expanding the bounds', function () { it('it should handle multiple loops withtout expanding the bounds', function () {
sd.bounds.init(); sd.bounds.init();
@ -457,7 +518,6 @@ describe('when checking the bounds in a sequenceDiagram',function() {
expect(bounds.stopx ).toBe(1000); expect(bounds.stopx ).toBe(1000);
expect(bounds.stopy ).toBe(1000); expect(bounds.stopy ).toBe(1000);
}); });
it('it should handle a loop that expands the area', function () { it('it should handle a loop that expands the area', function () {
sd.bounds.init(); sd.bounds.init();
@ -610,7 +670,6 @@ describe('when rendering a sequenceDiagram',function() {
expect(bounds.stopy ).toBe(0 + conf.messageMargin + conf.height); expect(bounds.stopy ).toBe(0 + conf.messageMargin + conf.height);
}); });
it('it should draw two actors and two messages', function () { it('it should draw two actors and two messages', function () {
sd.bounds.init(); sd.bounds.init();
var str = 'sequenceDiagram\n' + var str = 'sequenceDiagram\n' +
@ -627,8 +686,6 @@ describe('when rendering a sequenceDiagram',function() {
expect(bounds.stopy ).toBe(0 + 2*conf.messageMargin + conf.height); expect(bounds.stopy ).toBe(0 + 2*conf.messageMargin + conf.height);
}); });
it('it should draw two actors notes to the right', function () { it('it should draw two actors notes to the right', function () {
sd.bounds.init(); sd.bounds.init();
var str = 'sequenceDiagram\n' + var str = 'sequenceDiagram\n' +
@ -667,7 +724,6 @@ describe('when rendering a sequenceDiagram',function() {
expect(bounds.stopy ).toBe( 2*conf.messageMargin + conf.height + conf.boxMargin +10+ 2*conf.noteMargin); expect(bounds.stopy ).toBe( 2*conf.messageMargin + conf.height + conf.boxMargin +10+ 2*conf.noteMargin);
}); });
it('it should draw two loops', function () { it('it should draw two loops', function () {
sd.bounds.init(); sd.bounds.init();
var str = 'sequenceDiagram\n' + var str = 'sequenceDiagram\n' +
@ -762,4 +818,4 @@ describe('when rendering a sequenceDiagram with actor mirror activated',function
expect(bounds.stopy ).toBe(2*conf.height+2*conf.boxMargin); expect(bounds.stopy ).toBe(2*conf.height+2*conf.boxMargin);
}); });
}); });