Agents as objects after generate
This commit is contained in:
parent
1016f9aac0
commit
2d8e3d60e1
|
@ -1,31 +1,43 @@
|
|||
define(() => {
|
||||
'use strict';
|
||||
|
||||
function mergeSets(target, b = null) {
|
||||
function indexOf(list, element, equalityCheck = null) {
|
||||
if(equalityCheck === null) {
|
||||
return list.indexOf(element);
|
||||
}
|
||||
for(let i = 0; i < list.length; ++ i) {
|
||||
if(equalityCheck(list[i], element)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
function mergeSets(target, b = null, equalityCheck = null) {
|
||||
if(!b) {
|
||||
return;
|
||||
}
|
||||
for(let i = 0; i < b.length; ++ i) {
|
||||
if(target.indexOf(b[i]) === -1) {
|
||||
if(indexOf(target, b[i], equalityCheck) === -1) {
|
||||
target.push(b[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function removeAll(target, b = null) {
|
||||
function removeAll(target, b = null, equalityCheck = null) {
|
||||
if(!b) {
|
||||
return;
|
||||
}
|
||||
for(let i = 0; i < b.length; ++ i) {
|
||||
const p = target.indexOf(b[i]);
|
||||
const p = indexOf(target, b[i], equalityCheck);
|
||||
if(p !== -1) {
|
||||
target.splice(p, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function remove(list, item) {
|
||||
const p = list.indexOf(item);
|
||||
function remove(list, item, equalityCheck = null) {
|
||||
const p = indexOf(list, item, equalityCheck);
|
||||
if(p !== -1) {
|
||||
list.splice(p, 1);
|
||||
}
|
||||
|
@ -36,6 +48,7 @@ define(() => {
|
|||
}
|
||||
|
||||
return {
|
||||
indexOf,
|
||||
mergeSets,
|
||||
removeAll,
|
||||
remove,
|
||||
|
|
|
@ -35,6 +35,17 @@ defineDescribe('ArrayUtilities', ['./ArrayUtilities'], (array) => {
|
|||
array.mergeSets(p1, p2);
|
||||
expect(p1).toEqual(['a', 'x', 'c', 'd', 'e']);
|
||||
});
|
||||
|
||||
it('uses the given equality check function', () => {
|
||||
const p1 = ['a', 'b', 'c', 'd'];
|
||||
const p2 = ['b', 'B', 'E', 'e'];
|
||||
array.mergeSets(
|
||||
p1,
|
||||
p2,
|
||||
(a, b) => (a.toLowerCase() === b.toLowerCase())
|
||||
);
|
||||
expect(p1).toEqual(['a', 'b', 'c', 'd', 'E']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.removeAll', () => {
|
||||
|
@ -71,32 +82,53 @@ defineDescribe('ArrayUtilities', ['./ArrayUtilities'], (array) => {
|
|||
array.removeAll(p1, p2);
|
||||
expect(p1).toEqual(['a', 'x', 'd']);
|
||||
});
|
||||
|
||||
it('uses the given equality check function', () => {
|
||||
const p1 = ['a', 'b', 'c', 'd'];
|
||||
const p2 = ['B', 'e'];
|
||||
array.removeAll(
|
||||
p1,
|
||||
p2,
|
||||
(a, b) => (a.toLowerCase() === b.toLowerCase())
|
||||
);
|
||||
expect(p1).toEqual(['a', 'c', 'd']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.remove', () => {
|
||||
it('removes one element matching the parameter', () => {
|
||||
const p1 = ['a', 'b'];
|
||||
array.removeAll(p1, 'b');
|
||||
array.remove(p1, 'b');
|
||||
expect(p1).toEqual(['a']);
|
||||
});
|
||||
|
||||
it('removes only the first element matching the parameter', () => {
|
||||
const p1 = ['a', 'b', 'c', 'b'];
|
||||
array.removeAll(p1, 'b');
|
||||
array.remove(p1, 'b');
|
||||
expect(p1).toEqual(['a', 'c', 'b']);
|
||||
});
|
||||
|
||||
it('ignores if not found', () => {
|
||||
const p1 = ['a', 'b', 'c'];
|
||||
array.removeAll(p1, 'nope');
|
||||
array.remove(p1, 'nope');
|
||||
expect(p1).toEqual(['a', 'b', 'c']);
|
||||
});
|
||||
|
||||
it('maintains input ordering', () => {
|
||||
const p1 = ['a', 'b', 'c'];
|
||||
array.removeAll(p1, 'b');
|
||||
array.remove(p1, 'b');
|
||||
expect(p1).toEqual(['a', 'c']);
|
||||
});
|
||||
|
||||
it('uses the given equality check function', () => {
|
||||
const p1 = ['a', 'b', 'c', 'd'];
|
||||
array.remove(
|
||||
p1,
|
||||
'B',
|
||||
(a, b) => (a.toLowerCase() === b.toLowerCase())
|
||||
);
|
||||
expect(p1).toEqual(['a', 'c', 'd']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.last', () => {
|
||||
|
|
|
@ -8,6 +8,22 @@ define(['core/ArrayUtilities'], (array) => {
|
|||
}
|
||||
}
|
||||
|
||||
function agentEqCheck(a, b) {
|
||||
return a.name === b.name;
|
||||
}
|
||||
|
||||
function makeAgent(name, {anchorRight = false} = {}) {
|
||||
return {name, anchorRight};
|
||||
}
|
||||
|
||||
function convertAgent(agent) {
|
||||
return makeAgent(agent.name);
|
||||
}
|
||||
|
||||
function getAgentName(agent) {
|
||||
return agent.name;
|
||||
}
|
||||
|
||||
const LOCKED_AGENT = new AgentState(false, true);
|
||||
const DEFAULT_AGENT = new AgentState(false);
|
||||
|
||||
|
@ -30,12 +46,14 @@ define(['core/ArrayUtilities'], (array) => {
|
|||
this.stageHandlers = {
|
||||
'mark': this.handleMark.bind(this),
|
||||
'async': this.handleAsync.bind(this),
|
||||
'note over': this.handleNote.bind(this),
|
||||
'note left': this.handleNote.bind(this),
|
||||
'note right': this.handleNote.bind(this),
|
||||
'agent define': this.handleAgentDefine.bind(this),
|
||||
'agent begin': this.handleAgentBegin.bind(this),
|
||||
'agent end': this.handleAgentEnd.bind(this),
|
||||
'connection': this.handleConnection.bind(this),
|
||||
'note over': this.handleNote.bind(this),
|
||||
'note left': this.handleNote.bind(this),
|
||||
'note right': this.handleNote.bind(this),
|
||||
'note between': this.handleNote.bind(this),
|
||||
'block begin': this.handleBlockBegin.bind(this),
|
||||
'block split': this.handleBlockSplit.bind(this),
|
||||
'block end': this.handleBlockEnd.bind(this),
|
||||
|
@ -44,14 +62,14 @@ define(['core/ArrayUtilities'], (array) => {
|
|||
}
|
||||
|
||||
addBounds(target, agentL, agentR, involvedAgents = null) {
|
||||
array.remove(target, agentL);
|
||||
array.remove(target, agentR);
|
||||
array.remove(target, agentL, agentEqCheck);
|
||||
array.remove(target, agentR, agentEqCheck);
|
||||
|
||||
let indexL = 0;
|
||||
let indexR = target.length;
|
||||
if(involvedAgents) {
|
||||
const found = (involvedAgents
|
||||
.map((agent) => target.indexOf(agent))
|
||||
.map((agent) => array.indexOf(target, agent, agentEqCheck))
|
||||
.filter((p) => (p !== -1))
|
||||
);
|
||||
indexL = found.reduce((a, b) => Math.min(a, b), target.length);
|
||||
|
@ -62,9 +80,21 @@ define(['core/ArrayUtilities'], (array) => {
|
|||
target.splice(indexR + 1, 0, agentR);
|
||||
}
|
||||
|
||||
addStage(stage, isVisible = true) {
|
||||
this.currentSection.stages.push(stage);
|
||||
if(isVisible) {
|
||||
this.currentNest.hasContent = true;
|
||||
}
|
||||
}
|
||||
|
||||
defineAgents(agents) {
|
||||
array.mergeSets(this.currentNest.agents, agents, agentEqCheck);
|
||||
array.mergeSets(this.agents, agents, agentEqCheck);
|
||||
}
|
||||
|
||||
setAgentVis(agents, visible, mode, checked = false) {
|
||||
const filteredAgents = agents.filter((agent) => {
|
||||
const state = this.agentStates.get(agent) || DEFAULT_AGENT;
|
||||
const state = this.agentStates.get(agent.name) || DEFAULT_AGENT;
|
||||
if(state.locked) {
|
||||
if(checked) {
|
||||
throw new Error('Cannot begin/end agent: ' + agent);
|
||||
|
@ -78,33 +108,32 @@ define(['core/ArrayUtilities'], (array) => {
|
|||
return;
|
||||
}
|
||||
filteredAgents.forEach((agent) => {
|
||||
const state = this.agentStates.get(agent);
|
||||
const state = this.agentStates.get(agent.name);
|
||||
if(state) {
|
||||
state.visible = visible;
|
||||
} else {
|
||||
this.agentStates.set(agent, new AgentState(visible));
|
||||
this.agentStates.set(agent.name, new AgentState(visible));
|
||||
}
|
||||
});
|
||||
const type = (visible ? 'agent begin' : 'agent end');
|
||||
const existing = array.last(this.currentSection.stages) || {};
|
||||
const agentNames = filteredAgents.map(getAgentName);
|
||||
if(existing.type === type && existing.mode === mode) {
|
||||
array.mergeSets(existing.agents, filteredAgents);
|
||||
array.mergeSets(existing.agentNames, agentNames);
|
||||
} else {
|
||||
this.currentSection.stages.push({
|
||||
this.addStage({
|
||||
type,
|
||||
agents: filteredAgents,
|
||||
agentNames,
|
||||
mode,
|
||||
});
|
||||
this.currentNest.hasContent = true;
|
||||
}
|
||||
array.mergeSets(this.currentNest.agents, filteredAgents);
|
||||
array.mergeSets(this.agents, filteredAgents);
|
||||
this.defineAgents(filteredAgents);
|
||||
}
|
||||
|
||||
beginNested(mode, label, name) {
|
||||
const nameL = name + '[';
|
||||
const nameR = name + ']';
|
||||
const agents = [nameL, nameR];
|
||||
const leftAgent = makeAgent(name + '[', {anchorRight: true});
|
||||
const rightAgent = makeAgent(name + ']');
|
||||
const agents = [leftAgent, rightAgent];
|
||||
const stages = [];
|
||||
this.currentSection = {
|
||||
mode,
|
||||
|
@ -113,57 +142,80 @@ define(['core/ArrayUtilities'], (array) => {
|
|||
};
|
||||
this.currentNest = {
|
||||
agents,
|
||||
leftAgent,
|
||||
rightAgent,
|
||||
hasContent: false,
|
||||
stage: {
|
||||
type: 'block',
|
||||
sections: [this.currentSection],
|
||||
left: nameL,
|
||||
right: nameR,
|
||||
left: leftAgent.name,
|
||||
right: rightAgent.name,
|
||||
},
|
||||
};
|
||||
this.agentStates.set(nameL, LOCKED_AGENT);
|
||||
this.agentStates.set(nameR, LOCKED_AGENT);
|
||||
this.agentStates.set(leftAgent.name, LOCKED_AGENT);
|
||||
this.agentStates.set(rightAgent.name, LOCKED_AGENT);
|
||||
this.nesting.push(this.currentNest);
|
||||
|
||||
return {agents, stages};
|
||||
}
|
||||
|
||||
handleMark(stage) {
|
||||
this.markers.add(stage.name);
|
||||
this.currentSection.stages.push(stage);
|
||||
handleMark({name}) {
|
||||
this.markers.add(name);
|
||||
this.addStage({type: 'mark', name}, false);
|
||||
}
|
||||
|
||||
handleAsync(stage) {
|
||||
if(stage.target !== '' && !this.markers.has(stage.target)) {
|
||||
throw new Error('Unknown marker: ' + stage.target);
|
||||
handleAsync({target}) {
|
||||
if(target !== '' && !this.markers.has(target)) {
|
||||
throw new Error('Unknown marker: ' + target);
|
||||
}
|
||||
this.currentSection.stages.push(stage);
|
||||
this.addStage({type: 'async', target}, false);
|
||||
}
|
||||
|
||||
handleNote(stage) {
|
||||
if(stage.agents.length === 0) {
|
||||
this.handleUnknownStage(Object.assign({}, stage, {
|
||||
agents: NOTE_DEFAULT_AGENTS[stage.type] || [],
|
||||
}));
|
||||
handleConnection({agents, label, line, left, right}) {
|
||||
const colAgents = agents.map(convertAgent);
|
||||
this.setAgentVis(colAgents, true, 'box');
|
||||
this.defineAgents(colAgents);
|
||||
|
||||
this.addStage({
|
||||
type: 'connection',
|
||||
agentNames: agents.map(getAgentName),
|
||||
label,
|
||||
line,
|
||||
left,
|
||||
right,
|
||||
});
|
||||
}
|
||||
|
||||
handleNote({type, agents, mode, label}) {
|
||||
let colAgents = null;
|
||||
if(agents.length === 0) {
|
||||
colAgents = NOTE_DEFAULT_AGENTS[type] || [];
|
||||
} else {
|
||||
this.handleUnknownStage(stage);
|
||||
colAgents = agents.map(convertAgent);
|
||||
}
|
||||
|
||||
this.setAgentVis(colAgents, true, 'box');
|
||||
this.defineAgents(colAgents);
|
||||
|
||||
this.addStage({
|
||||
type,
|
||||
agentNames: colAgents.map(getAgentName),
|
||||
mode,
|
||||
label,
|
||||
});
|
||||
}
|
||||
|
||||
handleAgentDefine({agents}) {
|
||||
const agentNames = agents.map((agent) => agent.name);
|
||||
array.mergeSets(this.currentNest.agents, agentNames);
|
||||
array.mergeSets(this.agents, agentNames);
|
||||
const colAgents = agents.map(convertAgent);
|
||||
this.defineAgents(colAgents);
|
||||
}
|
||||
|
||||
handleAgentBegin({agents, mode}) {
|
||||
const agentNames = agents.map((agent) => agent.name);
|
||||
this.setAgentVis(agentNames, true, mode, true);
|
||||
this.setAgentVis(agents.map(convertAgent), true, mode, true);
|
||||
}
|
||||
|
||||
handleAgentEnd({agents, mode}) {
|
||||
const agentNames = agents.map((agent) => agent.name);
|
||||
this.setAgentVis(agentNames, false, mode, true);
|
||||
this.setAgentVis(agents.map(convertAgent), false, mode, true);
|
||||
}
|
||||
|
||||
handleBlockBegin({mode, label}) {
|
||||
|
@ -192,45 +244,23 @@ define(['core/ArrayUtilities'], (array) => {
|
|||
if(this.nesting.length <= 1) {
|
||||
throw new Error('Invalid block nesting (too many "end"s)');
|
||||
}
|
||||
const {hasContent, stage, agents} = this.nesting.pop();
|
||||
const nested = this.nesting.pop();
|
||||
this.currentNest = array.last(this.nesting);
|
||||
this.currentSection = array.last(this.currentNest.stage.sections);
|
||||
if(hasContent) {
|
||||
array.mergeSets(this.currentNest.agents, agents);
|
||||
array.mergeSets(this.agents, agents);
|
||||
if(nested.hasContent) {
|
||||
this.defineAgents(nested.agents);
|
||||
this.addBounds(
|
||||
this.agents,
|
||||
stage.left,
|
||||
stage.right,
|
||||
agents
|
||||
nested.leftAgent,
|
||||
nested.rightAgent,
|
||||
nested.agents
|
||||
);
|
||||
this.currentSection.stages.push(stage);
|
||||
this.currentNest.hasContent = true;
|
||||
this.addStage(nested.stage);
|
||||
}
|
||||
}
|
||||
|
||||
handleUnknownStage(stage) {
|
||||
if(stage.agents) {
|
||||
const agentNames = stage.agents.map((agent) => agent.name);
|
||||
this.setAgentVis(agentNames, true, 'box');
|
||||
array.mergeSets(this.currentNest.agents, agentNames);
|
||||
array.mergeSets(this.agents, agentNames);
|
||||
this.currentSection.stages.push(Object.assign({}, stage, {
|
||||
agents: agentNames,
|
||||
}));
|
||||
} else {
|
||||
this.currentSection.stages.push(stage);
|
||||
}
|
||||
this.currentNest.hasContent = true;
|
||||
}
|
||||
|
||||
handleStage(stage) {
|
||||
const handler = this.stageHandlers[stage.type];
|
||||
if(handler) {
|
||||
handler(stage);
|
||||
} else {
|
||||
this.handleUnknownStage(stage);
|
||||
}
|
||||
this.stageHandlers[stage.type](stage);
|
||||
}
|
||||
|
||||
generate({stages, meta = {}}) {
|
||||
|
@ -254,8 +284,8 @@ define(['core/ArrayUtilities'], (array) => {
|
|||
|
||||
this.addBounds(
|
||||
this.agents,
|
||||
this.currentNest.stage.left,
|
||||
this.currentNest.stage.right
|
||||
this.currentNest.leftAgent,
|
||||
this.currentNest.rightAgent
|
||||
);
|
||||
|
||||
return {
|
||||
|
|
|
@ -3,13 +3,122 @@ defineDescribe('Sequence Generator', ['./Generator'], (Generator) => {
|
|||
|
||||
const generator = new Generator();
|
||||
|
||||
const AGENT_DEFINE = 'agent define';
|
||||
const AGENT_BEGIN = 'agent begin';
|
||||
const AGENT_END = 'agent end';
|
||||
const parsed = {
|
||||
blockBegin: (mode, label) => {
|
||||
return {type: 'block begin', mode, label};
|
||||
},
|
||||
|
||||
const BLOCK_BEGIN = 'block begin';
|
||||
const BLOCK_SPLIT = 'block split';
|
||||
const BLOCK_END = 'block end';
|
||||
blockSplit: (mode, label) => {
|
||||
return {type: 'block split', mode, label};
|
||||
},
|
||||
|
||||
blockEnd: () => {
|
||||
return {type: 'block end'};
|
||||
},
|
||||
|
||||
defineAgents: (agentNames) => {
|
||||
return {
|
||||
type: 'agent define',
|
||||
agents: agentNames.map((name) => ({name})),
|
||||
};
|
||||
},
|
||||
|
||||
beginAgents: (agentNames, {mode = 'box'} = {}) => {
|
||||
return {
|
||||
type: 'agent begin',
|
||||
agents: agentNames.map((name) => ({name})),
|
||||
mode,
|
||||
};
|
||||
},
|
||||
|
||||
endAgents: (agentNames, {mode = 'cross'} = {}) => {
|
||||
return {
|
||||
type: 'agent end',
|
||||
agents: agentNames.map((name) => ({name})),
|
||||
mode,
|
||||
};
|
||||
},
|
||||
|
||||
connect: (agentNames, {
|
||||
label = '',
|
||||
line = '',
|
||||
left = false,
|
||||
right = false,
|
||||
} = {}) => {
|
||||
return {
|
||||
type: 'connection',
|
||||
agents: agentNames.map((name) => ({name})),
|
||||
label,
|
||||
line,
|
||||
left,
|
||||
right,
|
||||
};
|
||||
},
|
||||
|
||||
note: (agentNames, {
|
||||
type = 'note over',
|
||||
mode = '',
|
||||
label = '',
|
||||
} = {}) => {
|
||||
return {
|
||||
type,
|
||||
agents: agentNames.map((name) => ({name})),
|
||||
mode,
|
||||
label,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
const generated = {
|
||||
beginAgents: (agentNames, {
|
||||
mode = jasmine.anything(),
|
||||
} = {}) => {
|
||||
return {
|
||||
type: 'agent begin',
|
||||
agentNames,
|
||||
mode,
|
||||
};
|
||||
},
|
||||
|
||||
endAgents: (agentNames, {
|
||||
mode = jasmine.anything(),
|
||||
} = {}) => {
|
||||
return {
|
||||
type: 'agent end',
|
||||
agentNames,
|
||||
mode,
|
||||
};
|
||||
},
|
||||
|
||||
connect: (agentNames, {
|
||||
label = jasmine.anything(),
|
||||
line = jasmine.anything(),
|
||||
left = jasmine.anything(),
|
||||
right = jasmine.anything(),
|
||||
} = {}) => {
|
||||
return {
|
||||
type: 'connection',
|
||||
agentNames,
|
||||
label,
|
||||
line,
|
||||
left,
|
||||
right,
|
||||
};
|
||||
},
|
||||
|
||||
note: (agentNames, {
|
||||
type = jasmine.anything(),
|
||||
mode = jasmine.anything(),
|
||||
label = jasmine.anything(),
|
||||
} = {}) => {
|
||||
return {
|
||||
type,
|
||||
agentNames,
|
||||
mode,
|
||||
label,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
describe('.generate', () => {
|
||||
it('propagates title metadata', () => {
|
||||
|
@ -28,7 +137,10 @@ defineDescribe('Sequence Generator', ['./Generator'], (Generator) => {
|
|||
|
||||
it('includes implicit hidden left/right agents', () => {
|
||||
const sequence = generator.generate({stages: []});
|
||||
expect(sequence.agents).toEqual(['[', ']']);
|
||||
expect(sequence.agents).toEqual([
|
||||
{name: '[', anchorRight: true},
|
||||
{name: ']', anchorRight: false},
|
||||
]);
|
||||
});
|
||||
|
||||
it('passes marks and async through', () => {
|
||||
|
@ -53,39 +165,54 @@ defineDescribe('Sequence Generator', ['./Generator'], (Generator) => {
|
|||
|
||||
it('returns aggregated agents', () => {
|
||||
const sequence = generator.generate({stages: [
|
||||
{type: '->', agents: [{name: 'A'}, {name: 'B'}]},
|
||||
{type: '<-', agents: [{name: 'C'}, {name: 'D'}]},
|
||||
{type: AGENT_BEGIN, agents: [{name: 'E'}], mode: 'box'},
|
||||
parsed.connect(['A', 'B']),
|
||||
parsed.connect(['C', 'D']),
|
||||
parsed.beginAgents(['E']),
|
||||
]});
|
||||
expect(sequence.agents).toEqual(
|
||||
['[', 'A', 'B', 'C', 'D', 'E', ']']
|
||||
);
|
||||
expect(sequence.agents).toEqual([
|
||||
{name: '[', anchorRight: true},
|
||||
{name: 'A', anchorRight: false},
|
||||
{name: 'B', anchorRight: false},
|
||||
{name: 'C', anchorRight: false},
|
||||
{name: 'D', anchorRight: false},
|
||||
{name: 'E', anchorRight: false},
|
||||
{name: ']', anchorRight: false},
|
||||
]);
|
||||
});
|
||||
|
||||
it('always puts the implicit right agent on the right', () => {
|
||||
const sequence = generator.generate({stages: [
|
||||
{type: '->', agents: [{name: ']'}, {name: 'B'}]},
|
||||
parsed.connect([']', 'B']),
|
||||
]});
|
||||
expect(sequence.agents).toEqual(['[', 'B', ']']);
|
||||
expect(sequence.agents).toEqual([
|
||||
{name: '[', anchorRight: true},
|
||||
{name: 'B', anchorRight: false},
|
||||
{name: ']', anchorRight: false},
|
||||
]);
|
||||
});
|
||||
|
||||
it('accounts for define calls when ordering agents', () => {
|
||||
const sequence = generator.generate({stages: [
|
||||
{type: AGENT_DEFINE, agents: [{name: 'B'}]},
|
||||
{type: '->', agents: [{name: 'A'}, {name: 'B'}]},
|
||||
parsed.defineAgents(['B']),
|
||||
parsed.connect(['A', 'B']),
|
||||
]});
|
||||
expect(sequence.agents).toEqual(['[', 'B', 'A', ']']);
|
||||
expect(sequence.agents).toEqual([
|
||||
{name: '[', anchorRight: true},
|
||||
{name: 'B', anchorRight: false},
|
||||
{name: 'A', anchorRight: false},
|
||||
{name: ']', anchorRight: false},
|
||||
]);
|
||||
});
|
||||
|
||||
it('creates implicit begin stages for agents when used', () => {
|
||||
const sequence = generator.generate({stages: [
|
||||
{type: '->', agents: [{name: 'A'}, {name: 'B'}]},
|
||||
{type: '->', agents: [{name: 'B'}, {name: 'C'}]},
|
||||
parsed.connect(['A', 'B']),
|
||||
parsed.connect(['B', 'C']),
|
||||
]});
|
||||
expect(sequence.stages).toEqual([
|
||||
{type: AGENT_BEGIN, agents: ['A', 'B'], mode: 'box'},
|
||||
generated.beginAgents(['A', 'B']),
|
||||
jasmine.anything(),
|
||||
{type: AGENT_BEGIN, agents: ['C'], mode: 'box'},
|
||||
generated.beginAgents(['C']),
|
||||
jasmine.anything(),
|
||||
jasmine.anything(),
|
||||
]);
|
||||
|
@ -93,11 +220,32 @@ defineDescribe('Sequence Generator', ['./Generator'], (Generator) => {
|
|||
|
||||
it('passes connections through', () => {
|
||||
const sequence = generator.generate({stages: [
|
||||
{type: '->', agents: [{name: 'A'}, {name: 'B'}]},
|
||||
parsed.connect(['A', 'B']),
|
||||
]});
|
||||
expect(sequence.stages).toEqual([
|
||||
jasmine.anything(),
|
||||
{type: '->', agents: ['A', 'B']},
|
||||
generated.connect(['A', 'B']),
|
||||
jasmine.anything(),
|
||||
]);
|
||||
});
|
||||
|
||||
it('propagates connection information', () => {
|
||||
const sequence = generator.generate({stages: [
|
||||
parsed.connect(['A', 'B'], {
|
||||
label: 'foo',
|
||||
line: 'bar',
|
||||
left: true,
|
||||
right: false,
|
||||
}),
|
||||
]});
|
||||
expect(sequence.stages).toEqual([
|
||||
jasmine.anything(),
|
||||
generated.connect(['A', 'B'], {
|
||||
label: 'foo',
|
||||
line: 'bar',
|
||||
left: true,
|
||||
right: false,
|
||||
}),
|
||||
jasmine.anything(),
|
||||
]);
|
||||
});
|
||||
|
@ -108,189 +256,182 @@ defineDescribe('Sequence Generator', ['./Generator'], (Generator) => {
|
|||
terminators: 'foo',
|
||||
},
|
||||
stages: [
|
||||
{type: '->', agents: [{name: 'A'}, {name: 'B'}]},
|
||||
parsed.connect(['A', 'B']),
|
||||
],
|
||||
});
|
||||
expect(sequence.stages).toEqual([
|
||||
jasmine.anything(),
|
||||
jasmine.anything(),
|
||||
{type: AGENT_END, agents: ['A', 'B'], mode: 'foo'},
|
||||
generated.endAgents(['A', 'B'], {mode: 'foo'}),
|
||||
]);
|
||||
});
|
||||
|
||||
it('defaults to mode "none" for implicit end stages', () => {
|
||||
const sequence = generator.generate({stages: [
|
||||
parsed.connect(['A', 'B']),
|
||||
]});
|
||||
expect(sequence.stages).toEqual([
|
||||
jasmine.anything(),
|
||||
jasmine.anything(),
|
||||
generated.endAgents(['A', 'B'], {mode: 'none'}),
|
||||
]);
|
||||
});
|
||||
|
||||
it('defaults to mode "cross" for explicit end stages', () => {
|
||||
const sequence = generator.generate({stages: [
|
||||
parsed.connect(['A', 'B']),
|
||||
parsed.endAgents(['A', 'B']),
|
||||
]});
|
||||
expect(sequence.stages).toEqual([
|
||||
jasmine.anything(),
|
||||
jasmine.anything(),
|
||||
generated.endAgents(['A', 'B'], {mode: 'cross'}),
|
||||
]);
|
||||
});
|
||||
|
||||
it('does not create duplicate begin stages', () => {
|
||||
const sequence = generator.generate({stages: [
|
||||
{type: AGENT_BEGIN, agents: [
|
||||
{name: 'A'},
|
||||
{name: 'B'},
|
||||
{name: 'C'},
|
||||
], mode: 'box'},
|
||||
{type: '->', agents: [{name: 'A'}, {name: 'B'}]},
|
||||
{type: '->', agents: [{name: 'B'}, {name: 'C'}]},
|
||||
parsed.beginAgents(['A', 'B', 'C']),
|
||||
parsed.connect(['A', 'B']),
|
||||
parsed.connect(['B', 'C']),
|
||||
]});
|
||||
expect(sequence.stages).toEqual([
|
||||
{type: AGENT_BEGIN, agents: ['A', 'B', 'C'], mode: 'box'},
|
||||
{type: '->', agents: jasmine.anything()},
|
||||
{type: '->', agents: jasmine.anything()},
|
||||
{type: AGENT_END, agents: ['A', 'B', 'C'], mode: 'none'},
|
||||
generated.beginAgents(['A', 'B', 'C']),
|
||||
generated.connect(jasmine.anything()),
|
||||
generated.connect(jasmine.anything()),
|
||||
generated.endAgents(['A', 'B', 'C']),
|
||||
]);
|
||||
});
|
||||
|
||||
it('redisplays agents if they have been hidden', () => {
|
||||
const sequence = generator.generate({stages: [
|
||||
{type: AGENT_BEGIN, agents: [
|
||||
{name: 'A'},
|
||||
{name: 'B'},
|
||||
], mode: 'box'},
|
||||
{type: '->', agents: [{name: 'A'}, {name: 'B'}]},
|
||||
{type: AGENT_END, agents: [{name: 'B'}], mode: 'cross'},
|
||||
{type: '->', agents: [{name: 'A'}, {name: 'B'}]},
|
||||
parsed.beginAgents(['A', 'B']),
|
||||
parsed.connect(['A', 'B']),
|
||||
parsed.endAgents(['B']),
|
||||
parsed.connect(['A', 'B']),
|
||||
]});
|
||||
expect(sequence.stages).toEqual([
|
||||
{type: AGENT_BEGIN, agents: ['A', 'B'], mode: 'box'},
|
||||
jasmine.anything(),
|
||||
{type: AGENT_END, agents: ['B'], mode: 'cross'},
|
||||
{type: AGENT_BEGIN, agents: ['B'], mode: 'box'},
|
||||
jasmine.anything(),
|
||||
{type: AGENT_END, agents: ['A', 'B'], mode: 'none'},
|
||||
generated.endAgents(['B']),
|
||||
generated.beginAgents(['B']),
|
||||
jasmine.anything(),
|
||||
jasmine.anything(),
|
||||
]);
|
||||
});
|
||||
|
||||
it('collapses adjacent begin statements', () => {
|
||||
const sequence = generator.generate({stages: [
|
||||
{type: '->', agents: [{name: 'A'}, {name: 'B'}]},
|
||||
{type: AGENT_BEGIN, agents: [{name: 'D'}], mode: 'box'},
|
||||
{type: '->', agents: [{name: 'B'}, {name: 'C'}]},
|
||||
{type: '->', agents: [{name: 'C'}, {name: 'D'}]},
|
||||
parsed.connect(['A', 'B']),
|
||||
parsed.beginAgents(['D']),
|
||||
parsed.connect(['B', 'C']),
|
||||
parsed.connect(['C', 'D']),
|
||||
]});
|
||||
expect(sequence.stages).toEqual([
|
||||
{type: AGENT_BEGIN, agents: ['A', 'B'], mode: 'box'},
|
||||
{type: '->', agents: jasmine.anything()},
|
||||
{type: AGENT_BEGIN, agents: ['D', 'C'], mode: 'box'},
|
||||
{type: '->', agents: jasmine.anything()},
|
||||
{type: '->', agents: jasmine.anything()},
|
||||
generated.beginAgents(['A', 'B']),
|
||||
generated.connect(jasmine.anything()),
|
||||
generated.beginAgents(['D', 'C']),
|
||||
generated.connect(jasmine.anything()),
|
||||
generated.connect(jasmine.anything()),
|
||||
jasmine.anything(),
|
||||
]);
|
||||
});
|
||||
|
||||
it('removes superfluous begin statements', () => {
|
||||
const sequence = generator.generate({stages: [
|
||||
{type: '->', agents: [{name: 'A'}, {name: 'B'}]},
|
||||
{type: AGENT_BEGIN, agents: [
|
||||
{name: 'A'},
|
||||
{name: 'C'},
|
||||
{name: 'D'},
|
||||
], mode: 'box'},
|
||||
{type: AGENT_BEGIN, agents: [
|
||||
{name: 'C'},
|
||||
{name: 'E'},
|
||||
], mode: 'box'},
|
||||
parsed.connect(['A', 'B']),
|
||||
parsed.beginAgents(['A', 'C', 'D']),
|
||||
parsed.beginAgents(['C', 'E']),
|
||||
]});
|
||||
expect(sequence.stages).toEqual([
|
||||
{type: AGENT_BEGIN, agents: ['A', 'B'], mode: 'box'},
|
||||
{type: '->', agents: jasmine.anything()},
|
||||
{type: AGENT_BEGIN, agents: ['C', 'D', 'E'], mode: 'box'},
|
||||
generated.beginAgents(['A', 'B']),
|
||||
generated.connect(jasmine.anything()),
|
||||
generated.beginAgents(['C', 'D', 'E']),
|
||||
jasmine.anything(),
|
||||
]);
|
||||
});
|
||||
|
||||
it('removes superfluous end statements', () => {
|
||||
const sequence = generator.generate({stages: [
|
||||
{type: AGENT_DEFINE, agents: [{name: 'E'}]},
|
||||
{type: AGENT_BEGIN, agents: [
|
||||
{name: 'C'},
|
||||
{name: 'D'},
|
||||
], mode: 'box'},
|
||||
{type: '->', agents: [{name: 'A'}, {name: 'B'}]},
|
||||
{type: AGENT_END, agents: [
|
||||
{name: 'A'},
|
||||
{name: 'B'},
|
||||
{name: 'C'},
|
||||
], mode: 'cross'},
|
||||
{type: AGENT_END, agents: [
|
||||
{name: 'A'},
|
||||
{name: 'D'},
|
||||
{name: 'E'},
|
||||
], mode: 'cross'},
|
||||
parsed.defineAgents(['E']),
|
||||
parsed.beginAgents(['C', 'D']),
|
||||
parsed.connect(['A', 'B']),
|
||||
parsed.endAgents(['A', 'B', 'C']),
|
||||
parsed.endAgents(['A', 'D', 'E']),
|
||||
]});
|
||||
expect(sequence.stages).toEqual([
|
||||
jasmine.anything(),
|
||||
{type: '->', agents: jasmine.anything()},
|
||||
{type: AGENT_END, agents: ['A', 'B', 'C', 'D'], mode: 'cross'},
|
||||
generated.connect(jasmine.anything()),
|
||||
generated.endAgents(['A', 'B', 'C', 'D']),
|
||||
]);
|
||||
});
|
||||
|
||||
it('does not merge different modes of end', () => {
|
||||
const sequence = generator.generate({stages: [
|
||||
{type: AGENT_BEGIN, agents: [
|
||||
{name: 'C'},
|
||||
{name: 'D'},
|
||||
], mode: 'box'},
|
||||
{type: '->', agents: [
|
||||
{name: 'A'},
|
||||
{name: 'B'},
|
||||
]},
|
||||
{type: AGENT_END, agents: [
|
||||
{name: 'A'},
|
||||
{name: 'B'},
|
||||
{name: 'C'},
|
||||
], mode: 'cross'},
|
||||
parsed.beginAgents(['C', 'D']),
|
||||
parsed.connect(['A', 'B']),
|
||||
parsed.endAgents(['A', 'B', 'C']),
|
||||
]});
|
||||
expect(sequence.stages).toEqual([
|
||||
jasmine.anything(),
|
||||
{type: '->', agents: jasmine.anything()},
|
||||
{type: AGENT_END, agents: ['A', 'B', 'C'], mode: 'cross'},
|
||||
{type: AGENT_END, agents: ['D'], mode: 'none'},
|
||||
generated.connect(jasmine.anything()),
|
||||
generated.endAgents(['A', 'B', 'C'], {mode: 'cross'}),
|
||||
generated.endAgents(['D'], {mode: 'none'}),
|
||||
]);
|
||||
});
|
||||
|
||||
it('creates virtual agents for block statements', () => {
|
||||
const sequence = generator.generate({stages: [
|
||||
{type: BLOCK_BEGIN, mode: 'if', label: 'abc'},
|
||||
{type: '->', agents: [{name: 'A'}, {name: 'B'}]},
|
||||
{type: BLOCK_END},
|
||||
parsed.blockBegin('if', 'abc'),
|
||||
parsed.connect(['A', 'B']),
|
||||
parsed.blockEnd(),
|
||||
]});
|
||||
|
||||
expect(sequence.agents).toEqual(
|
||||
['[', '__BLOCK0[', 'A', 'B', '__BLOCK0]', ']']
|
||||
);
|
||||
expect(sequence.agents).toEqual([
|
||||
{name: '[', anchorRight: true},
|
||||
{name: '__BLOCK0[', anchorRight: true},
|
||||
{name: 'A', anchorRight: false},
|
||||
{name: 'B', anchorRight: false},
|
||||
{name: '__BLOCK0]', anchorRight: false},
|
||||
{name: ']', anchorRight: false},
|
||||
]);
|
||||
});
|
||||
|
||||
it('positions virtual block agents near involved agents', () => {
|
||||
const sequence = generator.generate({stages: [
|
||||
{type: '->', agents: [{name: 'A'}, {name: 'B'}]},
|
||||
{type: BLOCK_BEGIN, mode: 'if', label: 'abc'},
|
||||
{type: '->', agents: [{name: 'C'}, {name: 'D'}]},
|
||||
{type: BLOCK_BEGIN, mode: 'if', label: 'abc'},
|
||||
{type: '->', agents: [{name: 'E'}, {name: 'F'}]},
|
||||
{type: BLOCK_END},
|
||||
{type: BLOCK_END},
|
||||
{type: '->', agents: [{name: 'G'}, {name: 'H'}]},
|
||||
parsed.connect(['A', 'B']),
|
||||
parsed.blockBegin('if', 'abc'),
|
||||
parsed.connect(['C', 'D']),
|
||||
parsed.blockBegin('if', 'abc'),
|
||||
parsed.connect(['E', 'F']),
|
||||
parsed.blockEnd(),
|
||||
parsed.blockEnd(),
|
||||
parsed.connect(['G', 'H']),
|
||||
]});
|
||||
|
||||
expect(sequence.agents).toEqual([
|
||||
'[',
|
||||
'A',
|
||||
'B',
|
||||
'__BLOCK0[',
|
||||
'C',
|
||||
'D',
|
||||
'__BLOCK1[',
|
||||
'E',
|
||||
'F',
|
||||
'__BLOCK1]',
|
||||
'__BLOCK0]',
|
||||
'G',
|
||||
'H',
|
||||
']',
|
||||
{name: '[', anchorRight: true},
|
||||
{name: 'A', anchorRight: false},
|
||||
{name: 'B', anchorRight: false},
|
||||
{name: '__BLOCK0[', anchorRight: true},
|
||||
{name: 'C', anchorRight: false},
|
||||
{name: 'D', anchorRight: false},
|
||||
{name: '__BLOCK1[', anchorRight: true},
|
||||
{name: 'E', anchorRight: false},
|
||||
{name: 'F', anchorRight: false},
|
||||
{name: '__BLOCK1]', anchorRight: false},
|
||||
{name: '__BLOCK0]', anchorRight: false},
|
||||
{name: 'G', anchorRight: false},
|
||||
{name: 'H', anchorRight: false},
|
||||
{name: ']', anchorRight: false},
|
||||
]);
|
||||
});
|
||||
|
||||
it('records virtual block agent names in blocks', () => {
|
||||
const sequence = generator.generate({stages: [
|
||||
{type: BLOCK_BEGIN, mode: 'if', label: 'abc'},
|
||||
{type: '->', agents: [{name: 'A'}, {name: 'B'}]},
|
||||
{type: BLOCK_END},
|
||||
parsed.blockBegin('if', 'abc'),
|
||||
parsed.connect(['A', 'B']),
|
||||
parsed.blockEnd(),
|
||||
]});
|
||||
|
||||
const block0 = sequence.stages[0];
|
||||
|
@ -301,47 +442,47 @@ defineDescribe('Sequence Generator', ['./Generator'], (Generator) => {
|
|||
|
||||
it('records all sections within blocks', () => {
|
||||
const sequence = generator.generate({stages: [
|
||||
{type: BLOCK_BEGIN, mode: 'if', label: 'abc'},
|
||||
{type: '->', agents: [{name: 'A'}, {name: 'B'}]},
|
||||
{type: BLOCK_SPLIT, mode: 'else', label: 'xyz'},
|
||||
{type: '->', agents: [{name: 'A'}, {name: 'C'}]},
|
||||
{type: BLOCK_END},
|
||||
parsed.blockBegin('if', 'abc'),
|
||||
parsed.connect(['A', 'B']),
|
||||
parsed.blockSplit('else', 'xyz'),
|
||||
parsed.connect(['A', 'C']),
|
||||
parsed.blockEnd(),
|
||||
]});
|
||||
|
||||
const block0 = sequence.stages[0];
|
||||
expect(block0.sections).toEqual([
|
||||
{mode: 'if', label: 'abc', stages: [
|
||||
{type: AGENT_BEGIN, agents: ['A', 'B'], mode: 'box'},
|
||||
{type: '->', agents: ['A', 'B']},
|
||||
generated.beginAgents(['A', 'B']),
|
||||
generated.connect(['A', 'B']),
|
||||
]},
|
||||
{mode: 'else', label: 'xyz', stages: [
|
||||
{type: AGENT_BEGIN, agents: ['C'], mode: 'box'},
|
||||
{type: '->', agents: ['A', 'C']},
|
||||
generated.beginAgents(['C']),
|
||||
generated.connect(['A', 'C']),
|
||||
]},
|
||||
]);
|
||||
});
|
||||
|
||||
it('records virtual block agents in nested blocks', () => {
|
||||
const sequence = generator.generate({stages: [
|
||||
{type: BLOCK_BEGIN, mode: 'if', label: 'abc'},
|
||||
{type: '->', agents: [{name: 'A'}, {name: 'B'}]},
|
||||
{type: BLOCK_SPLIT, mode: 'else', label: 'xyz'},
|
||||
{type: BLOCK_BEGIN, mode: 'if', label: 'def'},
|
||||
{type: '->', agents: [{name: 'A'}, {name: 'C'}]},
|
||||
{type: BLOCK_END},
|
||||
{type: BLOCK_END},
|
||||
parsed.blockBegin('if', 'abc'),
|
||||
parsed.connect(['A', 'B']),
|
||||
parsed.blockSplit('else', 'xyz'),
|
||||
parsed.blockBegin('if', 'def'),
|
||||
parsed.connect(['A', 'C']),
|
||||
parsed.blockEnd(),
|
||||
parsed.blockEnd(),
|
||||
]});
|
||||
|
||||
expect(sequence.agents).toEqual([
|
||||
'[',
|
||||
'__BLOCK0[',
|
||||
'__BLOCK1[',
|
||||
'A',
|
||||
'B',
|
||||
'C',
|
||||
'__BLOCK1]',
|
||||
'__BLOCK0]',
|
||||
']',
|
||||
{name: '[', anchorRight: true},
|
||||
{name: '__BLOCK0[', anchorRight: true},
|
||||
{name: '__BLOCK1[', anchorRight: true},
|
||||
{name: 'A', anchorRight: false},
|
||||
{name: 'B', anchorRight: false},
|
||||
{name: 'C', anchorRight: false},
|
||||
{name: '__BLOCK1]', anchorRight: false},
|
||||
{name: '__BLOCK0]', anchorRight: false},
|
||||
{name: ']', anchorRight: false},
|
||||
]);
|
||||
const block0 = sequence.stages[0];
|
||||
expect(block0.type).toEqual('block');
|
||||
|
@ -356,23 +497,23 @@ defineDescribe('Sequence Generator', ['./Generator'], (Generator) => {
|
|||
|
||||
it('preserves block boundaries when agents exist outside', () => {
|
||||
const sequence = generator.generate({stages: [
|
||||
{type: '->', agents: [{name: 'A'}, {name: 'B'}]},
|
||||
{type: BLOCK_BEGIN, mode: 'if', label: 'abc'},
|
||||
{type: BLOCK_BEGIN, mode: 'if', label: 'def'},
|
||||
{type: '->', agents: [{name: 'A'}, {name: 'B'}]},
|
||||
{type: BLOCK_END},
|
||||
{type: BLOCK_END},
|
||||
parsed.connect(['A', 'B']),
|
||||
parsed.blockBegin('if', 'abc'),
|
||||
parsed.blockBegin('if', 'def'),
|
||||
parsed.connect(['A', 'B']),
|
||||
parsed.blockEnd(),
|
||||
parsed.blockEnd(),
|
||||
]});
|
||||
|
||||
expect(sequence.agents).toEqual([
|
||||
'[',
|
||||
'__BLOCK0[',
|
||||
'__BLOCK1[',
|
||||
'A',
|
||||
'B',
|
||||
'__BLOCK1]',
|
||||
'__BLOCK0]',
|
||||
']',
|
||||
{name: '[', anchorRight: true},
|
||||
{name: '__BLOCK0[', anchorRight: true},
|
||||
{name: '__BLOCK1[', anchorRight: true},
|
||||
{name: 'A', anchorRight: false},
|
||||
{name: 'B', anchorRight: false},
|
||||
{name: '__BLOCK1]', anchorRight: false},
|
||||
{name: '__BLOCK0]', anchorRight: false},
|
||||
{name: ']', anchorRight: false},
|
||||
]);
|
||||
const block0 = sequence.stages[2];
|
||||
expect(block0.type).toEqual('block');
|
||||
|
@ -387,10 +528,10 @@ defineDescribe('Sequence Generator', ['./Generator'], (Generator) => {
|
|||
|
||||
it('allows empty block parts after split', () => {
|
||||
const sequence = generator.generate({stages: [
|
||||
{type: BLOCK_BEGIN, mode: 'if', label: 'abc'},
|
||||
{type: '->', agents: [{name: 'A'}, {name: 'B'}]},
|
||||
{type: BLOCK_SPLIT, mode: 'else', label: 'xyz'},
|
||||
{type: BLOCK_END},
|
||||
parsed.blockBegin('if', 'abc'),
|
||||
parsed.connect(['A', 'B']),
|
||||
parsed.blockSplit('else', 'xyz'),
|
||||
parsed.blockEnd(),
|
||||
]});
|
||||
|
||||
const block0 = sequence.stages[0];
|
||||
|
@ -405,10 +546,10 @@ defineDescribe('Sequence Generator', ['./Generator'], (Generator) => {
|
|||
|
||||
it('allows empty block parts before split', () => {
|
||||
const sequence = generator.generate({stages: [
|
||||
{type: BLOCK_BEGIN, mode: 'if', label: 'abc'},
|
||||
{type: BLOCK_SPLIT, mode: 'else', label: 'xyz'},
|
||||
{type: '->', agents: [{name: 'A'}, {name: 'B'}]},
|
||||
{type: BLOCK_END},
|
||||
parsed.blockBegin('if', 'abc'),
|
||||
parsed.blockSplit('else', 'xyz'),
|
||||
parsed.connect(['A', 'B']),
|
||||
parsed.blockEnd(),
|
||||
]});
|
||||
|
||||
const block0 = sequence.stages[0];
|
||||
|
@ -423,11 +564,11 @@ defineDescribe('Sequence Generator', ['./Generator'], (Generator) => {
|
|||
|
||||
it('removes entirely empty blocks', () => {
|
||||
const sequence = generator.generate({stages: [
|
||||
{type: BLOCK_BEGIN, mode: 'if', label: 'abc'},
|
||||
{type: BLOCK_SPLIT, mode: 'else', label: 'xyz'},
|
||||
{type: BLOCK_BEGIN, mode: 'if', label: 'abc'},
|
||||
{type: BLOCK_END},
|
||||
{type: BLOCK_END},
|
||||
parsed.blockBegin('if', 'abc'),
|
||||
parsed.blockSplit('else', 'xyz'),
|
||||
parsed.blockBegin('if', 'abc'),
|
||||
parsed.blockEnd(),
|
||||
parsed.blockEnd(),
|
||||
]});
|
||||
|
||||
expect(sequence.stages).toEqual([]);
|
||||
|
@ -435,10 +576,10 @@ defineDescribe('Sequence Generator', ['./Generator'], (Generator) => {
|
|||
|
||||
it('removes blocks containing only define statements / markers', () => {
|
||||
const sequence = generator.generate({stages: [
|
||||
{type: BLOCK_BEGIN, mode: 'if', label: 'abc'},
|
||||
{type: AGENT_DEFINE, agents: [{name: 'A'}]},
|
||||
parsed.blockBegin('if', 'abc'),
|
||||
parsed.defineAgents(['A']),
|
||||
{type: 'mark', name: 'foo'},
|
||||
{type: BLOCK_END},
|
||||
parsed.blockEnd(),
|
||||
]});
|
||||
|
||||
expect(sequence.stages).toEqual([]);
|
||||
|
@ -446,24 +587,27 @@ defineDescribe('Sequence Generator', ['./Generator'], (Generator) => {
|
|||
|
||||
it('does not create virtual agents for empty blocks', () => {
|
||||
const sequence = generator.generate({stages: [
|
||||
{type: BLOCK_BEGIN, mode: 'if', label: 'abc'},
|
||||
{type: BLOCK_SPLIT, mode: 'else', label: 'xyz'},
|
||||
{type: BLOCK_BEGIN, mode: 'if', label: 'abc'},
|
||||
{type: BLOCK_END},
|
||||
{type: BLOCK_END},
|
||||
parsed.blockBegin('if', 'abc'),
|
||||
parsed.blockSplit('else', 'xyz'),
|
||||
parsed.blockBegin('if', 'abc'),
|
||||
parsed.blockEnd(),
|
||||
parsed.blockEnd(),
|
||||
]});
|
||||
|
||||
expect(sequence.agents).toEqual(['[', ']']);
|
||||
expect(sequence.agents).toEqual([
|
||||
{name: '[', anchorRight: true},
|
||||
{name: ']', anchorRight: false},
|
||||
]);
|
||||
});
|
||||
|
||||
it('removes entirely empty nested blocks', () => {
|
||||
const sequence = generator.generate({stages: [
|
||||
{type: BLOCK_BEGIN, mode: 'if', label: 'abc'},
|
||||
{type: '->', agents: [{name: 'A'}, {name: 'B'}]},
|
||||
{type: BLOCK_SPLIT, mode: 'else', label: 'xyz'},
|
||||
{type: BLOCK_BEGIN, mode: 'if', label: 'abc'},
|
||||
{type: BLOCK_END},
|
||||
{type: BLOCK_END},
|
||||
parsed.blockBegin('if', 'abc'),
|
||||
parsed.connect(['A', 'B']),
|
||||
parsed.blockSplit('else', 'xyz'),
|
||||
parsed.blockBegin('if', 'abc'),
|
||||
parsed.blockEnd(),
|
||||
parsed.blockEnd(),
|
||||
]});
|
||||
|
||||
const block0 = sequence.stages[0];
|
||||
|
@ -478,83 +622,100 @@ defineDescribe('Sequence Generator', ['./Generator'], (Generator) => {
|
|||
|
||||
it('rejects unterminated blocks', () => {
|
||||
expect(() => generator.generate({stages: [
|
||||
{type: BLOCK_BEGIN, mode: 'if', label: 'abc'},
|
||||
{type: '->', agents: [{name: 'A'}, {name: 'B'}]},
|
||||
parsed.blockBegin('if', 'abc'),
|
||||
parsed.connect(['A', 'B']),
|
||||
]})).toThrow();
|
||||
|
||||
expect(() => generator.generate({stages: [
|
||||
{type: BLOCK_BEGIN, mode: 'if', label: 'abc'},
|
||||
{type: BLOCK_BEGIN, mode: 'if', label: 'def'},
|
||||
{type: '->', agents: [{name: 'A'}, {name: 'B'}]},
|
||||
{type: BLOCK_END},
|
||||
parsed.blockBegin('if', 'abc'),
|
||||
parsed.blockBegin('if', 'def'),
|
||||
parsed.connect(['A', 'B']),
|
||||
parsed.blockEnd(),
|
||||
]})).toThrow();
|
||||
});
|
||||
|
||||
it('rejects extra block terminations', () => {
|
||||
expect(() => generator.generate({stages: [
|
||||
{type: BLOCK_END},
|
||||
parsed.blockEnd(),
|
||||
]})).toThrow();
|
||||
|
||||
expect(() => generator.generate({stages: [
|
||||
{type: BLOCK_BEGIN, mode: 'if', label: 'abc'},
|
||||
{type: '->', agents: [{name: 'A'}, {name: 'B'}]},
|
||||
{type: BLOCK_END},
|
||||
{type: BLOCK_END},
|
||||
parsed.blockBegin('if', 'abc'),
|
||||
parsed.connect(['A', 'B']),
|
||||
parsed.blockEnd(),
|
||||
parsed.blockEnd(),
|
||||
]})).toThrow();
|
||||
});
|
||||
|
||||
it('rejects block splitting without a block', () => {
|
||||
expect(() => generator.generate({stages: [
|
||||
{type: BLOCK_SPLIT, mode: 'else', label: 'xyz'},
|
||||
parsed.blockSplit('else', 'xyz'),
|
||||
]})).toThrow();
|
||||
|
||||
expect(() => generator.generate({stages: [
|
||||
{type: BLOCK_BEGIN, mode: 'if', label: 'abc'},
|
||||
{type: '->', agents: [{name: 'A'}, {name: 'B'}]},
|
||||
{type: BLOCK_END},
|
||||
{type: BLOCK_SPLIT, mode: 'else', label: 'xyz'},
|
||||
parsed.blockBegin('if', 'abc'),
|
||||
parsed.connect(['A', 'B']),
|
||||
parsed.blockEnd(),
|
||||
parsed.blockSplit('else', 'xyz'),
|
||||
]})).toThrow();
|
||||
});
|
||||
|
||||
it('rejects block splitting in non-splittable blocks', () => {
|
||||
expect(() => generator.generate({stages: [
|
||||
{type: BLOCK_BEGIN, mode: 'repeat', label: 'abc'},
|
||||
{type: BLOCK_SPLIT, mode: 'else', label: 'xyz'},
|
||||
{type: '->', agents: [{name: 'A'}, {name: 'B'}]},
|
||||
{type: BLOCK_END},
|
||||
parsed.blockBegin('repeat', 'abc'),
|
||||
parsed.blockSplit('else', 'xyz'),
|
||||
parsed.connect(['A', 'B']),
|
||||
parsed.blockEnd(),
|
||||
]})).toThrow();
|
||||
});
|
||||
|
||||
it('passes notes through', () => {
|
||||
const sequence = generator.generate({stages: [
|
||||
parsed.note(['A', 'B'], {
|
||||
type: 'note right',
|
||||
mode: 'foo',
|
||||
label: 'bar',
|
||||
}),
|
||||
]});
|
||||
expect(sequence.stages).toEqual([
|
||||
jasmine.anything(),
|
||||
generated.note(['A', 'B'], {
|
||||
type: 'note right',
|
||||
mode: 'foo',
|
||||
label: 'bar',
|
||||
}),
|
||||
jasmine.anything(),
|
||||
]);
|
||||
});
|
||||
|
||||
it('defaults to showing notes around the entire diagram', () => {
|
||||
const sequence = generator.generate({stages: [
|
||||
{type: 'note right', agents: [], foo: 'bar'},
|
||||
{type: 'note left', agents: [], foo: 'bar'},
|
||||
{type: 'note over', agents: [], foo: 'bar'},
|
||||
{type: 'note right', agents: [{name: '['}], foo: 'bar'},
|
||||
parsed.note([], {type: 'note right'}),
|
||||
parsed.note([], {type: 'note left'}),
|
||||
parsed.note([], {type: 'note over'}),
|
||||
]});
|
||||
expect(sequence.stages).toEqual([
|
||||
{type: 'note right', agents: [']'], foo: 'bar'},
|
||||
{type: 'note left', agents: ['['], foo: 'bar'},
|
||||
{type: 'note over', agents: ['[', ']'], foo: 'bar'},
|
||||
{type: 'note right', agents: ['['], foo: 'bar'},
|
||||
generated.note([']'], {type: 'note right'}),
|
||||
generated.note(['['], {type: 'note left'}),
|
||||
generated.note(['[', ']'], {type: 'note over'}),
|
||||
]);
|
||||
});
|
||||
|
||||
it('rejects attempts to change implicit agents', () => {
|
||||
expect(() => generator.generate({stages: [
|
||||
{type: AGENT_BEGIN, agents: [{name: '['}], mode: 'box'},
|
||||
parsed.beginAgents(['[']),
|
||||
]})).toThrow();
|
||||
|
||||
expect(() => generator.generate({stages: [
|
||||
{type: AGENT_BEGIN, agents: [{name: ']'}], mode: 'box'},
|
||||
parsed.beginAgents([']']),
|
||||
]})).toThrow();
|
||||
|
||||
expect(() => generator.generate({stages: [
|
||||
{type: AGENT_END, agents: [{name: '['}], mode: 'cross'},
|
||||
parsed.endAgents(['[']),
|
||||
]})).toThrow();
|
||||
|
||||
expect(() => generator.generate({stages: [
|
||||
{type: AGENT_END, agents: [{name: ']'}], mode: 'cross'},
|
||||
parsed.endAgents([']']),
|
||||
]})).toThrow();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -140,11 +140,11 @@ define([
|
|||
this.sizer = new this.SVGTextBlockClass.SizeTester(this.base);
|
||||
}
|
||||
|
||||
findExtremes(agents) {
|
||||
findExtremes(agentNames) {
|
||||
let min = null;
|
||||
let max = null;
|
||||
agents.forEach((agent) => {
|
||||
const info = this.agentInfos.get(agent);
|
||||
agentNames.forEach((name) => {
|
||||
const info = this.agentInfos.get(name);
|
||||
if(min === null || info.index < min.index) {
|
||||
min = info;
|
||||
}
|
||||
|
@ -158,32 +158,32 @@ define([
|
|||
};
|
||||
}
|
||||
|
||||
addSeparation(agent1, agent2, dist) {
|
||||
const info1 = this.agentInfos.get(agent1);
|
||||
const info2 = this.agentInfos.get(agent2);
|
||||
addSeparation(agentName1, agentName2, dist) {
|
||||
const info1 = this.agentInfos.get(agentName1);
|
||||
const info2 = this.agentInfos.get(agentName2);
|
||||
|
||||
const d1 = info1.separations.get(agent2) || 0;
|
||||
info1.separations.set(agent2, Math.max(d1, dist));
|
||||
const d1 = info1.separations.get(agentName2) || 0;
|
||||
info1.separations.set(agentName2, Math.max(d1, dist));
|
||||
|
||||
const d2 = info2.separations.get(agent1) || 0;
|
||||
info2.separations.set(agent1, Math.max(d2, dist));
|
||||
const d2 = info2.separations.get(agentName1) || 0;
|
||||
info2.separations.set(agentName1, Math.max(d2, dist));
|
||||
}
|
||||
|
||||
addSeparations(agents, agentSpaces) {
|
||||
agents.forEach((agentR) => {
|
||||
const infoR = this.agentInfos.get(agentR);
|
||||
const sepR = agentSpaces.get(agentR) || SEP_ZERO;
|
||||
addSeparations(agentNames, agentSpaces) {
|
||||
agentNames.forEach((agentNameR) => {
|
||||
const infoR = this.agentInfos.get(agentNameR);
|
||||
const sepR = agentSpaces.get(agentNameR) || SEP_ZERO;
|
||||
infoR.maxRPad = Math.max(infoR.maxRPad, sepR.right);
|
||||
infoR.maxLPad = Math.max(infoR.maxLPad, sepR.left);
|
||||
agents.forEach((agentL) => {
|
||||
const infoL = this.agentInfos.get(agentL);
|
||||
agentNames.forEach((agentNameL) => {
|
||||
const infoL = this.agentInfos.get(agentNameL);
|
||||
if(infoL.index >= infoR.index) {
|
||||
return;
|
||||
}
|
||||
const sepL = agentSpaces.get(agentL) || SEP_ZERO;
|
||||
const sepL = agentSpaces.get(agentNameL) || SEP_ZERO;
|
||||
this.addSeparation(
|
||||
agentR,
|
||||
agentL,
|
||||
agentNameR,
|
||||
agentNameL,
|
||||
sepR.left + sepL.right + this.theme.agentMargin
|
||||
);
|
||||
});
|
||||
|
@ -236,25 +236,25 @@ define([
|
|||
return {left: 0, right: 0};
|
||||
}
|
||||
|
||||
separationAgent({type, mode, agents}) {
|
||||
separationAgent({type, mode, agentNames}) {
|
||||
if(type === 'agent begin') {
|
||||
array.mergeSets(this.visibleAgents, agents);
|
||||
array.mergeSets(this.visibleAgents, agentNames);
|
||||
}
|
||||
|
||||
const agentSpaces = new Map();
|
||||
agents.forEach((agent) => {
|
||||
const info = this.agentInfos.get(agent);
|
||||
agentNames.forEach((name) => {
|
||||
const info = this.agentInfos.get(name);
|
||||
const separationFn = this.separationAgentCap[mode];
|
||||
agentSpaces.set(agent, separationFn(info));
|
||||
agentSpaces.set(name, separationFn(info));
|
||||
});
|
||||
this.addSeparations(this.visibleAgents, agentSpaces);
|
||||
|
||||
if(type === 'agent end') {
|
||||
array.removeAll(this.visibleAgents, agents);
|
||||
array.removeAll(this.visibleAgents, agentNames);
|
||||
}
|
||||
}
|
||||
|
||||
separationConnection({agents, label}) {
|
||||
separationConnection({agentNames, label}) {
|
||||
const config = this.theme.connect;
|
||||
|
||||
const labelWidth = (
|
||||
|
@ -263,9 +263,9 @@ define([
|
|||
);
|
||||
const strokeWidth = this.theme.agentLineAttrs['stroke-width'];
|
||||
|
||||
if(agents[0] === agents[1]) {
|
||||
if(agentNames[0] === agentNames[1]) {
|
||||
const agentSpaces = new Map();
|
||||
agentSpaces.set(agents[0], {
|
||||
agentSpaces.set(agentNames[0], {
|
||||
left: 0,
|
||||
right: (
|
||||
labelWidth +
|
||||
|
@ -277,14 +277,14 @@ define([
|
|||
this.addSeparations(this.visibleAgents, agentSpaces);
|
||||
} else {
|
||||
this.addSeparation(
|
||||
agents[0],
|
||||
agents[1],
|
||||
agentNames[0],
|
||||
agentNames[1],
|
||||
labelWidth + config.arrow.width * 2 + strokeWidth
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
separationNoteOver({agents, mode, label}) {
|
||||
separationNoteOver({agentNames, mode, label}) {
|
||||
const config = this.theme.note[mode];
|
||||
const width = (
|
||||
this.sizer.measure(config.labelAttrs, label).width +
|
||||
|
@ -293,8 +293,8 @@ define([
|
|||
);
|
||||
|
||||
const agentSpaces = new Map();
|
||||
if(agents.length > 1) {
|
||||
const {left, right} = this.findExtremes(agents);
|
||||
if(agentNames.length > 1) {
|
||||
const {left, right} = this.findExtremes(agentNames);
|
||||
|
||||
this.addSeparation(
|
||||
left,
|
||||
|
@ -308,7 +308,7 @@ define([
|
|||
agentSpaces.set(left, {left: config.overlap.left, right: 0});
|
||||
agentSpaces.set(right, {left: 0, right: config.overlap.right});
|
||||
} else {
|
||||
agentSpaces.set(agents[0], {
|
||||
agentSpaces.set(agentNames[0], {
|
||||
left: width / 2,
|
||||
right: width / 2,
|
||||
});
|
||||
|
@ -316,9 +316,9 @@ define([
|
|||
this.addSeparations(this.visibleAgents, agentSpaces);
|
||||
}
|
||||
|
||||
separationNoteSide(isRight, {agents, mode, label}) {
|
||||
separationNoteSide(isRight, {agentNames, mode, label}) {
|
||||
const config = this.theme.note[mode];
|
||||
const {left, right} = this.findExtremes(agents);
|
||||
const {left, right} = this.findExtremes(agentNames);
|
||||
const width = (
|
||||
this.sizer.measure(config.labelAttrs, label).width +
|
||||
config.padding.left +
|
||||
|
@ -336,9 +336,9 @@ define([
|
|||
this.addSeparations(this.visibleAgents, agentSpaces);
|
||||
}
|
||||
|
||||
separationNoteBetween({agents, mode, label}) {
|
||||
separationNoteBetween({agentNames, mode, label}) {
|
||||
const config = this.theme.note[mode];
|
||||
const {left, right} = this.findExtremes(agents);
|
||||
const {left, right} = this.findExtremes(agentNames);
|
||||
|
||||
this.addSeparation(
|
||||
left,
|
||||
|
@ -462,8 +462,8 @@ define([
|
|||
};
|
||||
}
|
||||
|
||||
checkAgentRange(agents) {
|
||||
const {left, right} = this.findExtremes(agents);
|
||||
checkAgentRange(agentNames) {
|
||||
const {left, right} = this.findExtremes(agentNames);
|
||||
const leftX = this.agentInfos.get(left).x;
|
||||
const rightX = this.agentInfos.get(right).x;
|
||||
this.agentInfos.forEach((agentInfo) => {
|
||||
|
@ -473,8 +473,8 @@ define([
|
|||
});
|
||||
}
|
||||
|
||||
markAgentRange(agents) {
|
||||
const {left, right} = this.findExtremes(agents);
|
||||
markAgentRange(agentNames) {
|
||||
const {left, right} = this.findExtremes(agentNames);
|
||||
const leftX = this.agentInfos.get(left).x;
|
||||
const rightX = this.agentInfos.get(right).x;
|
||||
this.agentInfos.forEach((agentInfo) => {
|
||||
|
@ -484,24 +484,24 @@ define([
|
|||
});
|
||||
}
|
||||
|
||||
renderAgentBegin({mode, agents}) {
|
||||
this.checkAgentRange(agents);
|
||||
renderAgentBegin({mode, agentNames}) {
|
||||
this.checkAgentRange(agentNames);
|
||||
let maxHeight = 0;
|
||||
agents.forEach((agent) => {
|
||||
const agentInfo = this.agentInfos.get(agent);
|
||||
agentNames.forEach((name) => {
|
||||
const agentInfo = this.agentInfos.get(name);
|
||||
const shifts = this.renderAgentCap[mode](agentInfo);
|
||||
maxHeight = Math.max(maxHeight, shifts.height);
|
||||
agentInfo.latestYStart = this.currentY + shifts.lineBottom;
|
||||
});
|
||||
this.currentY += maxHeight + this.theme.actionMargin;
|
||||
this.markAgentRange(agents);
|
||||
this.markAgentRange(agentNames);
|
||||
}
|
||||
|
||||
renderAgentEnd({mode, agents}) {
|
||||
this.checkAgentRange(agents);
|
||||
renderAgentEnd({mode, agentNames}) {
|
||||
this.checkAgentRange(agentNames);
|
||||
let maxHeight = 0;
|
||||
agents.forEach((agent) => {
|
||||
const agentInfo = this.agentInfos.get(agent);
|
||||
agentNames.forEach((name) => {
|
||||
const agentInfo = this.agentInfos.get(name);
|
||||
const x = agentInfo.x;
|
||||
const shifts = this.renderAgentCap[mode](agentInfo);
|
||||
maxHeight = Math.max(maxHeight, shifts.height);
|
||||
|
@ -515,12 +515,12 @@ define([
|
|||
agentInfo.latestYStart = null;
|
||||
});
|
||||
this.currentY += maxHeight + this.theme.actionMargin;
|
||||
this.markAgentRange(agents);
|
||||
this.markAgentRange(agentNames);
|
||||
}
|
||||
|
||||
renderSelfConnection({label, agents, line, left, right}) {
|
||||
renderSelfConnection({label, agentNames, line, left, right}) {
|
||||
const config = this.theme.connect;
|
||||
const from = this.agentInfos.get(agents[0]);
|
||||
const from = this.agentInfos.get(agentNames[0]);
|
||||
|
||||
const dy = config.arrow.height / 2;
|
||||
const short = this.theme.agentLineAttrs['stroke-width'];
|
||||
|
@ -591,10 +591,10 @@ define([
|
|||
this.currentY = y1 + dy + this.theme.actionMargin;
|
||||
}
|
||||
|
||||
renderSimpleConnection({label, agents, line, left, right}) {
|
||||
renderSimpleConnection({label, agentNames, line, left, right}) {
|
||||
const config = this.theme.connect;
|
||||
const from = this.agentInfos.get(agents[0]);
|
||||
const to = this.agentInfos.get(agents[1]);
|
||||
const from = this.agentInfos.get(agentNames[0]);
|
||||
const to = this.agentInfos.get(agentNames[1]);
|
||||
|
||||
const dy = config.arrow.height / 2;
|
||||
const dir = (from.x < to.x) ? 1 : -1;
|
||||
|
@ -650,13 +650,13 @@ define([
|
|||
}
|
||||
|
||||
renderConnection(stage) {
|
||||
this.checkAgentRange(stage.agents);
|
||||
if(stage.agents[0] === stage.agents[1]) {
|
||||
this.checkAgentRange(stage.agentNames);
|
||||
if(stage.agentNames[0] === stage.agentNames[1]) {
|
||||
this.renderSelfConnection(stage);
|
||||
} else {
|
||||
this.renderSimpleConnection(stage);
|
||||
}
|
||||
this.markAgentRange(stage.agents);
|
||||
this.markAgentRange(stage.agentNames);
|
||||
}
|
||||
|
||||
renderNote({xMid = null, x0 = null, x1 = null}, anchor, mode, label) {
|
||||
|
@ -721,53 +721,53 @@ define([
|
|||
);
|
||||
}
|
||||
|
||||
renderNoteOver({agents, mode, label}) {
|
||||
this.checkAgentRange(agents);
|
||||
renderNoteOver({agentNames, mode, label}) {
|
||||
this.checkAgentRange(agentNames);
|
||||
const config = this.theme.note[mode];
|
||||
|
||||
if(agents.length > 1) {
|
||||
const {left, right} = this.findExtremes(agents);
|
||||
if(agentNames.length > 1) {
|
||||
const {left, right} = this.findExtremes(agentNames);
|
||||
this.renderNote({
|
||||
x0: this.agentInfos.get(left).x - config.overlap.left,
|
||||
x1: this.agentInfos.get(right).x + config.overlap.right,
|
||||
}, 'middle', mode, label);
|
||||
} else {
|
||||
const xMid = this.agentInfos.get(agents[0]).x;
|
||||
const xMid = this.agentInfos.get(agentNames[0]).x;
|
||||
this.renderNote({xMid}, 'middle', mode, label);
|
||||
}
|
||||
this.markAgentRange(agents);
|
||||
this.markAgentRange(agentNames);
|
||||
}
|
||||
|
||||
renderNoteLeft({agents, mode, label}) {
|
||||
this.checkAgentRange(agents);
|
||||
renderNoteLeft({agentNames, mode, label}) {
|
||||
this.checkAgentRange(agentNames);
|
||||
const config = this.theme.note[mode];
|
||||
|
||||
const {left} = this.findExtremes(agents);
|
||||
const {left} = this.findExtremes(agentNames);
|
||||
const x1 = this.agentInfos.get(left).x - config.margin.right;
|
||||
this.renderNote({x1}, 'end', mode, label);
|
||||
this.markAgentRange(agents);
|
||||
this.markAgentRange(agentNames);
|
||||
}
|
||||
|
||||
renderNoteRight({agents, mode, label}) {
|
||||
this.checkAgentRange(agents);
|
||||
renderNoteRight({agentNames, mode, label}) {
|
||||
this.checkAgentRange(agentNames);
|
||||
const config = this.theme.note[mode];
|
||||
|
||||
const {right} = this.findExtremes(agents);
|
||||
const {right} = this.findExtremes(agentNames);
|
||||
const x0 = this.agentInfos.get(right).x + config.margin.left;
|
||||
this.renderNote({x0}, 'start', mode, label);
|
||||
this.markAgentRange(agents);
|
||||
this.markAgentRange(agentNames);
|
||||
}
|
||||
|
||||
renderNoteBetween({agents, mode, label}) {
|
||||
this.checkAgentRange(agents);
|
||||
const {left, right} = this.findExtremes(agents);
|
||||
renderNoteBetween({agentNames, mode, label}) {
|
||||
this.checkAgentRange(agentNames);
|
||||
const {left, right} = this.findExtremes(agentNames);
|
||||
const xMid = (
|
||||
this.agentInfos.get(left).x +
|
||||
this.agentInfos.get(right).x
|
||||
) / 2;
|
||||
|
||||
this.renderNote({xMid}, 'middle', mode, label);
|
||||
this.markAgentRange(agents);
|
||||
this.markAgentRange(agentNames);
|
||||
}
|
||||
|
||||
renderBlockBegin(scope, {left, right}) {
|
||||
|
@ -891,9 +891,9 @@ define([
|
|||
buildAgentInfos(agents, stages) {
|
||||
this.agentInfos = new Map();
|
||||
agents.forEach((agent, index) => {
|
||||
this.agentInfos.set(agent, {
|
||||
label: agent,
|
||||
anchorRight: agent.endsWith('['),
|
||||
this.agentInfos.set(agent.name, {
|
||||
label: agent.name,
|
||||
anchorRight: agent.anchorRight,
|
||||
index,
|
||||
x: null,
|
||||
latestYStart: null,
|
||||
|
|
|
@ -25,13 +25,13 @@ defineDescribe('Sequence Renderer', [
|
|||
});
|
||||
});
|
||||
|
||||
function connectionStage(agents, label = '') {
|
||||
function connectionStage(agentNames, label = '') {
|
||||
return {
|
||||
type: 'connection',
|
||||
line: 'solid',
|
||||
left: false,
|
||||
right: true,
|
||||
agents,
|
||||
agentNames,
|
||||
label,
|
||||
};
|
||||
}
|
||||
|
@ -40,7 +40,12 @@ defineDescribe('Sequence Renderer', [
|
|||
it('populates the SVG with content', () => {
|
||||
renderer.render({
|
||||
meta: {title: 'Title'},
|
||||
agents: ['[', 'Col 1', 'Col 2', ']'],
|
||||
agents: [
|
||||
{name: '[', anchorRight: true},
|
||||
{name: 'Col 1', anchorRight: false},
|
||||
{name: 'Col 2', anchorRight: false},
|
||||
{name: ']', anchorRight: false},
|
||||
],
|
||||
stages: [],
|
||||
});
|
||||
const element = renderer.svg();
|
||||
|
@ -55,11 +60,16 @@ defineDescribe('Sequence Renderer', [
|
|||
|
||||
renderer.render({
|
||||
meta: {title: ''},
|
||||
agents: ['[', 'A', 'B', ']'],
|
||||
agents: [
|
||||
{name: '[', anchorRight: true},
|
||||
{name: 'A', anchorRight: false},
|
||||
{name: 'B', anchorRight: false},
|
||||
{name: ']', anchorRight: false},
|
||||
],
|
||||
stages: [
|
||||
{type: 'agent begin', agents: ['A', 'B'], mode: 'box'},
|
||||
{type: 'agent begin', agentNames: ['A', 'B'], mode: 'box'},
|
||||
connectionStage(['A', 'B']),
|
||||
{type: 'agent end', agents: ['A', 'B'], mode: 'none'},
|
||||
{type: 'agent end', agentNames: ['A', 'B'], mode: 'none'},
|
||||
],
|
||||
});
|
||||
|
||||
|
@ -80,14 +90,28 @@ defineDescribe('Sequence Renderer', [
|
|||
|
||||
renderer.render({
|
||||
meta: {title: ''},
|
||||
agents: ['[', 'A', 'B', 'C', ']'],
|
||||
agents: [
|
||||
{name: '[', anchorRight: true},
|
||||
{name: 'A', anchorRight: false},
|
||||
{name: 'B', anchorRight: false},
|
||||
{name: 'C', anchorRight: false},
|
||||
{name: ']', anchorRight: false},
|
||||
],
|
||||
stages: [
|
||||
{type: 'agent begin', agents: ['A', 'B', 'C'], mode: 'box'},
|
||||
{
|
||||
type: 'agent begin',
|
||||
agentNames: ['A', 'B', 'C'],
|
||||
mode: 'box',
|
||||
},
|
||||
connectionStage(['[', 'A']),
|
||||
connectionStage(['A', 'B']),
|
||||
connectionStage(['B', 'C']),
|
||||
connectionStage(['C', ']']),
|
||||
{type: 'agent end', agents: ['A', 'B', 'C'], mode: 'none'},
|
||||
{
|
||||
type: 'agent end',
|
||||
agentNames: ['A', 'B', 'C'],
|
||||
mode: 'none',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
|
@ -115,17 +139,24 @@ defineDescribe('Sequence Renderer', [
|
|||
|
||||
renderer.render({
|
||||
meta: {title: ''},
|
||||
agents: ['[', 'A', 'B', 'C', 'D', ']'],
|
||||
agents: [
|
||||
{name: '[', anchorRight: true},
|
||||
{name: 'A', anchorRight: false},
|
||||
{name: 'B', anchorRight: false},
|
||||
{name: 'C', anchorRight: false},
|
||||
{name: 'D', anchorRight: false},
|
||||
{name: ']', anchorRight: false},
|
||||
],
|
||||
stages: [
|
||||
{type: 'agent begin', agents: ['A', 'B'], mode: 'box'},
|
||||
{type: 'agent begin', agentNames: ['A', 'B'], mode: 'box'},
|
||||
connectionStage(['A', 'B'], 'short'),
|
||||
{type: 'agent end', agents: ['B'], mode: 'cross'},
|
||||
{type: 'agent begin', agents: ['C'], mode: 'box'},
|
||||
{type: 'agent end', agentNames: ['B'], mode: 'cross'},
|
||||
{type: 'agent begin', agentNames: ['C'], mode: 'box'},
|
||||
connectionStage(['A', 'C'], 'long description here'),
|
||||
{type: 'agent end', agents: ['C'], mode: 'cross'},
|
||||
{type: 'agent begin', agents: ['D'], mode: 'box'},
|
||||
{type: 'agent end', agentNames: ['C'], mode: 'cross'},
|
||||
{type: 'agent begin', agentNames: ['D'], mode: 'box'},
|
||||
connectionStage(['A', 'D'], 'short again'),
|
||||
{type: 'agent end', agents: ['A', 'D'], mode: 'cross'},
|
||||
{type: 'agent end', agentNames: ['A', 'D'], mode: 'cross'},
|
||||
],
|
||||
});
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* jshint -W072 */
|
||||
defineDescribe('Sequence Renderer', [
|
||||
defineDescribe('Sequence Integration', [
|
||||
'./Parser',
|
||||
'./Generator',
|
||||
'./Renderer',
|
||||
|
|
Loading…
Reference in New Issue