Add support for aliases, and fix various issues when using the same agent multiple times in a statement [#19]
This commit is contained in:
parent
4384afdd03
commit
ddb4430ed2
13
README.md
13
README.md
|
@ -150,6 +150,19 @@ terminators bar
|
||||||
# (options are: box, bar, cross, none)
|
# (options are: box, bar, cross, none)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Agent Aliases
|
||||||
|
|
||||||
|
<img src="screenshots/AgentAliases.png" alt="Agent Aliases preview" width="200" align="right" />
|
||||||
|
|
||||||
|
```
|
||||||
|
define My complicated agent name as A
|
||||||
|
define "Another agent name,
|
||||||
|
and this one's multi-line!" as B
|
||||||
|
|
||||||
|
A -> B: this is much easier
|
||||||
|
A <- B: than writing the whole name
|
||||||
|
```
|
||||||
|
|
||||||
### Alternative Agent Ordering
|
### Alternative Agent Ordering
|
||||||
|
|
||||||
<img src="screenshots/AlternativeAgentOrdering.png" alt="Alternative Agent Ordering preview" width="150" align="right" />
|
<img src="screenshots/AlternativeAgentOrdering.png" alt="Alternative Agent Ordering preview" width="150" align="right" />
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
|
@ -1,183 +1,195 @@
|
||||||
define(['core/ArrayUtilities'], (array) => {
|
define(['core/ArrayUtilities'], (array) => {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const CM_END = {type: '', suggest: '\n', then: {}};
|
|
||||||
const CM_HIDDEN_END = {type: '', then: {}};
|
|
||||||
const CM_ERROR = {type: 'error line-error', then: {'': 0}};
|
const CM_ERROR = {type: 'error line-error', then: {'': 0}};
|
||||||
|
|
||||||
function makeCMCommaBlock(type, suggest, exits = {}) {
|
const CM_COMMANDS = ((() => {
|
||||||
return {type, suggest, then: Object.assign({
|
const end = {type: '', suggest: '\n', then: {}};
|
||||||
|
const hiddenEnd = {type: '', then: {}};
|
||||||
|
|
||||||
|
const ARROWS = [
|
||||||
|
'->', '-->',
|
||||||
|
'<-', '<--',
|
||||||
|
'<->', '<-->',
|
||||||
|
];
|
||||||
|
|
||||||
|
const textToEnd = {type: 'string', then: {'': 0, '\n': end}};
|
||||||
|
const aliasListToEnd = {type: 'variable', suggest: 'Agent', then: {
|
||||||
'': 0,
|
'': 0,
|
||||||
',': {type: 'operator', suggest: true, then: {
|
'as': {type: 'keyword', suggest: true, then: {
|
||||||
'': 1,
|
'': {type: 'variable', suggest: 'Agent', then: {
|
||||||
|
'': 0,
|
||||||
|
',': {type: 'operator', suggest: true, then: {'': 3}},
|
||||||
|
'\n': end,
|
||||||
|
}},
|
||||||
}},
|
}},
|
||||||
}, exits)};
|
',': {type: 'operator', suggest: true, then: {'': 1}},
|
||||||
}
|
'\n': end,
|
||||||
|
|
||||||
const CM_TEXT_TO_END = {type: 'string', then: {'': 0, '\n': CM_END}};
|
|
||||||
const CM_AGENT_LIST_TO_END = makeCMCommaBlock('variable', 'Agent', {
|
|
||||||
'\n': CM_END,
|
|
||||||
});
|
|
||||||
const CM_AGENT_LIST_TO_TEXT = makeCMCommaBlock('variable', 'Agent', {
|
|
||||||
':': {type: 'operator', suggest: true, then: {'': CM_TEXT_TO_END}},
|
|
||||||
});
|
|
||||||
const CM_AGENT_TO_OPTTEXT = {type: 'variable', suggest: 'Agent', then: {
|
|
||||||
'': 0,
|
|
||||||
':': {type: 'operator', suggest: true, then: {
|
|
||||||
'': CM_TEXT_TO_END,
|
|
||||||
'\n': CM_HIDDEN_END,
|
|
||||||
}},
|
|
||||||
'\n': CM_END,
|
|
||||||
}};
|
|
||||||
|
|
||||||
function makeCMSideNote(side) {
|
|
||||||
return {
|
|
||||||
type: 'keyword',
|
|
||||||
suggest: [side + ' of ', side + ': '],
|
|
||||||
then: {
|
|
||||||
'of': {type: 'keyword', suggest: true, then: {
|
|
||||||
'': CM_AGENT_LIST_TO_TEXT,
|
|
||||||
}},
|
|
||||||
':': {type: 'operator', suggest: true, then: {
|
|
||||||
'': CM_TEXT_TO_END,
|
|
||||||
}},
|
|
||||||
'': CM_AGENT_LIST_TO_TEXT,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function makeCMOperatorBlock(exit) {
|
|
||||||
const op = {type: 'operator', suggest: true, then: {
|
|
||||||
'+': CM_ERROR,
|
|
||||||
'-': CM_ERROR,
|
|
||||||
'*': CM_ERROR,
|
|
||||||
'!': CM_ERROR,
|
|
||||||
'': exit,
|
|
||||||
}};
|
}};
|
||||||
return {
|
const agentListToEnd = {type: 'variable', suggest: 'Agent', then: {
|
||||||
'+': {type: 'operator', suggest: true, then: {
|
'': 0,
|
||||||
|
',': {type: 'operator', suggest: true, then: {'': 1}},
|
||||||
|
':': {type: 'operator', suggest: true, then: {'': textToEnd}},
|
||||||
|
}};
|
||||||
|
const agentToOptText = {type: 'variable', suggest: 'Agent', then: {
|
||||||
|
'': 0,
|
||||||
|
':': {type: 'operator', suggest: true, then: {
|
||||||
|
'': textToEnd,
|
||||||
|
'\n': hiddenEnd,
|
||||||
|
}},
|
||||||
|
'\n': end,
|
||||||
|
}};
|
||||||
|
|
||||||
|
function makeSideNote(side) {
|
||||||
|
return {
|
||||||
|
type: 'keyword',
|
||||||
|
suggest: [side + ' of ', side + ': '],
|
||||||
|
then: {
|
||||||
|
'of': {type: 'keyword', suggest: true, then: {
|
||||||
|
'': agentListToEnd,
|
||||||
|
}},
|
||||||
|
':': {type: 'operator', suggest: true, then: {
|
||||||
|
'': textToEnd,
|
||||||
|
}},
|
||||||
|
'': agentListToEnd,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeOpBlock(exit) {
|
||||||
|
const op = {type: 'operator', suggest: true, then: {
|
||||||
'+': CM_ERROR,
|
'+': CM_ERROR,
|
||||||
'-': CM_ERROR,
|
'-': CM_ERROR,
|
||||||
'*': op,
|
'*': CM_ERROR,
|
||||||
'!': CM_ERROR,
|
'!': CM_ERROR,
|
||||||
'': exit,
|
'': exit,
|
||||||
}},
|
}};
|
||||||
'-': {type: 'operator', suggest: true, then: {
|
return {
|
||||||
'+': CM_ERROR,
|
'+': {type: 'operator', suggest: true, then: {
|
||||||
'-': CM_ERROR,
|
|
||||||
'*': op,
|
|
||||||
'!': {type: 'operator', then: {
|
|
||||||
'+': CM_ERROR,
|
'+': CM_ERROR,
|
||||||
'-': CM_ERROR,
|
'-': CM_ERROR,
|
||||||
|
'*': op,
|
||||||
|
'!': CM_ERROR,
|
||||||
|
'': exit,
|
||||||
|
}},
|
||||||
|
'-': {type: 'operator', suggest: true, then: {
|
||||||
|
'+': CM_ERROR,
|
||||||
|
'-': CM_ERROR,
|
||||||
|
'*': op,
|
||||||
|
'!': {type: 'operator', then: {
|
||||||
|
'+': CM_ERROR,
|
||||||
|
'-': CM_ERROR,
|
||||||
|
'*': CM_ERROR,
|
||||||
|
'!': CM_ERROR,
|
||||||
|
'': exit,
|
||||||
|
}},
|
||||||
|
'': exit,
|
||||||
|
}},
|
||||||
|
'*': {type: 'operator', suggest: true, then: {
|
||||||
|
'+': op,
|
||||||
|
'-': op,
|
||||||
'*': CM_ERROR,
|
'*': CM_ERROR,
|
||||||
'!': CM_ERROR,
|
'!': CM_ERROR,
|
||||||
'': exit,
|
'': exit,
|
||||||
}},
|
}},
|
||||||
|
'!': op,
|
||||||
'': exit,
|
'': exit,
|
||||||
}},
|
};
|
||||||
'*': {type: 'operator', suggest: true, then: {
|
}
|
||||||
'+': op,
|
|
||||||
'-': op,
|
|
||||||
'*': CM_ERROR,
|
|
||||||
'!': CM_ERROR,
|
|
||||||
'': exit,
|
|
||||||
}},
|
|
||||||
'!': op,
|
|
||||||
'': exit,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function makeCMConnect() {
|
function makeCMConnect() {
|
||||||
const connect = {
|
const connect = {
|
||||||
type: 'keyword',
|
type: 'keyword',
|
||||||
suggest: true,
|
suggest: true,
|
||||||
then: makeCMOperatorBlock(CM_AGENT_TO_OPTTEXT),
|
then: makeOpBlock(agentToOptText),
|
||||||
};
|
};
|
||||||
|
|
||||||
return makeCMOperatorBlock({type: 'variable', suggest: 'Agent', then: {
|
const then = {
|
||||||
'->': connect,
|
':': {
|
||||||
'-->': connect,
|
type: 'operator',
|
||||||
'<-': connect,
|
suggest: true,
|
||||||
'<--': connect,
|
override: 'Label',
|
||||||
'<->': connect,
|
then: {},
|
||||||
'<-->': connect,
|
},
|
||||||
':': {type: 'operator', suggest: true, override: 'Label', then: {}},
|
'': 0,
|
||||||
'': 0,
|
};
|
||||||
}});
|
ARROWS.forEach((arrow) => (then[arrow] = connect));
|
||||||
}
|
return makeOpBlock({type: 'variable', suggest: 'Agent', then});
|
||||||
|
}
|
||||||
|
|
||||||
const CM_COMMANDS = {type: 'error line-error', then: Object.assign({
|
return {type: 'error line-error', then: Object.assign({
|
||||||
'title': {type: 'keyword', suggest: true, then: {
|
'title': {type: 'keyword', suggest: true, then: {
|
||||||
'': CM_TEXT_TO_END,
|
'': textToEnd,
|
||||||
}},
|
|
||||||
'terminators': {type: 'keyword', suggest: true, then: {
|
|
||||||
'none': {type: 'keyword', suggest: true, then: {}},
|
|
||||||
'cross': {type: 'keyword', suggest: true, then: {}},
|
|
||||||
'box': {type: 'keyword', suggest: true, then: {}},
|
|
||||||
'bar': {type: 'keyword', suggest: true, then: {}},
|
|
||||||
}},
|
|
||||||
'define': {type: 'keyword', suggest: true, then: {
|
|
||||||
'': CM_AGENT_LIST_TO_END,
|
|
||||||
}},
|
|
||||||
'begin': {type: 'keyword', suggest: true, then: {
|
|
||||||
'': CM_AGENT_LIST_TO_END,
|
|
||||||
}},
|
|
||||||
'end': {type: 'keyword', suggest: true, then: {
|
|
||||||
'': CM_AGENT_LIST_TO_END,
|
|
||||||
'\n': CM_END,
|
|
||||||
}},
|
|
||||||
'if': {type: 'keyword', suggest: true, then: {
|
|
||||||
'': CM_TEXT_TO_END,
|
|
||||||
':': {type: 'operator', suggest: true, then: {
|
|
||||||
'': CM_TEXT_TO_END,
|
|
||||||
}},
|
}},
|
||||||
'\n': CM_END,
|
'terminators': {type: 'keyword', suggest: true, then: {
|
||||||
}},
|
'none': {type: 'keyword', suggest: true, then: {}},
|
||||||
'else': {type: 'keyword', suggest: ['else\n', 'else if: '], then: {
|
'cross': {type: 'keyword', suggest: true, then: {}},
|
||||||
'if': {type: 'keyword', suggest: 'if: ', then: {
|
'box': {type: 'keyword', suggest: true, then: {}},
|
||||||
'': CM_TEXT_TO_END,
|
'bar': {type: 'keyword', suggest: true, then: {}},
|
||||||
|
}},
|
||||||
|
'define': {type: 'keyword', suggest: true, then: {
|
||||||
|
'': aliasListToEnd,
|
||||||
|
}},
|
||||||
|
'begin': {type: 'keyword', suggest: true, then: {
|
||||||
|
'': aliasListToEnd,
|
||||||
|
}},
|
||||||
|
'end': {type: 'keyword', suggest: true, then: {
|
||||||
|
'': aliasListToEnd,
|
||||||
|
'\n': end,
|
||||||
|
}},
|
||||||
|
'if': {type: 'keyword', suggest: true, then: {
|
||||||
|
'': textToEnd,
|
||||||
':': {type: 'operator', suggest: true, then: {
|
':': {type: 'operator', suggest: true, then: {
|
||||||
'': CM_TEXT_TO_END,
|
'': textToEnd,
|
||||||
|
}},
|
||||||
|
'\n': end,
|
||||||
|
}},
|
||||||
|
'else': {type: 'keyword', suggest: ['else\n', 'else if: '], then: {
|
||||||
|
'if': {type: 'keyword', suggest: 'if: ', then: {
|
||||||
|
'': textToEnd,
|
||||||
|
':': {type: 'operator', suggest: true, then: {
|
||||||
|
'': textToEnd,
|
||||||
|
}},
|
||||||
|
}},
|
||||||
|
'\n': end,
|
||||||
|
}},
|
||||||
|
'repeat': {type: 'keyword', suggest: true, then: {
|
||||||
|
'': textToEnd,
|
||||||
|
':': {type: 'operator', suggest: true, then: {
|
||||||
|
'': textToEnd,
|
||||||
|
}},
|
||||||
|
'\n': end,
|
||||||
|
}},
|
||||||
|
'note': {type: 'keyword', suggest: true, then: {
|
||||||
|
'over': {type: 'keyword', suggest: true, then: {
|
||||||
|
'': agentListToEnd,
|
||||||
|
}},
|
||||||
|
'left': makeSideNote('left'),
|
||||||
|
'right': makeSideNote('right'),
|
||||||
|
'between': {type: 'keyword', suggest: true, then: {
|
||||||
|
'': agentListToEnd,
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
'\n': CM_END,
|
'state': {type: 'keyword', suggest: 'state over ', then: {
|
||||||
}},
|
'over': {type: 'keyword', suggest: true, then: {
|
||||||
'repeat': {type: 'keyword', suggest: true, then: {
|
'': agentListToEnd,
|
||||||
'': CM_TEXT_TO_END,
|
|
||||||
':': {type: 'operator', suggest: true, then: {
|
|
||||||
'': CM_TEXT_TO_END,
|
|
||||||
}},
|
|
||||||
'\n': CM_END,
|
|
||||||
}},
|
|
||||||
'note': {type: 'keyword', suggest: true, then: {
|
|
||||||
'over': {type: 'keyword', suggest: true, then: {
|
|
||||||
'': CM_AGENT_LIST_TO_TEXT,
|
|
||||||
}},
|
|
||||||
'left': makeCMSideNote('left'),
|
|
||||||
'right': makeCMSideNote('right'),
|
|
||||||
'between': {type: 'keyword', suggest: true, then: {
|
|
||||||
'': CM_AGENT_LIST_TO_TEXT,
|
|
||||||
}},
|
|
||||||
}},
|
|
||||||
'state': {type: 'keyword', suggest: 'state over ', then: {
|
|
||||||
'over': {type: 'keyword', suggest: true, then: {
|
|
||||||
'': CM_AGENT_LIST_TO_TEXT,
|
|
||||||
}},
|
|
||||||
}},
|
|
||||||
'text': {type: 'keyword', suggest: true, then: {
|
|
||||||
'left': makeCMSideNote('left'),
|
|
||||||
'right': makeCMSideNote('right'),
|
|
||||||
}},
|
|
||||||
'simultaneously': {type: 'keyword', suggest: true, then: {
|
|
||||||
':': {type: 'operator', suggest: true, then: {}},
|
|
||||||
'with': {type: 'keyword', suggest: true, then: {
|
|
||||||
'': {type: 'variable', suggest: 'Label', then: {
|
|
||||||
'': 0,
|
|
||||||
':': {type: 'operator', suggest: true, then: {}},
|
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
}},
|
'text': {type: 'keyword', suggest: true, then: {
|
||||||
}, makeCMConnect())};
|
'left': makeSideNote('left'),
|
||||||
|
'right': makeSideNote('right'),
|
||||||
|
}},
|
||||||
|
'simultaneously': {type: 'keyword', suggest: true, then: {
|
||||||
|
':': {type: 'operator', suggest: true, then: {}},
|
||||||
|
'with': {type: 'keyword', suggest: true, then: {
|
||||||
|
'': {type: 'variable', suggest: 'Label', then: {
|
||||||
|
'': 0,
|
||||||
|
':': {type: 'operator', suggest: true, then: {}},
|
||||||
|
}},
|
||||||
|
}},
|
||||||
|
}},
|
||||||
|
}, makeCMConnect())};
|
||||||
|
})());
|
||||||
|
|
||||||
function cmCappedToken(token, current) {
|
function cmCappedToken(token, current) {
|
||||||
if(Object.keys(current.then).length > 0) {
|
if(Object.keys(current.then).length > 0) {
|
||||||
|
|
|
@ -17,10 +17,6 @@ define(['core/ArrayUtilities'], (array) => {
|
||||||
return {name, anchorRight};
|
return {name, anchorRight};
|
||||||
}
|
}
|
||||||
|
|
||||||
function convertAgent(agent) {
|
|
||||||
return makeAgent(agent.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getAgentName(agent) {
|
function getAgentName(agent) {
|
||||||
return agent.name;
|
return agent.name;
|
||||||
}
|
}
|
||||||
|
@ -181,6 +177,7 @@ define(['core/ArrayUtilities'], (array) => {
|
||||||
return class Generator {
|
return class Generator {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.agentStates = new Map();
|
this.agentStates = new Map();
|
||||||
|
this.agentAliases = new Map();
|
||||||
this.agents = [];
|
this.agents = [];
|
||||||
this.blockCount = 0;
|
this.blockCount = 0;
|
||||||
this.nesting = [];
|
this.nesting = [];
|
||||||
|
@ -204,6 +201,29 @@ define(['core/ArrayUtilities'], (array) => {
|
||||||
'block end': this.handleBlockEnd.bind(this),
|
'block end': this.handleBlockEnd.bind(this),
|
||||||
};
|
};
|
||||||
this.handleStage = this.handleStage.bind(this);
|
this.handleStage = this.handleStage.bind(this);
|
||||||
|
this.convertAgent = this.convertAgent.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
convertAgent({alias, name}) {
|
||||||
|
if(alias) {
|
||||||
|
if(this.agentAliases.has(name)) {
|
||||||
|
throw new Error(
|
||||||
|
'Cannot alias ' + name + '; it is already an alias'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const old = this.agentAliases.get(alias);
|
||||||
|
if(
|
||||||
|
(old && old !== alias) ||
|
||||||
|
this.agents.some((agent) => (agent.name === alias))
|
||||||
|
) {
|
||||||
|
throw new Error(
|
||||||
|
'Cannot use ' + alias +
|
||||||
|
' as an alias; it is already in use'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.agentAliases.set(alias, name);
|
||||||
|
}
|
||||||
|
return makeAgent(this.agentAliases.get(name) || name);
|
||||||
}
|
}
|
||||||
|
|
||||||
addStage(stage, isVisible = true) {
|
addStage(stage, isVisible = true) {
|
||||||
|
@ -230,13 +250,18 @@ define(['core/ArrayUtilities'], (array) => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
defineAgents(agents) {
|
defineAgents(colAgents) {
|
||||||
array.mergeSets(this.currentNest.agents, agents, agentEqCheck);
|
array.mergeSets(this.currentNest.agents, colAgents, agentEqCheck);
|
||||||
array.mergeSets(this.agents, agents, agentEqCheck);
|
array.mergeSets(this.agents, colAgents, agentEqCheck);
|
||||||
}
|
}
|
||||||
|
|
||||||
setAgentVisRaw(agents, visible, mode, checked = false) {
|
setAgentVis(colAgents, visible, mode, checked = false) {
|
||||||
const filteredAgents = agents.filter((agent) => {
|
const seen = new Set();
|
||||||
|
const filteredAgents = colAgents.filter((agent) => {
|
||||||
|
if(seen.has(agent.name)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
seen.add(agent.name);
|
||||||
const state = this.agentStates.get(agent.name) || DEFAULT_AGENT;
|
const state = this.agentStates.get(agent.name) || DEFAULT_AGENT;
|
||||||
if(state.locked) {
|
if(state.locked) {
|
||||||
if(checked) {
|
if(checked) {
|
||||||
|
@ -269,17 +294,8 @@ define(['core/ArrayUtilities'], (array) => {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
setAgentVis(agents, visible, mode, checked = false) {
|
setAgentHighlight(colAgents, highlighted, checked = false) {
|
||||||
return this.setAgentVisRaw(
|
const filteredAgents = colAgents.filter((agent) => {
|
||||||
agents.map(convertAgent),
|
|
||||||
visible,
|
|
||||||
mode,
|
|
||||||
checked
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
setAgentHighlight(agents, highlighted, checked = false) {
|
|
||||||
const filteredAgents = agents.filter((agent) => {
|
|
||||||
const state = this.agentStates.get(agent.name) || DEFAULT_AGENT;
|
const state = this.agentStates.get(agent.name) || DEFAULT_AGENT;
|
||||||
if(state.locked) {
|
if(state.locked) {
|
||||||
if(checked) {
|
if(checked) {
|
||||||
|
@ -349,27 +365,44 @@ define(['core/ArrayUtilities'], (array) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
handleConnect({agents, label, options}) {
|
handleConnect({agents, label, options}) {
|
||||||
const beginAgents = agents.filter(agentHasFlag('begin'));
|
const beginAgents = (agents
|
||||||
const endAgents = agents.filter(agentHasFlag('end'));
|
.filter(agentHasFlag('begin'))
|
||||||
|
.map(this.convertAgent)
|
||||||
|
);
|
||||||
|
const endAgents = (agents
|
||||||
|
.filter(agentHasFlag('end'))
|
||||||
|
.map(this.convertAgent)
|
||||||
|
);
|
||||||
if(array.hasIntersection(beginAgents, endAgents, agentEqCheck)) {
|
if(array.hasIntersection(beginAgents, endAgents, agentEqCheck)) {
|
||||||
throw new Error('Cannot set agent visibility multiple times');
|
throw new Error('Cannot set agent visibility multiple times');
|
||||||
}
|
}
|
||||||
|
|
||||||
const startAgents = agents.filter(agentHasFlag('start'));
|
const startAgents = (agents
|
||||||
const stopAgents = agents.filter(agentHasFlag('stop'));
|
.filter(agentHasFlag('start'))
|
||||||
|
.map(this.convertAgent)
|
||||||
|
);
|
||||||
|
const stopAgents = (agents
|
||||||
|
.filter(agentHasFlag('stop'))
|
||||||
|
.map(this.convertAgent)
|
||||||
|
);
|
||||||
array.mergeSets(stopAgents, endAgents);
|
array.mergeSets(stopAgents, endAgents);
|
||||||
if(array.hasIntersection(startAgents, stopAgents, agentEqCheck)) {
|
if(array.hasIntersection(startAgents, stopAgents, agentEqCheck)) {
|
||||||
throw new Error('Cannot set agent highlighting multiple times');
|
throw new Error('Cannot set agent highlighting multiple times');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.defineAgents(agents.map(convertAgent));
|
const colAgents = agents.map(this.convertAgent);
|
||||||
|
const agentNames = colAgents.map(getAgentName);
|
||||||
|
this.defineAgents(colAgents);
|
||||||
|
|
||||||
const implicitBegin = agents.filter(agentHasFlag('begin', false));
|
const implicitBegin = (agents
|
||||||
|
.filter(agentHasFlag('begin', false))
|
||||||
|
.map(this.convertAgent)
|
||||||
|
);
|
||||||
this.addStage(this.setAgentVis(implicitBegin, true, 'box'));
|
this.addStage(this.setAgentVis(implicitBegin, true, 'box'));
|
||||||
|
|
||||||
const connectStage = {
|
const connectStage = {
|
||||||
type: 'connect',
|
type: 'connect',
|
||||||
agentNames: agents.map(getAgentName),
|
agentNames,
|
||||||
label,
|
label,
|
||||||
options,
|
options,
|
||||||
};
|
};
|
||||||
|
@ -388,32 +421,39 @@ define(['core/ArrayUtilities'], (array) => {
|
||||||
if(agents.length === 0) {
|
if(agents.length === 0) {
|
||||||
colAgents = NOTE_DEFAULT_AGENTS[type] || [];
|
colAgents = NOTE_DEFAULT_AGENTS[type] || [];
|
||||||
} else {
|
} else {
|
||||||
colAgents = agents.map(convertAgent);
|
colAgents = agents.map(this.convertAgent);
|
||||||
|
}
|
||||||
|
const agentNames = colAgents.map(getAgentName);
|
||||||
|
const uniqueAgents = new Set(agentNames).size;
|
||||||
|
if(type === 'note between' && uniqueAgents < 2) {
|
||||||
|
throw new Error('note between requires at least 2 agents');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.addStage(this.setAgentVisRaw(colAgents, true, 'box'));
|
this.addStage(this.setAgentVis(colAgents, true, 'box'));
|
||||||
this.defineAgents(colAgents);
|
this.defineAgents(colAgents);
|
||||||
|
|
||||||
this.addStage({
|
this.addStage({
|
||||||
type,
|
type,
|
||||||
agentNames: colAgents.map(getAgentName),
|
agentNames,
|
||||||
mode,
|
mode,
|
||||||
label,
|
label,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleAgentDefine({agents}) {
|
handleAgentDefine({agents}) {
|
||||||
this.defineAgents(agents.map(convertAgent));
|
this.defineAgents(agents.map(this.convertAgent));
|
||||||
}
|
}
|
||||||
|
|
||||||
handleAgentBegin({agents, mode}) {
|
handleAgentBegin({agents, mode}) {
|
||||||
this.addStage(this.setAgentVis(agents, true, mode, true));
|
const colAgents = agents.map(this.convertAgent);
|
||||||
|
this.addStage(this.setAgentVis(colAgents, true, mode, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
handleAgentEnd({agents, mode}) {
|
handleAgentEnd({agents, mode}) {
|
||||||
|
const colAgents = agents.map(this.convertAgent);
|
||||||
this.addParallelStages([
|
this.addParallelStages([
|
||||||
this.setAgentHighlight(agents, false),
|
this.setAgentHighlight(colAgents, false),
|
||||||
this.setAgentVis(agents, false, mode, true),
|
this.setAgentVis(colAgents, false, mode, true),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -467,6 +507,7 @@ define(['core/ArrayUtilities'], (array) => {
|
||||||
generate({stages, meta = {}}) {
|
generate({stages, meta = {}}) {
|
||||||
this.agentStates.clear();
|
this.agentStates.clear();
|
||||||
this.markers.clear();
|
this.markers.clear();
|
||||||
|
this.agentAliases.clear();
|
||||||
this.agents.length = 0;
|
this.agents.length = 0;
|
||||||
this.blockCount = 0;
|
this.blockCount = 0;
|
||||||
this.nesting.length = 0;
|
this.nesting.length = 0;
|
||||||
|
@ -485,7 +526,7 @@ define(['core/ArrayUtilities'], (array) => {
|
||||||
|
|
||||||
this.addParallelStages([
|
this.addParallelStages([
|
||||||
this.setAgentHighlight(this.agents, false),
|
this.setAgentHighlight(this.agents, false),
|
||||||
this.setAgentVisRaw(this.agents, false, terminators),
|
this.setAgentVis(this.agents, false, terminators),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
addBounds(
|
addBounds(
|
||||||
|
|
|
@ -8,7 +8,7 @@ defineDescribe('Sequence Generator', ['./Generator'], (Generator) => {
|
||||||
if(typeof item === 'object') {
|
if(typeof item === 'object') {
|
||||||
return item;
|
return item;
|
||||||
} else {
|
} else {
|
||||||
return {name: item, flags: []};
|
return {name: item, alias: '', flags: []};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -231,6 +231,33 @@ defineDescribe('Sequence Generator', ['./Generator'], (Generator) => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('converts aliases', () => {
|
||||||
|
const sequence = generator.generate({stages: [
|
||||||
|
PARSED.defineAgents([{name: 'Baz', alias: 'B', flags: []}]),
|
||||||
|
PARSED.connect(['A', 'B']),
|
||||||
|
]});
|
||||||
|
expect(sequence.agents).toEqual([
|
||||||
|
{name: '[', anchorRight: true},
|
||||||
|
{name: 'Baz', anchorRight: false},
|
||||||
|
{name: 'A', anchorRight: false},
|
||||||
|
{name: ']', anchorRight: false},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects duplicate aliases', () => {
|
||||||
|
expect(() => generator.generate({stages: [
|
||||||
|
PARSED.defineAgents([{name: 'Foo', alias: 'B', flags: []}]),
|
||||||
|
PARSED.defineAgents([{name: 'Bar', alias: 'B', flags: []}]),
|
||||||
|
]})).toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects using agent names as aliases', () => {
|
||||||
|
expect(() => generator.generate({stages: [
|
||||||
|
PARSED.defineAgents([{name: 'Foo', alias: 'B', flags: []}]),
|
||||||
|
PARSED.defineAgents([{name: 'Bar', alias: 'Foo', flags: []}]),
|
||||||
|
]})).toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
it('creates implicit begin stages for agents when used', () => {
|
it('creates implicit begin stages for agents when used', () => {
|
||||||
const sequence = generator.generate({stages: [
|
const sequence = generator.generate({stages: [
|
||||||
PARSED.connect(['A', 'B']),
|
PARSED.connect(['A', 'B']),
|
||||||
|
@ -347,6 +374,16 @@ defineDescribe('Sequence Generator', ['./Generator'], (Generator) => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('removes duplicate begin agents', () => {
|
||||||
|
const sequence = generator.generate({stages: [
|
||||||
|
PARSED.beginAgents(['A', 'A']),
|
||||||
|
]});
|
||||||
|
expect(sequence.stages).toEqual([
|
||||||
|
GENERATED.beginAgents(['A']),
|
||||||
|
jasmine.anything(),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
it('collapses adjacent begin statements', () => {
|
it('collapses adjacent begin statements', () => {
|
||||||
const sequence = generator.generate({stages: [
|
const sequence = generator.generate({stages: [
|
||||||
PARSED.connect(['A', 'B']),
|
PARSED.connect(['A', 'B']),
|
||||||
|
@ -378,6 +415,17 @@ defineDescribe('Sequence Generator', ['./Generator'], (Generator) => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('removes duplicate end agents', () => {
|
||||||
|
const sequence = generator.generate({stages: [
|
||||||
|
PARSED.beginAgents(['A']),
|
||||||
|
PARSED.endAgents(['A', 'A']),
|
||||||
|
]});
|
||||||
|
expect(sequence.stages).toEqual([
|
||||||
|
jasmine.anything(),
|
||||||
|
GENERATED.endAgents(['A']),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
it('removes superfluous end statements', () => {
|
it('removes superfluous end statements', () => {
|
||||||
const sequence = generator.generate({stages: [
|
const sequence = generator.generate({stages: [
|
||||||
PARSED.defineAgents(['E']),
|
PARSED.defineAgents(['E']),
|
||||||
|
@ -409,8 +457,8 @@ defineDescribe('Sequence Generator', ['./Generator'], (Generator) => {
|
||||||
|
|
||||||
it('adds parallel highlighting stages', () => {
|
it('adds parallel highlighting stages', () => {
|
||||||
const sequence = generator.generate({stages: [
|
const sequence = generator.generate({stages: [
|
||||||
PARSED.connect(['A', {name: 'B', flags: ['start']}]),
|
PARSED.connect(['A', {name: 'B', alias: '', flags: ['start']}]),
|
||||||
PARSED.connect(['A', {name: 'B', flags: ['stop']}]),
|
PARSED.connect(['A', {name: 'B', alias: '', flags: ['stop']}]),
|
||||||
]});
|
]});
|
||||||
expect(sequence.stages).toEqual([
|
expect(sequence.stages).toEqual([
|
||||||
jasmine.anything(),
|
jasmine.anything(),
|
||||||
|
@ -428,7 +476,7 @@ defineDescribe('Sequence Generator', ['./Generator'], (Generator) => {
|
||||||
|
|
||||||
it('adds parallel begin stages', () => {
|
it('adds parallel begin stages', () => {
|
||||||
const sequence = generator.generate({stages: [
|
const sequence = generator.generate({stages: [
|
||||||
PARSED.connect(['A', {name: 'B', flags: ['begin']}]),
|
PARSED.connect(['A', {name: 'B', alias: '', flags: ['begin']}]),
|
||||||
]});
|
]});
|
||||||
expect(sequence.stages).toEqual([
|
expect(sequence.stages).toEqual([
|
||||||
GENERATED.beginAgents(['A']),
|
GENERATED.beginAgents(['A']),
|
||||||
|
@ -442,7 +490,7 @@ defineDescribe('Sequence Generator', ['./Generator'], (Generator) => {
|
||||||
|
|
||||||
it('adds parallel end stages', () => {
|
it('adds parallel end stages', () => {
|
||||||
const sequence = generator.generate({stages: [
|
const sequence = generator.generate({stages: [
|
||||||
PARSED.connect(['A', {name: 'B', flags: ['end']}]),
|
PARSED.connect(['A', {name: 'B', alias: '', flags: ['end']}]),
|
||||||
]});
|
]});
|
||||||
expect(sequence.stages).toEqual([
|
expect(sequence.stages).toEqual([
|
||||||
GENERATED.beginAgents(['A', 'B']),
|
GENERATED.beginAgents(['A', 'B']),
|
||||||
|
@ -456,8 +504,8 @@ defineDescribe('Sequence Generator', ['./Generator'], (Generator) => {
|
||||||
|
|
||||||
it('implicitly ends highlighting when ending a stage', () => {
|
it('implicitly ends highlighting when ending a stage', () => {
|
||||||
const sequence = generator.generate({stages: [
|
const sequence = generator.generate({stages: [
|
||||||
PARSED.connect(['A', {name: 'B', flags: ['start']}]),
|
PARSED.connect(['A', {name: 'B', alias: '', flags: ['start']}]),
|
||||||
PARSED.connect(['A', {name: 'B', flags: ['end']}]),
|
PARSED.connect(['A', {name: 'B', alias: '', flags: ['end']}]),
|
||||||
]});
|
]});
|
||||||
expect(sequence.stages).toEqual([
|
expect(sequence.stages).toEqual([
|
||||||
jasmine.anything(),
|
jasmine.anything(),
|
||||||
|
@ -472,32 +520,41 @@ defineDescribe('Sequence Generator', ['./Generator'], (Generator) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('rejects conflicting flags', () => {
|
it('rejects conflicting flags', () => {
|
||||||
expect(() => generator.generate({stages: [
|
|
||||||
PARSED.connect(['A', {name: 'B', flags: ['start', 'stop']}]),
|
|
||||||
]})).toThrow();
|
|
||||||
|
|
||||||
expect(() => generator.generate({stages: [
|
expect(() => generator.generate({stages: [
|
||||||
PARSED.connect([
|
PARSED.connect([
|
||||||
{name: 'A', flags: ['start']},
|
'A',
|
||||||
{name: 'A', flags: ['stop']},
|
{name: 'B', alias: '', flags: ['start', 'stop']},
|
||||||
]),
|
]),
|
||||||
]})).toThrow();
|
]})).toThrow();
|
||||||
|
|
||||||
expect(() => generator.generate({stages: [
|
expect(() => generator.generate({stages: [
|
||||||
PARSED.connect(['A', {name: 'B', flags: ['begin', 'end']}]),
|
PARSED.connect([
|
||||||
|
{name: 'A', alias: '', flags: ['start']},
|
||||||
|
{name: 'A', alias: '', flags: ['stop']},
|
||||||
|
]),
|
||||||
]})).toThrow();
|
]})).toThrow();
|
||||||
|
|
||||||
expect(() => generator.generate({stages: [
|
expect(() => generator.generate({stages: [
|
||||||
PARSED.connect([
|
PARSED.connect([
|
||||||
{name: 'A', flags: ['begin']},
|
'A',
|
||||||
{name: 'A', flags: ['end']},
|
{name: 'B', alias: '', flags: ['begin', 'end']},
|
||||||
|
]),
|
||||||
|
]})).toThrow();
|
||||||
|
|
||||||
|
expect(() => generator.generate({stages: [
|
||||||
|
PARSED.connect([
|
||||||
|
{name: 'A', alias: '', flags: ['begin']},
|
||||||
|
{name: 'A', alias: '', flags: ['end']},
|
||||||
]),
|
]),
|
||||||
]})).toThrow();
|
]})).toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('adds implicit highlight end with implicit terminator', () => {
|
it('adds implicit highlight end with implicit terminator', () => {
|
||||||
const sequence = generator.generate({stages: [
|
const sequence = generator.generate({stages: [
|
||||||
PARSED.connect(['A', {name: 'B', flags: ['start']}]),
|
PARSED.connect([
|
||||||
|
'A',
|
||||||
|
{name: 'B', alias: '', flags: ['start']},
|
||||||
|
]),
|
||||||
]});
|
]});
|
||||||
expect(sequence.stages).toEqual([
|
expect(sequence.stages).toEqual([
|
||||||
jasmine.anything(),
|
jasmine.anything(),
|
||||||
|
@ -511,7 +568,7 @@ defineDescribe('Sequence Generator', ['./Generator'], (Generator) => {
|
||||||
|
|
||||||
it('adds implicit highlight end with explicit terminator', () => {
|
it('adds implicit highlight end with explicit terminator', () => {
|
||||||
const sequence = generator.generate({stages: [
|
const sequence = generator.generate({stages: [
|
||||||
PARSED.connect(['A', {name: 'B', flags: ['start']}]),
|
PARSED.connect(['A', {name: 'B', alias: '', flags: ['start']}]),
|
||||||
PARSED.endAgents(['A', 'B']),
|
PARSED.endAgents(['A', 'B']),
|
||||||
]});
|
]});
|
||||||
expect(sequence.stages).toEqual([
|
expect(sequence.stages).toEqual([
|
||||||
|
@ -527,8 +584,8 @@ defineDescribe('Sequence Generator', ['./Generator'], (Generator) => {
|
||||||
it('collapses adjacent end statements containing highlighting', () => {
|
it('collapses adjacent end statements containing highlighting', () => {
|
||||||
const sequence = generator.generate({stages: [
|
const sequence = generator.generate({stages: [
|
||||||
PARSED.connect([
|
PARSED.connect([
|
||||||
{name: 'A', flags: ['start']},
|
{name: 'A', alias: '', flags: ['start']},
|
||||||
{name: 'B', flags: ['start']},
|
{name: 'B', alias: '', flags: ['start']},
|
||||||
]),
|
]),
|
||||||
PARSED.endAgents(['A']),
|
PARSED.endAgents(['A']),
|
||||||
PARSED.endAgents(['B']),
|
PARSED.endAgents(['B']),
|
||||||
|
@ -849,6 +906,15 @@ defineDescribe('Sequence Generator', ['./Generator'], (Generator) => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('rejects note between with a repeated agent', () => {
|
||||||
|
expect(() => generator.generate({stages: [
|
||||||
|
PARSED.note('note between', ['A', 'A'], {
|
||||||
|
mode: 'foo',
|
||||||
|
label: 'bar',
|
||||||
|
}),
|
||||||
|
]})).toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
it('defaults to showing notes around the entire diagram', () => {
|
it('defaults to showing notes around the entire diagram', () => {
|
||||||
const sequence = generator.generate({stages: [
|
const sequence = generator.generate({stages: [
|
||||||
PARSED.note('note right', []),
|
PARSED.note('note right', []),
|
||||||
|
|
|
@ -114,7 +114,27 @@ define([
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function readAgent(line, start, end, flagTypes = {}) {
|
function readAgentAlias(line, start, end, enableAlias) {
|
||||||
|
let aliasSep = -1;
|
||||||
|
if(enableAlias) {
|
||||||
|
aliasSep = findToken(line, 'as', start);
|
||||||
|
}
|
||||||
|
if(aliasSep === -1 || aliasSep >= end) {
|
||||||
|
aliasSep = end;
|
||||||
|
}
|
||||||
|
if(start >= aliasSep) {
|
||||||
|
throw new Error('Missing agent name');
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
name: joinLabel(line, start, aliasSep),
|
||||||
|
alias: joinLabel(line, aliasSep + 1, end),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function readAgent(line, start, end, {
|
||||||
|
flagTypes = {},
|
||||||
|
aliases = false,
|
||||||
|
} = {}) {
|
||||||
const flags = [];
|
const flags = [];
|
||||||
let p = start;
|
let p = start;
|
||||||
for(; p < end; ++ p) {
|
for(; p < end; ++ p) {
|
||||||
|
@ -129,23 +149,22 @@ define([
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(p >= end) {
|
const {name, alias} = readAgentAlias(line, p, end, aliases);
|
||||||
throw new Error('Missing agent name');
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
name: joinLabel(line, p, end),
|
name,
|
||||||
|
alias,
|
||||||
flags,
|
flags,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function readAgentList(line, start, end, flagTypes) {
|
function readAgentList(line, start, end, readAgentOpts) {
|
||||||
const list = [];
|
const list = [];
|
||||||
let currentStart = -1;
|
let currentStart = -1;
|
||||||
for(let i = start; i < end; ++ i) {
|
for(let i = start; i < end; ++ i) {
|
||||||
const token = line[i];
|
const token = line[i];
|
||||||
if(tokenKeyword(token) === ',') {
|
if(tokenKeyword(token) === ',') {
|
||||||
if(currentStart !== -1) {
|
if(currentStart !== -1) {
|
||||||
list.push(readAgent(line, currentStart, i, flagTypes));
|
list.push(readAgent(line, currentStart, i, readAgentOpts));
|
||||||
currentStart = -1;
|
currentStart = -1;
|
||||||
}
|
}
|
||||||
} else if(currentStart === -1) {
|
} else if(currentStart === -1) {
|
||||||
|
@ -153,7 +172,7 @@ define([
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(currentStart !== -1) {
|
if(currentStart !== -1) {
|
||||||
list.push(readAgent(line, currentStart, end, flagTypes));
|
list.push(readAgent(line, currentStart, end, readAgentOpts));
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
@ -208,7 +227,7 @@ define([
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return Object.assign({
|
return Object.assign({
|
||||||
agents: readAgentList(line, 1, line.length),
|
agents: readAgentList(line, 1, line.length, {aliases: true}),
|
||||||
}, type);
|
}, type);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -280,11 +299,14 @@ define([
|
||||||
if(typePos <= 0 || typePos >= labelSep - 1) {
|
if(typePos <= 0 || typePos >= labelSep - 1) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
const readAgentOpts = {
|
||||||
|
flagTypes: CONNECT_AGENT_FLAGS,
|
||||||
|
};
|
||||||
return {
|
return {
|
||||||
type: 'connect',
|
type: 'connect',
|
||||||
agents: [
|
agents: [
|
||||||
readAgent(line, 0, typePos, CONNECT_AGENT_FLAGS),
|
readAgent(line, 0, typePos, readAgentOpts),
|
||||||
readAgent(line, typePos + 1, labelSep, CONNECT_AGENT_FLAGS),
|
readAgent(line, typePos + 1, labelSep, readAgentOpts),
|
||||||
],
|
],
|
||||||
label: joinLabel(line, labelSep + 1),
|
label: joinLabel(line, labelSep + 1),
|
||||||
options,
|
options,
|
||||||
|
|
|
@ -12,7 +12,11 @@ defineDescribe('Sequence Parser', ['./Parser'], (Parser) => {
|
||||||
} = {}) => {
|
} = {}) => {
|
||||||
return {
|
return {
|
||||||
type: 'connect',
|
type: 'connect',
|
||||||
agents: agentNames.map((name) => ({name, flags: []})),
|
agents: agentNames.map((name) => ({
|
||||||
|
name,
|
||||||
|
alias: '',
|
||||||
|
flags: [],
|
||||||
|
})),
|
||||||
label,
|
label,
|
||||||
options: {
|
options: {
|
||||||
line,
|
line,
|
||||||
|
@ -64,6 +68,15 @@ defineDescribe('Sequence Parser', ['./Parser'], (Parser) => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('propagates aliases', () => {
|
||||||
|
const parsed = parser.parse('define Foo Bar as A B');
|
||||||
|
expect(parsed.stages).toEqual([
|
||||||
|
{type: 'agent define', agents: [
|
||||||
|
{name: 'Foo Bar', alias: 'A B', flags: []},
|
||||||
|
]},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
it('respects spacing within agent names', () => {
|
it('respects spacing within agent names', () => {
|
||||||
const parsed = parser.parse('A+B -> C D');
|
const parsed = parser.parse('A+B -> C D');
|
||||||
expect(parsed.stages).toEqual([
|
expect(parsed.stages).toEqual([
|
||||||
|
@ -84,8 +97,12 @@ defineDescribe('Sequence Parser', ['./Parser'], (Parser) => {
|
||||||
{
|
{
|
||||||
type: 'connect',
|
type: 'connect',
|
||||||
agents: [
|
agents: [
|
||||||
{name: 'A', flags: ['start']},
|
{name: 'A', alias: '', flags: ['start']},
|
||||||
{name: 'B', flags: ['stop', 'begin', 'end']},
|
{name: 'B', alias: '', flags: [
|
||||||
|
'stop',
|
||||||
|
'begin',
|
||||||
|
'end',
|
||||||
|
]},
|
||||||
],
|
],
|
||||||
label: jasmine.anything(),
|
label: jasmine.anything(),
|
||||||
options: jasmine.anything(),
|
options: jasmine.anything(),
|
||||||
|
@ -192,7 +209,7 @@ defineDescribe('Sequence Parser', ['./Parser'], (Parser) => {
|
||||||
const parsed = parser.parse('note over A: hello there');
|
const parsed = parser.parse('note over A: hello there');
|
||||||
expect(parsed.stages).toEqual([{
|
expect(parsed.stages).toEqual([{
|
||||||
type: 'note over',
|
type: 'note over',
|
||||||
agents: [{name: 'A', flags: []}],
|
agents: [{name: 'A', alias: '', flags: []}],
|
||||||
mode: 'note',
|
mode: 'note',
|
||||||
label: 'hello there',
|
label: 'hello there',
|
||||||
}]);
|
}]);
|
||||||
|
@ -209,31 +226,34 @@ defineDescribe('Sequence Parser', ['./Parser'], (Parser) => {
|
||||||
expect(parsed.stages).toEqual([
|
expect(parsed.stages).toEqual([
|
||||||
{
|
{
|
||||||
type: 'note left',
|
type: 'note left',
|
||||||
agents: [{name: 'A', flags: []}],
|
agents: [{name: 'A', alias: '', flags: []}],
|
||||||
mode: 'note',
|
mode: 'note',
|
||||||
label: 'hello there',
|
label: 'hello there',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'note left',
|
type: 'note left',
|
||||||
agents: [{name: 'A', flags: []}],
|
agents: [{name: 'A', alias: '', flags: []}],
|
||||||
mode: 'note',
|
mode: 'note',
|
||||||
label: 'hello there',
|
label: 'hello there',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'note right',
|
type: 'note right',
|
||||||
agents: [{name: 'A', flags: []}],
|
agents: [{name: 'A', alias: '', flags: []}],
|
||||||
mode: 'note',
|
mode: 'note',
|
||||||
label: 'hello there',
|
label: 'hello there',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'note right',
|
type: 'note right',
|
||||||
agents: [{name: 'A', flags: []}],
|
agents: [{name: 'A', alias: '', flags: []}],
|
||||||
mode: 'note',
|
mode: 'note',
|
||||||
label: 'hello there',
|
label: 'hello there',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'note between',
|
type: 'note between',
|
||||||
agents: [{name: 'A', flags: []}, {name: 'B', flags: []}],
|
agents: [
|
||||||
|
{name: 'A', alias: '', flags: []},
|
||||||
|
{name: 'B', alias: '', flags: []},
|
||||||
|
],
|
||||||
mode: 'note',
|
mode: 'note',
|
||||||
label: 'hi',
|
label: 'hi',
|
||||||
},
|
},
|
||||||
|
@ -244,7 +264,10 @@ defineDescribe('Sequence Parser', ['./Parser'], (Parser) => {
|
||||||
const parsed = parser.parse('note over A B, C D: hi');
|
const parsed = parser.parse('note over A B, C D: hi');
|
||||||
expect(parsed.stages).toEqual([{
|
expect(parsed.stages).toEqual([{
|
||||||
type: 'note over',
|
type: 'note over',
|
||||||
agents: [{name: 'A B', flags: []}, {name: 'C D', flags: []}],
|
agents: [
|
||||||
|
{name: 'A B', alias: '', flags: []},
|
||||||
|
{name: 'C D', alias: '', flags: []},
|
||||||
|
],
|
||||||
mode: 'note',
|
mode: 'note',
|
||||||
label: 'hi',
|
label: 'hi',
|
||||||
}]);
|
}]);
|
||||||
|
@ -258,7 +281,7 @@ defineDescribe('Sequence Parser', ['./Parser'], (Parser) => {
|
||||||
const parsed = parser.parse('state over A: doing stuff');
|
const parsed = parser.parse('state over A: doing stuff');
|
||||||
expect(parsed.stages).toEqual([{
|
expect(parsed.stages).toEqual([{
|
||||||
type: 'note over',
|
type: 'note over',
|
||||||
agents: [{name: 'A', flags: []}],
|
agents: [{name: 'A', alias: '', flags: []}],
|
||||||
mode: 'state',
|
mode: 'state',
|
||||||
label: 'doing stuff',
|
label: 'doing stuff',
|
||||||
}]);
|
}]);
|
||||||
|
@ -272,7 +295,7 @@ defineDescribe('Sequence Parser', ['./Parser'], (Parser) => {
|
||||||
const parsed = parser.parse('text right of A: doing stuff');
|
const parsed = parser.parse('text right of A: doing stuff');
|
||||||
expect(parsed.stages).toEqual([{
|
expect(parsed.stages).toEqual([{
|
||||||
type: 'note right',
|
type: 'note right',
|
||||||
agents: [{name: 'A', flags: []}],
|
agents: [{name: 'A', alias: '', flags: []}],
|
||||||
mode: 'text',
|
mode: 'text',
|
||||||
label: 'doing stuff',
|
label: 'doing stuff',
|
||||||
}]);
|
}]);
|
||||||
|
@ -287,16 +310,25 @@ defineDescribe('Sequence Parser', ['./Parser'], (Parser) => {
|
||||||
expect(parsed.stages).toEqual([
|
expect(parsed.stages).toEqual([
|
||||||
{
|
{
|
||||||
type: 'agent define',
|
type: 'agent define',
|
||||||
agents: [{name: 'A', flags: []}, {name: 'B', flags: []}],
|
agents: [
|
||||||
|
{name: 'A', alias: '', flags: []},
|
||||||
|
{name: 'B', alias: '', flags: []},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'agent begin',
|
type: 'agent begin',
|
||||||
agents: [{name: 'A', flags: []}, {name: 'B', flags: []}],
|
agents: [
|
||||||
|
{name: 'A', alias: '', flags: []},
|
||||||
|
{name: 'B', alias: '', flags: []},
|
||||||
|
],
|
||||||
mode: 'box',
|
mode: 'box',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'agent end',
|
type: 'agent end',
|
||||||
agents: [{name: 'A', flags: []}, {name: 'B', flags: []}],
|
agents: [
|
||||||
|
{name: 'A', alias: '', flags: []},
|
||||||
|
{name: 'B', alias: '', flags: []},
|
||||||
|
],
|
||||||
mode: 'cross',
|
mode: 'cross',
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -103,11 +103,10 @@ define(['./BaseComponent'], (BaseComponent) => {
|
||||||
config.padding.right
|
config.padding.right
|
||||||
);
|
);
|
||||||
|
|
||||||
if(agentNames.length > 1) {
|
const {left, right} = findExtremes(env.agentInfos, agentNames);
|
||||||
const {left, right} = findExtremes(env.agentInfos, agentNames);
|
const infoL = env.agentInfos.get(left);
|
||||||
const infoL = env.agentInfos.get(left);
|
const infoR = env.agentInfos.get(right);
|
||||||
const infoR = env.agentInfos.get(right);
|
if(infoL !== infoR) {
|
||||||
|
|
||||||
const hangL = infoL.currentMaxRad + config.overlap.left;
|
const hangL = infoL.currentMaxRad + config.overlap.left;
|
||||||
const hangR = infoR.currentMaxRad + config.overlap.right;
|
const hangR = infoR.currentMaxRad + config.overlap.right;
|
||||||
|
|
||||||
|
@ -116,7 +115,7 @@ define(['./BaseComponent'], (BaseComponent) => {
|
||||||
env.addSpacing(left, {left: hangL, right: 0});
|
env.addSpacing(left, {left: hangL, right: 0});
|
||||||
env.addSpacing(right, {left: 0, right: hangR});
|
env.addSpacing(right, {left: 0, right: hangR});
|
||||||
} else {
|
} else {
|
||||||
env.addSpacing(agentNames[0], {
|
env.addSpacing(left, {
|
||||||
left: width / 2,
|
left: width / 2,
|
||||||
right: width / 2,
|
right: width / 2,
|
||||||
});
|
});
|
||||||
|
@ -126,10 +125,10 @@ define(['./BaseComponent'], (BaseComponent) => {
|
||||||
render({agentNames, mode, label}, env) {
|
render({agentNames, mode, label}, env) {
|
||||||
const config = env.theme.note[mode];
|
const config = env.theme.note[mode];
|
||||||
|
|
||||||
if(agentNames.length > 1) {
|
const {left, right} = findExtremes(env.agentInfos, agentNames);
|
||||||
const {left, right} = findExtremes(env.agentInfos, agentNames);
|
const infoL = env.agentInfos.get(left);
|
||||||
const infoL = env.agentInfos.get(left);
|
const infoR = env.agentInfos.get(right);
|
||||||
const infoR = env.agentInfos.get(right);
|
if(infoL !== infoR) {
|
||||||
return this.renderNote({
|
return this.renderNote({
|
||||||
x0: infoL.x - infoL.currentMaxRad - config.overlap.left,
|
x0: infoL.x - infoL.currentMaxRad - config.overlap.left,
|
||||||
x1: infoR.x + infoR.currentMaxRad + config.overlap.right,
|
x1: infoR.x + infoR.currentMaxRad + config.overlap.right,
|
||||||
|
@ -138,7 +137,7 @@ define(['./BaseComponent'], (BaseComponent) => {
|
||||||
label,
|
label,
|
||||||
}, env);
|
}, env);
|
||||||
} else {
|
} else {
|
||||||
const xMid = env.agentInfos.get(agentNames[0]).x;
|
const xMid = infoL.x;
|
||||||
return this.renderNote({
|
return this.renderNote({
|
||||||
xMid,
|
xMid,
|
||||||
anchor: 'middle',
|
anchor: 'middle',
|
||||||
|
|
|
@ -34,7 +34,7 @@ define(['jshintConfig', 'specs'], (jshintConfig) => {
|
||||||
|
|
||||||
const OPTS_TEST = Object.assign({}, jshintConfig, {
|
const OPTS_TEST = Object.assign({}, jshintConfig, {
|
||||||
predef: PREDEF_TEST,
|
predef: PREDEF_TEST,
|
||||||
maxstatements: 50, // allow lots of tests
|
maxstatements: 100, // allow lots of tests
|
||||||
});
|
});
|
||||||
|
|
||||||
function formatError(error) {
|
function formatError(error) {
|
||||||
|
|
|
@ -88,6 +88,7 @@ html, body {
|
||||||
background: #FFFFFF;
|
background: #FFFFFF;
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.options.links {
|
.options.links {
|
||||||
|
|
Loading…
Reference in New Issue