mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-10-05 07:09:40 +02:00
Compare commits
20 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
5b85fe9293 | ||
![]() |
b5e3323a93 | ||
![]() |
8f6d148481 | ||
![]() |
671a892b52 | ||
![]() |
5c25c5563a | ||
![]() |
8b05eeaa59 | ||
![]() |
1b001cf1e8 | ||
![]() |
c8091c61c0 | ||
![]() |
5d9018aeec | ||
![]() |
cf686c445c | ||
![]() |
0478e4217b | ||
![]() |
f11d1a6fa1 | ||
![]() |
9dc6668e8a | ||
![]() |
527aea9264 | ||
![]() |
056f321ee6 | ||
![]() |
e679556975 | ||
![]() |
e9f4ac7425 | ||
![]() |
c6502fb03b | ||
![]() |
83b7163844 | ||
![]() |
c33533082c |
@@ -6,10 +6,10 @@
|
||||
|
||||
## Special note regarding version 8.2
|
||||
|
||||
In version 8.2 a security improvement was introduced. A securityLevel configuration was introduced wich sets the level of trust to be used on the parsed diagrams.
|
||||
In version 8.2 a security improvement was introduced. A securityLevel configuration was introduced which sets the level of trust to be used on the parsed diagrams.
|
||||
|
||||
* **true**: (default) tags in text are encoded, click functionality is disabled
|
||||
* false: tags in text are allowed, click functionality is enabledClosed issues:
|
||||
* **`strict`**: (default) tags in text are encoded, click functionality is disabled
|
||||
* `loose`: tags in text are allowed, click functionality is enabledClosed issues:
|
||||
|
||||
⚠️ **Note** : This changes the default behaviour of mermaid so that after upgrade to 8.2, if the securityLevel is not configured, tags in flowcharts are encoded as tags and clicking is prohibited.
|
||||
|
||||
|
36
__mocks__/d3.js
vendored
36
__mocks__/d3.js
vendored
@@ -1,17 +1,16 @@
|
||||
/* eslint-env jest */
|
||||
let NewD3 = function () {
|
||||
function returnThis () {
|
||||
return this
|
||||
}
|
||||
return {
|
||||
append: function () {
|
||||
return NewD3()
|
||||
},
|
||||
attr: function () {
|
||||
return this
|
||||
},
|
||||
style: function () {
|
||||
return this
|
||||
},
|
||||
text: function () {
|
||||
return this
|
||||
},
|
||||
lower: returnThis,
|
||||
attr: returnThis,
|
||||
style: returnThis,
|
||||
text: returnThis,
|
||||
0: {
|
||||
0: {
|
||||
getBBox: function () {
|
||||
@@ -36,3 +35,22 @@ export const selectAll = function () {
|
||||
export const curveBasis = 'basis'
|
||||
export const curveLinear = 'linear'
|
||||
export const curveCardinal = 'cardinal'
|
||||
|
||||
export const MockD3 = (name, parent) => {
|
||||
const children = []
|
||||
const elem = {
|
||||
get __children () { return children },
|
||||
get __name () { return name },
|
||||
get __parent () { return parent }
|
||||
}
|
||||
elem.append = (name) => {
|
||||
const mockElem = MockD3(name, elem)
|
||||
children.push(mockElem)
|
||||
return mockElem
|
||||
}
|
||||
elem.lower = jest.fn(() => elem)
|
||||
elem.attr = jest.fn(() => elem)
|
||||
elem.text = jest.fn(() => elem)
|
||||
elem.style = jest.fn(() => elem)
|
||||
return elem
|
||||
}
|
||||
|
4
dist/index.html
vendored
4
dist/index.html
vendored
@@ -305,12 +305,16 @@ sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
participant John as John<br/>Second Line
|
||||
rect rgb(200, 220, 100)
|
||||
rect rgb(200, 255, 200)
|
||||
Alice ->> Bob: Hello Bob, how are you?
|
||||
Bob-->>John: How about you John?
|
||||
end
|
||||
Bob--x Alice: I am good thanks!
|
||||
Bob-x John: I am good thanks!
|
||||
Note right of John: Bob thinks a long<br/>long time, so long<br/>that the text does<br/>not fit on a row.
|
||||
Bob-->Alice: Checking with John...
|
||||
end
|
||||
alt either this
|
||||
Alice->>John: Yes
|
||||
else or this
|
||||
|
94
dist/xssi.html
vendored
94
dist/xssi.html
vendored
@@ -10,11 +10,31 @@
|
||||
alert(x + ' cause an xss attack');
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.label text { fill: red}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="mermaid">
|
||||
info
|
||||
</div>
|
||||
<div class="mermaid">
|
||||
graph LR;
|
||||
alert`xss`-->B;
|
||||
click B "javaSc
|
||||
ript:alert`salt`" "This is a tooltip for a link"
|
||||
</div>
|
||||
<div class="mermaid">
|
||||
graph LR;
|
||||
alert`xss`-->B;
|
||||
click B "java
|
||||
script:alert`xss`" "This is a tooltip for a link"
|
||||
</div>
|
||||
<div class="mermaid">
|
||||
graph LR;
|
||||
alert`base64`-->B;
|
||||
click B "data:image/png;base64,HNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4="
|
||||
</div>
|
||||
<img src=xss.png />
|
||||
<div class="mermaid">
|
||||
graph TD
|
||||
@@ -37,13 +57,56 @@ BBBB --> C{Let me think}
|
||||
C -->|One| D[Laptop]
|
||||
C -->|Two| E[iPhone]
|
||||
C -->|Three| F[Car]
|
||||
click A "index.html#link-clicked" "link test"
|
||||
click A "http://localhost:9000/index.html#link-clicked" "link test"
|
||||
click BBBB testClick "click test"
|
||||
click C "javascript:alert" "link test"
|
||||
classDef someclass fill:#f96;
|
||||
class A someclass;
|
||||
</div>
|
||||
|
||||
<div class="mermaid">
|
||||
graph LR;
|
||||
alert`md5_salt`-->B;
|
||||
click alert`md5_salt` eval "Tooltip for a callback"
|
||||
click B "javascript:alert`salt`" "This is a tooltip for a link"
|
||||
</div>
|
||||
<div class="mermaid">
|
||||
gantt
|
||||
dateFormat YYYY-MM-DD
|
||||
axisFormat %d/%m
|
||||
title Adding GANTT diagram to mermaid
|
||||
excludes weekdays 2014-01-10
|
||||
|
||||
section A section
|
||||
Completed task :done, des1, 2014-01-06,2014-01-08
|
||||
Active task :active, des2, 2014-01-09, 3d
|
||||
Future task : des3, after des2, 5d
|
||||
Future task2 : des4, after des3, 5d
|
||||
|
||||
section Critical tasks
|
||||
Completed task in the critical line :crit, done, 2014-01-06,24h
|
||||
Implement parser and jison :crit, done, after des1, 2d
|
||||
Create tests for parser :crit, active, 3d
|
||||
Future task in critical line :crit, 5d
|
||||
Create tests for renderer :2d
|
||||
Add to mermaid :1d
|
||||
|
||||
section Documentation
|
||||
Describe gantt syntax :active, a1, after des1, 3d
|
||||
Add gantt diagram to demo page :after a1 , 20h
|
||||
Add another diagram to demo page :doc1, after a1 , 48h
|
||||
|
||||
section Clickable
|
||||
Visit mermaidjs :active, cl1, 2014-01-07,2014-01-10
|
||||
Calling a Callback (look at the console log) :cl2, after cl1, 3d
|
||||
|
||||
click cl1 href "javascript:alert`salt`"
|
||||
click cl2 call ganttTestClick("test", test, test)
|
||||
|
||||
section Last section
|
||||
Describe gantt syntax :after doc1, 3d
|
||||
Add gantt diagram to demo page : 20h
|
||||
Add another diagram to demo page : 48h
|
||||
</div>
|
||||
<div class="mermaid">
|
||||
sequenceDiagram
|
||||
participant "Alice"
|
||||
@@ -85,18 +148,39 @@ Class01 : int chimp
|
||||
Class01 : int gorilla
|
||||
Class08 <--> C2: Cool label
|
||||
</div>
|
||||
<div class="mermaid">
|
||||
graph LR
|
||||
|
||||
SavePropertyController --> SavePropertyCommand
|
||||
SavePropertyCommand --> SavePropertyCommandHandler
|
||||
SavePropertyCommandHandler --> EventElastica[elastica.postupdate]
|
||||
SavePropertyCommandHandler --> EventProperty[property.postdisable]
|
||||
|
||||
SavePropertyController --> Exceptions
|
||||
Exceptions --> ExceptionList(SecurityException<br/>EmptyRequestBodyException<br/>Throwable)
|
||||
|
||||
classDef Ui fill:#FFFFFF
|
||||
classDef object fill:#1E98EC
|
||||
classDef event fill:#ECB11E
|
||||
|
||||
class EventElastica,EventProperty event
|
||||
class SavePropertyCommand,SavePropertyCommandHandler object
|
||||
class SavePropertyController Ui
|
||||
</div>
|
||||
|
||||
<script src="./mermaid.js"></script>
|
||||
<!-- <script src="//cdn.jsdelivr.net/npm/mermaid@8.2.1/dist/mermaid.min.js"></script> -->
|
||||
<script>
|
||||
mermaid.initialize({
|
||||
theme: 'forest',
|
||||
// themeCSS: '.node rect { fill: red; }',
|
||||
logLevel: 3,
|
||||
flowchart: { curve: 'linear' },
|
||||
logLevel: 4,
|
||||
flowchart: { htmlLabels: false, curve: 'linear' },
|
||||
gantt: { axisFormat: '%m/%d/%Y' },
|
||||
sequence: { actorMargin: 50 },
|
||||
// sequenceDiagram: { actorMargin: 300 } // deprecated
|
||||
securityLevel:'loose'
|
||||
securityLevel:'strict',
|
||||
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
|
@@ -111,13 +111,13 @@ graph LR
|
||||
id1{This is the text in the box}
|
||||
```
|
||||
|
||||
### 1
|
||||
### Trapeziod
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[/Christmas\]
|
||||
```
|
||||
### 2
|
||||
### Trapeziod alt
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
@@ -32,4 +32,90 @@ describe('Sequencediagram', () => {
|
||||
`,
|
||||
{})
|
||||
})
|
||||
describe('background rects', async () => {
|
||||
it('should render a single and nested rects', async () => {
|
||||
await imgSnapshotTest(page, `
|
||||
sequenceDiagram
|
||||
participant A
|
||||
participant B
|
||||
participant C
|
||||
participant D
|
||||
participant E
|
||||
participant G
|
||||
|
||||
A ->>+ B: Task 1
|
||||
rect rgb(178, 102, 255)
|
||||
B ->>+ C: Task 2
|
||||
C -->>- B: Return
|
||||
end
|
||||
|
||||
A ->> D: Task 3
|
||||
rect rgb(0, 128, 255)
|
||||
D ->>+ E: Task 4
|
||||
rect rgb(0, 204, 0)
|
||||
E ->>+ G: Task 5
|
||||
G -->>- E: Return
|
||||
end
|
||||
E ->> E: Task 6
|
||||
end
|
||||
D -->> A: Complete
|
||||
`, {})
|
||||
})
|
||||
it('should render rect around and inside loops', async () => {
|
||||
await imgSnapshotTest(page, `
|
||||
sequenceDiagram
|
||||
A ->> B: 1
|
||||
rect rgb(204, 0, 102)
|
||||
loop check C
|
||||
C ->> C: Every 10 seconds
|
||||
end
|
||||
end
|
||||
A ->> B: 2
|
||||
loop check D
|
||||
C ->> D: 3
|
||||
rect rgb(153, 153, 255)
|
||||
D -->> D: 5
|
||||
D --> C: 4
|
||||
end
|
||||
end
|
||||
`, {})
|
||||
})
|
||||
it('should render rect around and inside alts', async () => {
|
||||
await imgSnapshotTest(page, `
|
||||
sequenceDiagram
|
||||
A ->> B: 1
|
||||
rect rgb(204, 0, 102)
|
||||
alt yes
|
||||
C ->> C: 1
|
||||
else no
|
||||
rect rgb(0, 204, 204)
|
||||
C ->> C: 0
|
||||
end
|
||||
end
|
||||
end
|
||||
B ->> A: Return
|
||||
`, {})
|
||||
})
|
||||
it('should render rect around and inside opts', async () => {
|
||||
await imgSnapshotTest(page, `
|
||||
sequenceDiagram
|
||||
A ->> B: 1
|
||||
rect rgb(204, 0, 102)
|
||||
opt maybe
|
||||
C -->> D: Do something
|
||||
rect rgb(0, 204, 204)
|
||||
C ->> C: 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
opt possibly
|
||||
rect rgb(0, 204, 204)
|
||||
C ->> C: 0
|
||||
end
|
||||
end
|
||||
B ->> A: Return
|
||||
`, {})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mermaid",
|
||||
"version": "8.2.1",
|
||||
"version": "8.2.3",
|
||||
"description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
|
||||
"main": "dist/mermaid.core.js",
|
||||
"keywords": [
|
||||
@@ -44,6 +44,7 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@braintree/sanitize-url": "^3.1.0",
|
||||
"d3": "^5.7.0",
|
||||
"dagre-d3-renderer": "^0.5.8",
|
||||
"dagre-layout": "^0.8.8",
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import * as d3 from 'd3'
|
||||
|
||||
import { sanitizeUrl } from '@braintree/sanitize-url'
|
||||
import { logger } from '../../logger'
|
||||
import utils from '../../utils'
|
||||
import { getConfig } from '../../config'
|
||||
@@ -22,6 +22,7 @@ const sanitize = text => {
|
||||
txt = txt.replace(/<br>/g, '#br#')
|
||||
txt = txt.replace(/<br\S*?\/>/g, '#br#')
|
||||
txt = txt.replace(/</g, '<').replace(/>/g, '>')
|
||||
txt = txt.replace(/=/g, '=')
|
||||
txt = txt.replace(/#br#/g, '<br/>')
|
||||
}
|
||||
|
||||
@@ -214,7 +215,11 @@ const setClickFun = function (id, functionName) {
|
||||
export const setLink = function (ids, linkStr, tooltip) {
|
||||
ids.split(',').forEach(function (id) {
|
||||
if (typeof vertices[id] !== 'undefined') {
|
||||
vertices[id].link = linkStr
|
||||
if (config.securityLevel === 'strict') {
|
||||
vertices[id].link = sanitizeUrl(linkStr) // .replace(/javascript:.*/g, '')
|
||||
} else {
|
||||
vertices[id].link = linkStr
|
||||
}
|
||||
}
|
||||
})
|
||||
setTooltip(ids, tooltip)
|
||||
|
@@ -3,6 +3,7 @@ import * as d3 from 'd3'
|
||||
|
||||
import flowDb from './flowDb'
|
||||
import flow from './parser/flow'
|
||||
import { getConfig } from '../../config'
|
||||
import dagreD3 from 'dagre-d3-renderer'
|
||||
import addHtmlLabel from 'dagre-d3-renderer/lib/label/add-html-label.js'
|
||||
import { logger } from '../../logger'
|
||||
@@ -63,7 +64,7 @@ export const addVertices = function (vert, g, svgId) {
|
||||
|
||||
// We create a SVG label, either by delegating to addHtmlLabel or manually
|
||||
let vertexNode
|
||||
if (conf.htmlLabels) {
|
||||
if (getConfig().flowchart.htmlLabels) {
|
||||
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
|
||||
const node = { label: vertexText.replace(/fa[lrsb]?:fa-[\w-]+/g, s => `<i class='${s.replace(':', ' ')}'></i>`) }
|
||||
vertexNode = addHtmlLabel(svg, node).node()
|
||||
@@ -205,7 +206,7 @@ export const addEdges = function (edges, g) {
|
||||
edgeData.arrowheadStyle = 'fill: #333'
|
||||
if (typeof edge.style === 'undefined') {
|
||||
edgeData.labelpos = 'c'
|
||||
if (conf.htmlLabels) {
|
||||
if (getConfig().flowchart.htmlLabels) {
|
||||
edgeData.labelType = 'html'
|
||||
edgeData.label = '<span class="edgeLabel">' + edge.text + '</span>'
|
||||
} else {
|
||||
@@ -534,7 +535,7 @@ export const draw = function (text, id) {
|
||||
}
|
||||
|
||||
// Add label rects for non html labels
|
||||
if (!conf.htmlLabels) {
|
||||
if (!getConfig().flowchart.htmlLabels) {
|
||||
const labels = document.querySelectorAll('#' + id + ' .edgeLabel .label')
|
||||
for (let k = 0; k < labels.length; k++) {
|
||||
const label = labels[k]
|
||||
|
@@ -1631,7 +1631,7 @@ describe('when parsing ', function () {
|
||||
})
|
||||
|
||||
it('it should be able to parse a \'=\'', function () {
|
||||
charTest('=')
|
||||
charTest('=','=')
|
||||
})
|
||||
it('it should be able to parse a \'&\'', function () {
|
||||
charTest('&')
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import moment from 'moment-mini'
|
||||
import { sanitizeUrl } from '@braintree/sanitize-url'
|
||||
import { logger } from '../../logger'
|
||||
import * as d3 from 'd3'
|
||||
import { getConfig } from '../../config'
|
||||
|
||||
const config = getConfig()
|
||||
@@ -64,12 +64,10 @@ export const getExcludes = function () {
|
||||
}
|
||||
|
||||
export const setTitle = function (txt) {
|
||||
console.log('Setting title ', txt)
|
||||
title = txt
|
||||
}
|
||||
|
||||
export const getTitle = function () {
|
||||
console.log('Title is ', title)
|
||||
return title
|
||||
}
|
||||
|
||||
@@ -430,7 +428,11 @@ const compileTasks = function () {
|
||||
* @param ids Comma separated list of ids
|
||||
* @param linkStr URL to create a link for
|
||||
*/
|
||||
export const setLink = function (ids, linkStr) {
|
||||
export const setLink = function (ids, _linkStr) {
|
||||
let linkStr = _linkStr
|
||||
if (config.securityLevel === 'strict') {
|
||||
linkStr = sanitizeUrl(_linkStr)
|
||||
}
|
||||
ids.split(',').forEach(function (id) {
|
||||
let rawTask = findTaskById(id)
|
||||
if (typeof rawTask !== 'undefined') {
|
||||
@@ -490,17 +492,19 @@ const setClickFun = function (id, functionName, functionArgs) {
|
||||
*/
|
||||
const pushFun = function (id, callbackFunction) {
|
||||
funs.push(function (element) {
|
||||
const elem = d3.select(element).select(`[id="${id}"]`)
|
||||
// const elem = d3.select(element).select(`[id="${id}"]`)
|
||||
const elem = document.querySelector(`[id="${id}"]`)
|
||||
if (elem !== null) {
|
||||
elem.on('click', function () {
|
||||
elem.addEventListener('click', function () {
|
||||
callbackFunction()
|
||||
})
|
||||
}
|
||||
})
|
||||
funs.push(function (element) {
|
||||
const elem = d3.select(element).select(`[id="${id}-text"]`)
|
||||
// const elem = d3.select(element).select(`[id="${id}-text"]`)
|
||||
const elem = document.querySelector(`[id="${id}-text"]`)
|
||||
if (elem !== null) {
|
||||
elem.on('click', function () {
|
||||
elem.addEventListener('click', function () {
|
||||
callbackFunction()
|
||||
})
|
||||
}
|
||||
|
@@ -201,6 +201,7 @@ export const draw = function (text, id) {
|
||||
|
||||
// Append task labels
|
||||
rectangles.append('text')
|
||||
.attr('id', function (d) { return d.id + '-text' })
|
||||
.text(function (d) {
|
||||
return d.task
|
||||
})
|
||||
|
@@ -31,6 +31,7 @@
|
||||
<ALIAS>"as" { this.popState(); this.popState(); this.begin('LINE'); return 'AS'; }
|
||||
<ALIAS>(?:) { this.popState(); this.popState(); return 'NL'; }
|
||||
"loop" { this.begin('LINE'); return 'loop'; }
|
||||
"rect" { this.begin('LINE'); return 'rect'; }
|
||||
"opt" { this.begin('LINE'); return 'opt'; }
|
||||
"alt" { this.begin('LINE'); return 'alt'; }
|
||||
"else" { this.begin('LINE'); return 'else'; }
|
||||
@@ -99,6 +100,11 @@ statement
|
||||
$3.unshift({type: 'loopStart', loopText:$2, signalType: yy.LINETYPE.LOOP_START});
|
||||
$3.push({type: 'loopEnd', loopText:$2, signalType: yy.LINETYPE.LOOP_END});
|
||||
$$=$3;}
|
||||
| 'rect' restOfLine document end
|
||||
{
|
||||
$3.unshift({type: 'rectStart', color:$2, signalType: yy.LINETYPE.RECT_START });
|
||||
$3.push({type: 'rectEnd', color:$2, signalType: yy.LINETYPE.RECT_END });
|
||||
$$=$3;}
|
||||
| opt restOfLine document end
|
||||
{
|
||||
$3.unshift({type: 'optStart', optText:$2, signalType: yy.LINETYPE.OPT_START});
|
||||
|
@@ -71,13 +71,13 @@
|
||||
recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error)
|
||||
}
|
||||
*/
|
||||
var sequenceDiagram = (function(){
|
||||
var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[1,2],$V1=[1,3],$V2=[1,4],$V3=[2,4],$V4=[1,9],$V5=[1,11],$V6=[1,12],$V7=[1,14],$V8=[1,15],$V9=[1,17],$Va=[1,18],$Vb=[1,19],$Vc=[1,20],$Vd=[1,21],$Ve=[1,23],$Vf=[1,24],$Vg=[1,4,5,10,15,16,18,20,21,22,23,25,27,28,29,40],$Vh=[1,32],$Vi=[4,5,10,15,16,18,20,21,22,23,25,29,40],$Vj=[4,5,10,15,16,18,20,21,22,23,25,28,29,40],$Vk=[4,5,10,15,16,18,20,21,22,23,25,27,29,40],$Vl=[38,39,40];
|
||||
var parser = (function(){
|
||||
var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[1,2],$V1=[1,3],$V2=[1,4],$V3=[2,4],$V4=[1,9],$V5=[1,11],$V6=[1,12],$V7=[1,14],$V8=[1,15],$V9=[1,17],$Va=[1,18],$Vb=[1,19],$Vc=[1,20],$Vd=[1,21],$Ve=[1,22],$Vf=[1,24],$Vg=[1,25],$Vh=[1,4,5,10,15,16,18,20,21,22,23,24,26,28,29,30,41],$Vi=[1,33],$Vj=[4,5,10,15,16,18,20,21,22,23,24,26,30,41],$Vk=[4,5,10,15,16,18,20,21,22,23,24,26,29,30,41],$Vl=[4,5,10,15,16,18,20,21,22,23,24,26,28,30,41],$Vm=[39,40,41];
|
||||
var parser = {trace: function trace () { },
|
||||
yy: {},
|
||||
symbols_: {"error":2,"start":3,"SPACE":4,"NL":5,"SD":6,"document":7,"line":8,"statement":9,"participant":10,"actor":11,"AS":12,"restOfLine":13,"signal":14,"activate":15,"deactivate":16,"note_statement":17,"title":18,"text2":19,"loop":20,"end":21,"opt":22,"alt":23,"else_sections":24,"par":25,"par_sections":26,"and":27,"else":28,"note":29,"placement":30,"over":31,"actor_pair":32,"spaceList":33,",":34,"left_of":35,"right_of":36,"signaltype":37,"+":38,"-":39,"ACTOR":40,"SOLID_OPEN_ARROW":41,"DOTTED_OPEN_ARROW":42,"SOLID_ARROW":43,"DOTTED_ARROW":44,"SOLID_CROSS":45,"DOTTED_CROSS":46,"TXT":47,"$accept":0,"$end":1},
|
||||
terminals_: {2:"error",4:"SPACE",5:"NL",6:"SD",10:"participant",12:"AS",13:"restOfLine",15:"activate",16:"deactivate",18:"title",20:"loop",21:"end",22:"opt",23:"alt",25:"par",27:"and",28:"else",29:"note",31:"over",34:",",35:"left_of",36:"right_of",38:"+",39:"-",40:"ACTOR",41:"SOLID_OPEN_ARROW",42:"DOTTED_OPEN_ARROW",43:"SOLID_ARROW",44:"DOTTED_ARROW",45:"SOLID_CROSS",46:"DOTTED_CROSS",47:"TXT"},
|
||||
productions_: [0,[3,2],[3,2],[3,2],[7,0],[7,2],[8,2],[8,1],[8,1],[9,5],[9,3],[9,2],[9,3],[9,3],[9,2],[9,3],[9,4],[9,4],[9,4],[9,4],[26,1],[26,4],[24,1],[24,4],[17,4],[17,4],[33,2],[33,1],[32,3],[32,1],[30,1],[30,1],[14,5],[14,5],[14,4],[11,1],[37,1],[37,1],[37,1],[37,1],[37,1],[37,1],[19,1]],
|
||||
symbols_: {"error":2,"start":3,"SPACE":4,"NL":5,"SD":6,"document":7,"line":8,"statement":9,"participant":10,"actor":11,"AS":12,"restOfLine":13,"signal":14,"activate":15,"deactivate":16,"note_statement":17,"title":18,"text2":19,"loop":20,"end":21,"rect":22,"opt":23,"alt":24,"else_sections":25,"par":26,"par_sections":27,"and":28,"else":29,"note":30,"placement":31,"over":32,"actor_pair":33,"spaceList":34,",":35,"left_of":36,"right_of":37,"signaltype":38,"+":39,"-":40,"ACTOR":41,"SOLID_OPEN_ARROW":42,"DOTTED_OPEN_ARROW":43,"SOLID_ARROW":44,"DOTTED_ARROW":45,"SOLID_CROSS":46,"DOTTED_CROSS":47,"TXT":48,"$accept":0,"$end":1},
|
||||
terminals_: {2:"error",4:"SPACE",5:"NL",6:"SD",10:"participant",12:"AS",13:"restOfLine",15:"activate",16:"deactivate",18:"title",20:"loop",21:"end",22:"rect",23:"opt",24:"alt",26:"par",28:"and",29:"else",30:"note",32:"over",35:",",36:"left_of",37:"right_of",39:"+",40:"-",41:"ACTOR",42:"SOLID_OPEN_ARROW",43:"DOTTED_OPEN_ARROW",44:"SOLID_ARROW",45:"DOTTED_ARROW",46:"SOLID_CROSS",47:"DOTTED_CROSS",48:"TXT"},
|
||||
productions_: [0,[3,2],[3,2],[3,2],[7,0],[7,2],[8,2],[8,1],[8,1],[9,5],[9,3],[9,2],[9,3],[9,3],[9,2],[9,3],[9,4],[9,4],[9,4],[9,4],[9,4],[27,1],[27,4],[25,1],[25,4],[17,4],[17,4],[34,2],[34,1],[33,3],[33,1],[31,1],[31,1],[14,5],[14,5],[14,4],[11,1],[38,1],[38,1],[38,1],[38,1],[38,1],[38,1],[19,1]],
|
||||
performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) {
|
||||
/* this == yyval */
|
||||
|
||||
@@ -121,11 +121,17 @@ case 16:
|
||||
break;
|
||||
case 17:
|
||||
|
||||
$$[$0-1].unshift({type: 'rectStart', color:$$[$0-2], signalType: yy.LINETYPE.RECT_START });
|
||||
$$[$0-1].push({type: 'rectEnd', color:$$[$0-2], signalType: yy.LINETYPE.RECT_END });
|
||||
this.$=$$[$0-1];
|
||||
break;
|
||||
case 18:
|
||||
|
||||
$$[$0-1].unshift({type: 'optStart', optText:$$[$0-2], signalType: yy.LINETYPE.OPT_START});
|
||||
$$[$0-1].push({type: 'optEnd', optText:$$[$0-2], signalType: yy.LINETYPE.OPT_END});
|
||||
this.$=$$[$0-1];
|
||||
break;
|
||||
case 18:
|
||||
case 19:
|
||||
|
||||
// Alt start
|
||||
$$[$0-1].unshift({type: 'altStart', altText:$$[$0-2], signalType: yy.LINETYPE.ALT_START});
|
||||
@@ -134,7 +140,7 @@ case 18:
|
||||
$$[$0-1].push({type: 'altEnd', signalType: yy.LINETYPE.ALT_END});
|
||||
this.$=$$[$0-1];
|
||||
break;
|
||||
case 19:
|
||||
case 20:
|
||||
|
||||
// Parallel start
|
||||
$$[$0-1].unshift({type: 'parStart', parText:$$[$0-2], signalType: yy.LINETYPE.PAR_START});
|
||||
@@ -143,17 +149,17 @@ case 19:
|
||||
$$[$0-1].push({type: 'parEnd', signalType: yy.LINETYPE.PAR_END});
|
||||
this.$=$$[$0-1];
|
||||
break;
|
||||
case 21:
|
||||
case 22:
|
||||
this.$ = $$[$0-3].concat([{type: 'and', parText:$$[$0-1], signalType: yy.LINETYPE.PAR_AND}, $$[$0]]);
|
||||
break;
|
||||
case 23:
|
||||
case 24:
|
||||
this.$ = $$[$0-3].concat([{type: 'else', altText:$$[$0-1], signalType: yy.LINETYPE.ALT_ELSE}, $$[$0]]);
|
||||
break;
|
||||
case 24:
|
||||
case 25:
|
||||
|
||||
this.$ = [$$[$0-1], {type:'addNote', placement:$$[$0-2], actor:$$[$0-1].actor, text:$$[$0]}];
|
||||
break;
|
||||
case 25:
|
||||
case 26:
|
||||
|
||||
// Coerce actor_pair into a [to, from, ...] array
|
||||
$$[$0-2] = [].concat($$[$0-1], $$[$0-1]).slice(0, 2);
|
||||
@@ -161,59 +167,59 @@ case 25:
|
||||
$$[$0-2][1] = $$[$0-2][1].actor;
|
||||
this.$ = [$$[$0-1], {type:'addNote', placement:yy.PLACEMENT.OVER, actor:$$[$0-2].slice(0, 2), text:$$[$0]}];
|
||||
break;
|
||||
case 28:
|
||||
case 29:
|
||||
this.$ = [$$[$0-2], $$[$0]];
|
||||
break;
|
||||
case 29:
|
||||
case 30:
|
||||
this.$ = $$[$0];
|
||||
break;
|
||||
case 30:
|
||||
case 31:
|
||||
this.$ = yy.PLACEMENT.LEFTOF;
|
||||
break;
|
||||
case 31:
|
||||
case 32:
|
||||
this.$ = yy.PLACEMENT.RIGHTOF;
|
||||
break;
|
||||
case 32:
|
||||
case 33:
|
||||
this.$ = [$$[$0-4],$$[$0-1],{type: 'addMessage', from:$$[$0-4].actor, to:$$[$0-1].actor, signalType:$$[$0-3], msg:$$[$0]},
|
||||
{type: 'activeStart', signalType: yy.LINETYPE.ACTIVE_START, actor: $$[$0-1]}
|
||||
]
|
||||
break;
|
||||
case 33:
|
||||
case 34:
|
||||
this.$ = [$$[$0-4],$$[$0-1],{type: 'addMessage', from:$$[$0-4].actor, to:$$[$0-1].actor, signalType:$$[$0-3], msg:$$[$0]},
|
||||
{type: 'activeEnd', signalType: yy.LINETYPE.ACTIVE_END, actor: $$[$0-4]}
|
||||
]
|
||||
break;
|
||||
case 34:
|
||||
case 35:
|
||||
this.$ = [$$[$0-3],$$[$0-1],{type: 'addMessage', from:$$[$0-3].actor, to:$$[$0-1].actor, signalType:$$[$0-2], msg:$$[$0]}]
|
||||
break;
|
||||
case 35:
|
||||
case 36:
|
||||
this.$={type: 'addActor', actor:$$[$0]}
|
||||
break;
|
||||
case 36:
|
||||
case 37:
|
||||
this.$ = yy.LINETYPE.SOLID_OPEN;
|
||||
break;
|
||||
case 37:
|
||||
case 38:
|
||||
this.$ = yy.LINETYPE.DOTTED_OPEN;
|
||||
break;
|
||||
case 38:
|
||||
case 39:
|
||||
this.$ = yy.LINETYPE.SOLID;
|
||||
break;
|
||||
case 39:
|
||||
case 40:
|
||||
this.$ = yy.LINETYPE.DOTTED;
|
||||
break;
|
||||
case 40:
|
||||
case 41:
|
||||
this.$ = yy.LINETYPE.SOLID_CROSS;
|
||||
break;
|
||||
case 41:
|
||||
case 42:
|
||||
this.$ = yy.LINETYPE.DOTTED_CROSS;
|
||||
break;
|
||||
case 42:
|
||||
case 43:
|
||||
this.$ = $$[$0].substring(1).trim().replace(/\\n/gm, "\n");
|
||||
break;
|
||||
}
|
||||
},
|
||||
table: [{3:1,4:$V0,5:$V1,6:$V2},{1:[3]},{3:5,4:$V0,5:$V1,6:$V2},{3:6,4:$V0,5:$V1,6:$V2},o([1,4,5,10,15,16,18,20,22,23,25,29,40],$V3,{7:7}),{1:[2,1]},{1:[2,2]},{1:[2,3],4:$V4,5:$V5,8:8,9:10,10:$V6,11:22,14:13,15:$V7,16:$V8,17:16,18:$V9,20:$Va,22:$Vb,23:$Vc,25:$Vd,29:$Ve,40:$Vf},o($Vg,[2,5]),{9:25,10:$V6,11:22,14:13,15:$V7,16:$V8,17:16,18:$V9,20:$Va,22:$Vb,23:$Vc,25:$Vd,29:$Ve,40:$Vf},o($Vg,[2,7]),o($Vg,[2,8]),{11:26,40:$Vf},{5:[1,27]},{11:28,40:$Vf},{11:29,40:$Vf},{5:[1,30]},{19:31,47:$Vh},{13:[1,33]},{13:[1,34]},{13:[1,35]},{13:[1,36]},{37:37,41:[1,38],42:[1,39],43:[1,40],44:[1,41],45:[1,42],46:[1,43]},{30:44,31:[1,45],35:[1,46],36:[1,47]},o([5,12,34,41,42,43,44,45,46,47],[2,35]),o($Vg,[2,6]),{5:[1,49],12:[1,48]},o($Vg,[2,11]),{5:[1,50]},{5:[1,51]},o($Vg,[2,14]),{5:[1,52]},{5:[2,42]},o($Vi,$V3,{7:53}),o($Vi,$V3,{7:54}),o($Vj,$V3,{24:55,7:56}),o($Vk,$V3,{26:57,7:58}),{11:61,38:[1,59],39:[1,60],40:$Vf},o($Vl,[2,36]),o($Vl,[2,37]),o($Vl,[2,38]),o($Vl,[2,39]),o($Vl,[2,40]),o($Vl,[2,41]),{11:62,40:$Vf},{11:64,32:63,40:$Vf},{40:[2,30]},{40:[2,31]},{13:[1,65]},o($Vg,[2,10]),o($Vg,[2,12]),o($Vg,[2,13]),o($Vg,[2,15]),{4:$V4,5:$V5,8:8,9:10,10:$V6,11:22,14:13,15:$V7,16:$V8,17:16,18:$V9,20:$Va,21:[1,66],22:$Vb,23:$Vc,25:$Vd,29:$Ve,40:$Vf},{4:$V4,5:$V5,8:8,9:10,10:$V6,11:22,14:13,15:$V7,16:$V8,17:16,18:$V9,20:$Va,21:[1,67],22:$Vb,23:$Vc,25:$Vd,29:$Ve,40:$Vf},{21:[1,68]},{4:$V4,5:$V5,8:8,9:10,10:$V6,11:22,14:13,15:$V7,16:$V8,17:16,18:$V9,20:$Va,21:[2,22],22:$Vb,23:$Vc,25:$Vd,28:[1,69],29:$Ve,40:$Vf},{21:[1,70]},{4:$V4,5:$V5,8:8,9:10,10:$V6,11:22,14:13,15:$V7,16:$V8,17:16,18:$V9,20:$Va,21:[2,20],22:$Vb,23:$Vc,25:$Vd,27:[1,71],29:$Ve,40:$Vf},{11:72,40:$Vf},{11:73,40:$Vf},{19:74,47:$Vh},{19:75,47:$Vh},{19:76,47:$Vh},{34:[1,77],47:[2,29]},{5:[1,78]},o($Vg,[2,16]),o($Vg,[2,17]),o($Vg,[2,18]),{13:[1,79]},o($Vg,[2,19]),{13:[1,80]},{19:81,47:$Vh},{19:82,47:$Vh},{5:[2,34]},{5:[2,24]},{5:[2,25]},{11:83,40:$Vf},o($Vg,[2,9]),o($Vj,$V3,{7:56,24:84}),o($Vk,$V3,{7:58,26:85}),{5:[2,32]},{5:[2,33]},{47:[2,28]},{21:[2,23]},{21:[2,21]}],
|
||||
defaultActions: {5:[2,1],6:[2,2],32:[2,42],46:[2,30],47:[2,31],74:[2,34],75:[2,24],76:[2,25],81:[2,32],82:[2,33],83:[2,28],84:[2,23],85:[2,21]},
|
||||
table: [{3:1,4:$V0,5:$V1,6:$V2},{1:[3]},{3:5,4:$V0,5:$V1,6:$V2},{3:6,4:$V0,5:$V1,6:$V2},o([1,4,5,10,15,16,18,20,22,23,24,26,30,41],$V3,{7:7}),{1:[2,1]},{1:[2,2]},{1:[2,3],4:$V4,5:$V5,8:8,9:10,10:$V6,11:23,14:13,15:$V7,16:$V8,17:16,18:$V9,20:$Va,22:$Vb,23:$Vc,24:$Vd,26:$Ve,30:$Vf,41:$Vg},o($Vh,[2,5]),{9:26,10:$V6,11:23,14:13,15:$V7,16:$V8,17:16,18:$V9,20:$Va,22:$Vb,23:$Vc,24:$Vd,26:$Ve,30:$Vf,41:$Vg},o($Vh,[2,7]),o($Vh,[2,8]),{11:27,41:$Vg},{5:[1,28]},{11:29,41:$Vg},{11:30,41:$Vg},{5:[1,31]},{19:32,48:$Vi},{13:[1,34]},{13:[1,35]},{13:[1,36]},{13:[1,37]},{13:[1,38]},{38:39,42:[1,40],43:[1,41],44:[1,42],45:[1,43],46:[1,44],47:[1,45]},{31:46,32:[1,47],36:[1,48],37:[1,49]},o([5,12,35,42,43,44,45,46,47,48],[2,36]),o($Vh,[2,6]),{5:[1,51],12:[1,50]},o($Vh,[2,11]),{5:[1,52]},{5:[1,53]},o($Vh,[2,14]),{5:[1,54]},{5:[2,43]},o($Vj,$V3,{7:55}),o($Vj,$V3,{7:56}),o($Vj,$V3,{7:57}),o($Vk,$V3,{25:58,7:59}),o($Vl,$V3,{27:60,7:61}),{11:64,39:[1,62],40:[1,63],41:$Vg},o($Vm,[2,37]),o($Vm,[2,38]),o($Vm,[2,39]),o($Vm,[2,40]),o($Vm,[2,41]),o($Vm,[2,42]),{11:65,41:$Vg},{11:67,33:66,41:$Vg},{41:[2,31]},{41:[2,32]},{13:[1,68]},o($Vh,[2,10]),o($Vh,[2,12]),o($Vh,[2,13]),o($Vh,[2,15]),{4:$V4,5:$V5,8:8,9:10,10:$V6,11:23,14:13,15:$V7,16:$V8,17:16,18:$V9,20:$Va,21:[1,69],22:$Vb,23:$Vc,24:$Vd,26:$Ve,30:$Vf,41:$Vg},{4:$V4,5:$V5,8:8,9:10,10:$V6,11:23,14:13,15:$V7,16:$V8,17:16,18:$V9,20:$Va,21:[1,70],22:$Vb,23:$Vc,24:$Vd,26:$Ve,30:$Vf,41:$Vg},{4:$V4,5:$V5,8:8,9:10,10:$V6,11:23,14:13,15:$V7,16:$V8,17:16,18:$V9,20:$Va,21:[1,71],22:$Vb,23:$Vc,24:$Vd,26:$Ve,30:$Vf,41:$Vg},{21:[1,72]},{4:$V4,5:$V5,8:8,9:10,10:$V6,11:23,14:13,15:$V7,16:$V8,17:16,18:$V9,20:$Va,21:[2,23],22:$Vb,23:$Vc,24:$Vd,26:$Ve,29:[1,73],30:$Vf,41:$Vg},{21:[1,74]},{4:$V4,5:$V5,8:8,9:10,10:$V6,11:23,14:13,15:$V7,16:$V8,17:16,18:$V9,20:$Va,21:[2,21],22:$Vb,23:$Vc,24:$Vd,26:$Ve,28:[1,75],30:$Vf,41:$Vg},{11:76,41:$Vg},{11:77,41:$Vg},{19:78,48:$Vi},{19:79,48:$Vi},{19:80,48:$Vi},{35:[1,81],48:[2,30]},{5:[1,82]},o($Vh,[2,16]),o($Vh,[2,17]),o($Vh,[2,18]),o($Vh,[2,19]),{13:[1,83]},o($Vh,[2,20]),{13:[1,84]},{19:85,48:$Vi},{19:86,48:$Vi},{5:[2,35]},{5:[2,25]},{5:[2,26]},{11:87,41:$Vg},o($Vh,[2,9]),o($Vk,$V3,{7:59,25:88}),o($Vl,$V3,{7:61,27:89}),{5:[2,33]},{5:[2,34]},{48:[2,29]},{21:[2,24]},{21:[2,22]}],
|
||||
defaultActions: {5:[2,1],6:[2,2],33:[2,43],48:[2,31],49:[2,32],78:[2,35],79:[2,25],80:[2,26],85:[2,33],86:[2,34],87:[2,29],88:[2,24],89:[2,22]},
|
||||
parseError: function parseError (str, hash) {
|
||||
if (hash.recoverable) {
|
||||
this.trace(str);
|
||||
@@ -252,15 +258,18 @@ parse: function parse(input) {
|
||||
vstack.length = vstack.length - n;
|
||||
lstack.length = lstack.length - n;
|
||||
}
|
||||
_token_stack:
|
||||
var lex = function () {
|
||||
function lex() {
|
||||
var token;
|
||||
token = lexer.lex() || EOF;
|
||||
token = tstack.pop() || lexer.lex() || EOF;
|
||||
if (typeof token !== 'number') {
|
||||
if (token instanceof Array) {
|
||||
tstack = token;
|
||||
token = tstack.pop();
|
||||
}
|
||||
token = self.symbols_[token] || token;
|
||||
}
|
||||
return token;
|
||||
};
|
||||
}
|
||||
var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected;
|
||||
while (true) {
|
||||
state = stack[stack.length - 1];
|
||||
@@ -272,27 +281,27 @@ parse: function parse(input) {
|
||||
}
|
||||
action = table[state] && table[state][symbol];
|
||||
}
|
||||
if (typeof action === 'undefined' || !action.length || !action[0]) {
|
||||
var errStr = '';
|
||||
expected = [];
|
||||
for (p in table[state]) {
|
||||
if (this.terminals_[p] && p > TERROR) {
|
||||
expected.push('\'' + this.terminals_[p] + '\'');
|
||||
}
|
||||
if (typeof action === 'undefined' || !action.length || !action[0]) {
|
||||
var errStr = '';
|
||||
expected = [];
|
||||
for (p in table[state]) {
|
||||
if (this.terminals_[p] && p > TERROR) {
|
||||
expected.push('\'' + this.terminals_[p] + '\'');
|
||||
}
|
||||
if (lexer.showPosition) {
|
||||
errStr = 'Parse error on line ' + (yylineno + 1) + ':\n' + lexer.showPosition() + '\nExpecting ' + expected.join(', ') + ', got \'' + (this.terminals_[symbol] || symbol) + '\'';
|
||||
} else {
|
||||
errStr = 'Parse error on line ' + (yylineno + 1) + ': Unexpected ' + (symbol == EOF ? 'end of input' : '\'' + (this.terminals_[symbol] || symbol) + '\'');
|
||||
}
|
||||
this.parseError(errStr, {
|
||||
text: lexer.match,
|
||||
token: this.terminals_[symbol] || symbol,
|
||||
line: lexer.yylineno,
|
||||
loc: yyloc,
|
||||
expected: expected
|
||||
});
|
||||
}
|
||||
if (lexer.showPosition) {
|
||||
errStr = 'Parse error on line ' + (yylineno + 1) + ':\n' + lexer.showPosition() + '\nExpecting ' + expected.join(', ') + ', got \'' + (this.terminals_[symbol] || symbol) + '\'';
|
||||
} else {
|
||||
errStr = 'Parse error on line ' + (yylineno + 1) + ': Unexpected ' + (symbol == EOF ? 'end of input' : '\'' + (this.terminals_[symbol] || symbol) + '\'');
|
||||
}
|
||||
this.parseError(errStr, {
|
||||
text: lexer.match,
|
||||
token: this.terminals_[symbol] || symbol,
|
||||
line: lexer.yylineno,
|
||||
loc: yyloc,
|
||||
expected: expected
|
||||
});
|
||||
}
|
||||
if (action[0] instanceof Array && action.length > 1) {
|
||||
throw new Error('Parse Error: multiple actions possible at state: ' + state + ', token: ' + symbol);
|
||||
}
|
||||
@@ -701,7 +710,7 @@ case 4:/* skip comments */
|
||||
break;
|
||||
case 5: this.begin('ID'); return 10;
|
||||
break;
|
||||
case 6: yy_.yytext = yy_.yytext.trim(); this.begin('ALIAS'); return 40;
|
||||
case 6: yy_.yytext = yy_.yytext.trim(); this.begin('ALIAS'); return 41;
|
||||
break;
|
||||
case 7: this.popState(); this.popState(); this.begin('LINE'); return 12;
|
||||
break;
|
||||
@@ -713,64 +722,66 @@ case 10: this.begin('LINE'); return 22;
|
||||
break;
|
||||
case 11: this.begin('LINE'); return 23;
|
||||
break;
|
||||
case 12: this.begin('LINE'); return 28;
|
||||
case 12: this.begin('LINE'); return 24;
|
||||
break;
|
||||
case 13: this.begin('LINE'); return 25;
|
||||
case 13: this.begin('LINE'); return 29;
|
||||
break;
|
||||
case 14: this.begin('LINE'); return 27;
|
||||
case 14: this.begin('LINE'); return 26;
|
||||
break;
|
||||
case 15: this.popState(); return 13;
|
||||
case 15: this.begin('LINE'); return 28;
|
||||
break;
|
||||
case 16:return 21;
|
||||
case 16: this.popState(); return 13;
|
||||
break;
|
||||
case 17:return 35;
|
||||
case 17:return 21;
|
||||
break;
|
||||
case 18:return 36;
|
||||
break;
|
||||
case 19:return 31;
|
||||
case 19:return 37;
|
||||
break;
|
||||
case 20:return 29;
|
||||
case 20:return 32;
|
||||
break;
|
||||
case 21: this.begin('ID'); return 15;
|
||||
case 21:return 30;
|
||||
break;
|
||||
case 22: this.begin('ID'); return 16;
|
||||
case 22: this.begin('ID'); return 15;
|
||||
break;
|
||||
case 23:return 18;
|
||||
case 23: this.begin('ID'); return 16;
|
||||
break;
|
||||
case 24:return 6;
|
||||
case 24:return 18;
|
||||
break;
|
||||
case 25:return 34;
|
||||
case 25:return 6;
|
||||
break;
|
||||
case 26:return 5;
|
||||
case 26:return 35;
|
||||
break;
|
||||
case 27: yy_.yytext = yy_.yytext.trim(); return 40;
|
||||
case 27:return 5;
|
||||
break;
|
||||
case 28:return 43;
|
||||
case 28: yy_.yytext = yy_.yytext.trim(); return 41;
|
||||
break;
|
||||
case 29:return 44;
|
||||
break;
|
||||
case 30:return 41;
|
||||
case 30:return 45;
|
||||
break;
|
||||
case 31:return 42;
|
||||
break;
|
||||
case 32:return 45;
|
||||
case 32:return 43;
|
||||
break;
|
||||
case 33:return 46;
|
||||
break;
|
||||
case 34:return 47;
|
||||
break;
|
||||
case 35:return 38;
|
||||
case 35:return 48;
|
||||
break;
|
||||
case 36:return 39;
|
||||
break;
|
||||
case 37:return 5;
|
||||
case 37:return 40;
|
||||
break;
|
||||
case 38:return 'INVALID';
|
||||
case 38:return 5;
|
||||
break;
|
||||
case 39:return 'INVALID';
|
||||
break;
|
||||
}
|
||||
},
|
||||
rules: [/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:((?!\n)\s)+)/i,/^(?:#[^\n]*)/i,/^(?:%[^\n]*)/i,/^(?:participant\b)/i,/^(?:[^\->:\n,;]+?(?=((?!\n)\s)+as(?!\n)\s|[#\n;]|$))/i,/^(?:as\b)/i,/^(?:(?:))/i,/^(?:loop\b)/i,/^(?:opt\b)/i,/^(?:alt\b)/i,/^(?:else\b)/i,/^(?:par\b)/i,/^(?:and\b)/i,/^(?:[^#\n;]*)/i,/^(?:end\b)/i,/^(?:left of\b)/i,/^(?:right of\b)/i,/^(?:over\b)/i,/^(?:note\b)/i,/^(?:activate\b)/i,/^(?:deactivate\b)/i,/^(?:title\b)/i,/^(?:sequenceDiagram\b)/i,/^(?:,)/i,/^(?:;)/i,/^(?:[^\+\->:\n,;]+)/i,/^(?:->>)/i,/^(?:-->>)/i,/^(?:->)/i,/^(?:-->)/i,/^(?:-[x])/i,/^(?:--[x])/i,/^(?::[^#\n;]+)/i,/^(?:\+)/i,/^(?:-)/i,/^(?:$)/i,/^(?:.)/i],
|
||||
conditions: {"LINE":{"rules":[2,3,15],"inclusive":false},"ALIAS":{"rules":[2,3,7,8],"inclusive":false},"ID":{"rules":[2,3,6],"inclusive":false},"INITIAL":{"rules":[0,1,3,4,5,9,10,11,12,13,14,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38],"inclusive":true}}
|
||||
rules: [/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:((?!\n)\s)+)/i,/^(?:#[^\n]*)/i,/^(?:%[^\n]*)/i,/^(?:participant\b)/i,/^(?:[^\->:\n,;]+?(?=((?!\n)\s)+as(?!\n)\s|[#\n;]|$))/i,/^(?:as\b)/i,/^(?:(?:))/i,/^(?:loop\b)/i,/^(?:rect\b)/i,/^(?:opt\b)/i,/^(?:alt\b)/i,/^(?:else\b)/i,/^(?:par\b)/i,/^(?:and\b)/i,/^(?:[^#\n;]*)/i,/^(?:end\b)/i,/^(?:left of\b)/i,/^(?:right of\b)/i,/^(?:over\b)/i,/^(?:note\b)/i,/^(?:activate\b)/i,/^(?:deactivate\b)/i,/^(?:title\b)/i,/^(?:sequenceDiagram\b)/i,/^(?:,)/i,/^(?:;)/i,/^(?:[^\+\->:\n,;]+)/i,/^(?:->>)/i,/^(?:-->>)/i,/^(?:->)/i,/^(?:-->)/i,/^(?:-[x])/i,/^(?:--[x])/i,/^(?::[^#\n;]+)/i,/^(?:\+)/i,/^(?:-)/i,/^(?:$)/i,/^(?:.)/i],
|
||||
conditions: {"LINE":{"rules":[2,3,16],"inclusive":false},"ALIAS":{"rules":[2,3,7,8],"inclusive":false},"ID":{"rules":[2,3,6],"inclusive":false},"INITIAL":{"rules":[0,1,3,4,5,9,10,11,12,13,14,15,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39],"inclusive":true}}
|
||||
});
|
||||
return lexer;
|
||||
})();
|
||||
@@ -784,9 +795,9 @@ return new Parser;
|
||||
|
||||
|
||||
if (typeof require !== 'undefined' && typeof exports !== 'undefined') {
|
||||
exports.parser = sequenceDiagram;
|
||||
exports.Parser = sequenceDiagram.Parser;
|
||||
exports.parse = function () { return sequenceDiagram.parse.apply(sequenceDiagram, arguments); };
|
||||
exports.parser = parser;
|
||||
exports.Parser = parser.Parser;
|
||||
exports.parse = function () { return parser.parse.apply(parser, arguments); };
|
||||
exports.main = function commonjsMain (args) {
|
||||
if (!args[1]) {
|
||||
console.log('Usage: '+args[0]+' FILE');
|
||||
|
@@ -66,7 +66,9 @@ export const LINETYPE = {
|
||||
ACTIVE_END: 18,
|
||||
PAR_START: 19,
|
||||
PAR_AND: 20,
|
||||
PAR_END: 21
|
||||
PAR_END: 21,
|
||||
RECT_START: 22,
|
||||
RECT_END: 23
|
||||
}
|
||||
|
||||
export const ARROWTYPE = {
|
||||
@@ -122,6 +124,12 @@ export const apply = function (param) {
|
||||
case 'loopEnd':
|
||||
addSignal(undefined, undefined, undefined, param.signalType)
|
||||
break
|
||||
case 'rectStart':
|
||||
addSignal(undefined, undefined, param.color, param.signalType)
|
||||
break
|
||||
case 'rectEnd':
|
||||
addSignal(undefined, undefined, undefined, param.signalType)
|
||||
break
|
||||
case 'optStart':
|
||||
addSignal(undefined, undefined, param.optText, param.signalType)
|
||||
break
|
||||
|
@@ -369,6 +369,57 @@ describe('when parsing a sequenceDiagram', function () {
|
||||
expect(messages[0].from).toBe('Alice')
|
||||
expect(messages[1].from).toBe('Bob')
|
||||
})
|
||||
it('it should add a rect around sequence', function () {
|
||||
const str = `
|
||||
sequenceDiagram
|
||||
Alice->Bob: Hello Bob, how are you?
|
||||
%% Comment
|
||||
rect rgb(200, 255, 200)
|
||||
Note right of Bob: Bob thinks
|
||||
Bob-->Alice: I am good thanks
|
||||
end
|
||||
`
|
||||
|
||||
parser.parse(str)
|
||||
const actors = parser.yy.getActors()
|
||||
expect(actors.Alice.description).toBe('Alice')
|
||||
actors.Bob.description = 'Bob'
|
||||
|
||||
const messages = parser.yy.getMessages()
|
||||
expect(messages[1].type).toEqual(parser.yy.LINETYPE.RECT_START)
|
||||
expect(messages[1].message).toBe('rgb(200, 255, 200)')
|
||||
expect(messages[2].type).toEqual(parser.yy.LINETYPE.NOTE)
|
||||
expect(messages[3].type).toEqual(parser.yy.LINETYPE.DOTTED_OPEN)
|
||||
expect(messages[4].type).toEqual(parser.yy.LINETYPE.RECT_END)
|
||||
})
|
||||
|
||||
it('it should allow for nested rects', function () {
|
||||
const str = `
|
||||
sequenceDiagram
|
||||
Alice->Bob: Hello Bob, how are you?
|
||||
%% Comment
|
||||
rect rgb(200, 255, 200)
|
||||
rect rgb(0, 0, 0)
|
||||
Note right of Bob: Bob thinks
|
||||
end
|
||||
Bob-->Alice: I am good thanks
|
||||
end
|
||||
`
|
||||
parser.parse(str)
|
||||
const actors = parser.yy.getActors()
|
||||
expect(actors.Alice.description).toBe('Alice')
|
||||
actors.Bob.description = 'Bob'
|
||||
|
||||
const messages = parser.yy.getMessages()
|
||||
expect(messages[1].type).toEqual(parser.yy.LINETYPE.RECT_START)
|
||||
expect(messages[1].message).toBe('rgb(200, 255, 200)')
|
||||
expect(messages[2].type).toEqual(parser.yy.LINETYPE.RECT_START)
|
||||
expect(messages[2].message).toBe('rgb(0, 0, 0)')
|
||||
expect(messages[3].type).toEqual(parser.yy.LINETYPE.NOTE)
|
||||
expect(messages[4].type).toEqual(parser.yy.LINETYPE.RECT_END)
|
||||
expect(messages[5].type).toEqual(parser.yy.LINETYPE.DOTTED_OPEN)
|
||||
expect(messages[6].type).toEqual(parser.yy.LINETYPE.RECT_END)
|
||||
})
|
||||
it('it should handle opt statements', function () {
|
||||
const str = 'sequenceDiagram\n' +
|
||||
'Alice->Bob: Hello Bob, how are you?\n\n' +
|
||||
@@ -929,6 +980,24 @@ describe('when rendering a sequenceDiagram', function () {
|
||||
expect(bounds.stopx).toBe(0 + conf.width * 2 + conf.actorMargin)
|
||||
expect(bounds.stopy).toBe(0 + 2 * conf.messageMargin + conf.height + 3 * conf.boxMargin + conf.boxTextMargin)
|
||||
})
|
||||
it('it should draw background rect', function () {
|
||||
renderer.bounds.init()
|
||||
const str = `
|
||||
sequenceDiagram
|
||||
Alice->Bob: Hello Bob, are you alright?
|
||||
rect rgb(0, 0, 0)
|
||||
Bob->Alice: I feel surrounded by darkness
|
||||
end
|
||||
`
|
||||
parser.parse(str)
|
||||
renderer.draw(str, 'tst')
|
||||
const bounds = renderer.bounds.getBounds()
|
||||
expect(bounds.startx).toBe(0)
|
||||
expect(bounds.starty).toBe(0)
|
||||
|
||||
expect(bounds.stopx).toBe(0 + conf.width * 2 + conf.actorMargin)
|
||||
expect(bounds.stopy).toBe(0 + 2 * conf.messageMargin + conf.height + 3 * conf.boxMargin)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when rendering a sequenceDiagram with actor mirror activated', function () {
|
||||
|
@@ -131,8 +131,8 @@ export const bounds = {
|
||||
const activation = this.activations.splice(lastActorActivationIdx, 1)[0]
|
||||
return activation
|
||||
},
|
||||
newLoop: function (title) {
|
||||
this.sequenceItems.push({ startx: undefined, starty: this.verticalPos, stopx: undefined, stopy: undefined, title: title })
|
||||
newLoop: function (title, fill) {
|
||||
this.sequenceItems.push({ startx: undefined, starty: this.verticalPos, stopx: undefined, stopy: undefined, title: title, fill: fill })
|
||||
},
|
||||
endLoop: function () {
|
||||
const loop = this.sequenceItems.pop()
|
||||
@@ -410,6 +410,16 @@ export const draw = function (text, id) {
|
||||
svgDraw.drawLoop(diagram, loopData, 'loop', conf)
|
||||
bounds.bumpVerticalPos(conf.boxMargin)
|
||||
break
|
||||
case parser.yy.LINETYPE.RECT_START:
|
||||
bounds.bumpVerticalPos(conf.boxMargin)
|
||||
bounds.newLoop(undefined, msg.message)
|
||||
bounds.bumpVerticalPos(conf.boxMargin)
|
||||
break
|
||||
case parser.yy.LINETYPE.RECT_END:
|
||||
const rectData = bounds.endLoop()
|
||||
svgDraw.drawBackgroundRect(diagram, rectData)
|
||||
bounds.bumpVerticalPos(conf.boxMargin)
|
||||
break
|
||||
case parser.yy.LINETYPE.OPT_START:
|
||||
bounds.bumpVerticalPos(conf.boxMargin)
|
||||
bounds.newLoop(msg.message)
|
||||
|
@@ -167,6 +167,21 @@ export const drawLoop = function (elem, bounds, labelText, conf) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a background rectangle
|
||||
* @param color - The fill color for the background
|
||||
*/
|
||||
export const drawBackgroundRect = function (elem, bounds) {
|
||||
const rectElem = drawRect(elem, {
|
||||
x: bounds.startx,
|
||||
y: bounds.starty,
|
||||
width: bounds.stopx - bounds.startx,
|
||||
height: bounds.stopy - bounds.starty,
|
||||
fill: bounds.fill,
|
||||
class: 'rect'
|
||||
})
|
||||
rectElem.lower()
|
||||
}
|
||||
/**
|
||||
* Setup arrow head and define the marker. The result is appended to the svg.
|
||||
*/
|
||||
@@ -331,6 +346,7 @@ export default {
|
||||
anchorElement,
|
||||
drawActivation,
|
||||
drawLoop,
|
||||
drawBackgroundRect,
|
||||
insertArrowHead,
|
||||
insertSequenceNumber,
|
||||
insertArrowCrossHead,
|
||||
|
76
src/diagrams/sequence/svgDraw.spec.js
Normal file
76
src/diagrams/sequence/svgDraw.spec.js
Normal file
@@ -0,0 +1,76 @@
|
||||
/* eslint-env jasmine */
|
||||
const svgDraw = require('./svgDraw')
|
||||
const { MockD3 } = require('d3')
|
||||
|
||||
describe('svgDraw', function () {
|
||||
describe('drawRect', function () {
|
||||
it('it should append a rectangle', function () {
|
||||
const svg = MockD3('svg')
|
||||
svgDraw.drawRect(svg, {
|
||||
x: 10,
|
||||
y: 10,
|
||||
fill: '#ccc',
|
||||
stroke: 'red',
|
||||
width: '20',
|
||||
height: '20',
|
||||
rx: '10',
|
||||
ry: '10',
|
||||
class: 'unitTestRectangleClass'
|
||||
})
|
||||
expect(svg.__children.length).toBe(1)
|
||||
const rect = svg.__children[0]
|
||||
expect(rect.__name).toBe('rect')
|
||||
expect(rect.attr).toHaveBeenCalledWith('x', 10)
|
||||
expect(rect.attr).toHaveBeenCalledWith('y', 10)
|
||||
expect(rect.attr).toHaveBeenCalledWith('fill', '#ccc')
|
||||
expect(rect.attr).toHaveBeenCalledWith('stroke', 'red')
|
||||
expect(rect.attr).toHaveBeenCalledWith('width', '20')
|
||||
expect(rect.attr).toHaveBeenCalledWith('height', '20')
|
||||
expect(rect.attr).toHaveBeenCalledWith('rx', '10')
|
||||
expect(rect.attr).toHaveBeenCalledWith('ry', '10')
|
||||
expect(rect.attr).toHaveBeenCalledWith('class', 'unitTestRectangleClass')
|
||||
})
|
||||
it('it should not add the class attribute if a class isn`t provided', () => {
|
||||
const svg = MockD3('svg')
|
||||
svgDraw.drawRect(svg, {
|
||||
x: 10,
|
||||
y: 10,
|
||||
fill: '#ccc',
|
||||
stroke: 'red',
|
||||
width: '20',
|
||||
height: '20',
|
||||
rx: '10',
|
||||
ry: '10'
|
||||
})
|
||||
expect(svg.__children.length).toBe(1)
|
||||
const rect = svg.__children[0]
|
||||
expect(rect.__name).toBe('rect')
|
||||
expect(rect.attr).toHaveBeenCalledWith('fill', '#ccc')
|
||||
expect(rect.attr).not.toHaveBeenCalledWith('class', expect.anything())
|
||||
})
|
||||
})
|
||||
describe('drawBackgroundRect', function () {
|
||||
it('it should append a rect before the previous element within a given bound', function () {
|
||||
const svg = MockD3('svg')
|
||||
const boundingRect = {
|
||||
startx: 50,
|
||||
starty: 200,
|
||||
stopx: 150,
|
||||
stopy: 260,
|
||||
title: undefined,
|
||||
fill: '#ccc'
|
||||
}
|
||||
svgDraw.drawBackgroundRect(svg, boundingRect)
|
||||
expect(svg.__children.length).toBe(1)
|
||||
const rect = svg.__children[0]
|
||||
expect(rect.__name).toBe('rect')
|
||||
expect(rect.attr).toHaveBeenCalledWith('x', 50)
|
||||
expect(rect.attr).toHaveBeenCalledWith('y', 200)
|
||||
expect(rect.attr).toHaveBeenCalledWith('width', 100)
|
||||
expect(rect.attr).toHaveBeenCalledWith('height', 60)
|
||||
expect(rect.attr).toHaveBeenCalledWith('fill', '#ccc')
|
||||
expect(rect.attr).toHaveBeenCalledWith('class', 'rect')
|
||||
expect(rect.lower).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
})
|
@@ -3,6 +3,10 @@
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.label text {
|
||||
fill: #333;
|
||||
}
|
||||
|
||||
.node rect,
|
||||
.node circle,
|
||||
.node ellipse,
|
||||
|
@@ -1288,6 +1288,11 @@
|
||||
lodash "^4.17.11"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@braintree/sanitize-url@^3.1.0":
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@braintree/sanitize-url/-/sanitize-url-3.1.0.tgz#8ff71d51053cd5ee4981e5a501d80a536244f7fd"
|
||||
integrity sha512-GcIY79elgB+azP74j8vqkiXz8xLFfIzbQJdlwOPisgbKT00tviJQuEghOXSMVxJ00HoYJbGswr4kcllUc4xCcg==
|
||||
|
||||
"@types/events@*":
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types%2fevents/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7"
|
||||
|
Reference in New Issue
Block a user