Add simple agent options (red, database) [#36]
This commit is contained in:
parent
ab3d67f313
commit
8397810c12
|
@ -604,7 +604,15 @@ define('core/ArrayUtilities',[],() => {
|
||||||
define('sequence/CodeMirrorMode',['core/ArrayUtilities'], (array) => {
|
define('sequence/CodeMirrorMode',['core/ArrayUtilities'], (array) => {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const CM_ERROR = {type: 'error line-error', then: {'': 0}};
|
const CM_ERROR = {type: 'error line-error', suggest: false, then: {'': 0}};
|
||||||
|
|
||||||
|
function textTo(exit, suggest = false) {
|
||||||
|
return {
|
||||||
|
type: 'string',
|
||||||
|
suggest,
|
||||||
|
then: Object.assign({'': 0}, exit),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function suggestionsEqual(a, b) {
|
function suggestionsEqual(a, b) {
|
||||||
return (
|
return (
|
||||||
|
@ -615,6 +623,11 @@ define('sequence/CodeMirrorMode',['core/ArrayUtilities'], (array) => {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const AGENT_INFO_TYPES = [
|
||||||
|
'database',
|
||||||
|
'red',
|
||||||
|
];
|
||||||
|
|
||||||
const makeCommands = ((() => {
|
const makeCommands = ((() => {
|
||||||
// The order of commands inside "then" blocks directly influences the
|
// The order of commands inside "then" blocks directly influences the
|
||||||
// order they are displayed to the user in autocomplete menus.
|
// order they are displayed to the user in autocomplete menus.
|
||||||
|
@ -623,36 +636,7 @@ define('sequence/CodeMirrorMode',['core/ArrayUtilities'], (array) => {
|
||||||
// to use Map objects instead for strict compliance, at the cost of
|
// to use Map objects instead for strict compliance, at the cost of
|
||||||
// extra syntax.
|
// extra syntax.
|
||||||
|
|
||||||
const end = {type: '', suggest: '\n', then: {}};
|
function agentListTo(exit, next = 1) {
|
||||||
const hiddenEnd = {type: '', then: {}};
|
|
||||||
|
|
||||||
function textTo(exit, suggest) {
|
|
||||||
return {
|
|
||||||
type: 'string',
|
|
||||||
suggest,
|
|
||||||
then: Object.assign({'': 0}, exit),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const textToEnd = textTo({'\n': end});
|
|
||||||
const aliasListToEnd = {
|
|
||||||
type: 'variable',
|
|
||||||
suggest: {known: 'Agent'},
|
|
||||||
then: {
|
|
||||||
'': 0,
|
|
||||||
'\n': end,
|
|
||||||
',': {type: 'operator', suggest: true, then: {'': 1}},
|
|
||||||
'as': {type: 'keyword', suggest: true, then: {
|
|
||||||
'': {type: 'variable', suggest: {known: 'Agent'}, then: {
|
|
||||||
'': 0,
|
|
||||||
',': {type: 'operator', suggest: true, then: {'': 3}},
|
|
||||||
'\n': end,
|
|
||||||
}},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
function agentListTo(exit) {
|
|
||||||
return {
|
return {
|
||||||
type: 'variable',
|
type: 'variable',
|
||||||
suggest: {known: 'Agent'},
|
suggest: {known: 'Agent'},
|
||||||
|
@ -660,46 +644,37 @@ define('sequence/CodeMirrorMode',['core/ArrayUtilities'], (array) => {
|
||||||
exit,
|
exit,
|
||||||
{
|
{
|
||||||
'': 0,
|
'': 0,
|
||||||
',': {type: 'operator', suggest: true, then: {'': 1}},
|
',': {type: 'operator', then: {'': next}},
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const end = {type: '', suggest: '\n', then: {}};
|
||||||
|
const hiddenEnd = {type: '', suggest: false, then: {}};
|
||||||
|
const textToEnd = textTo({'\n': end});
|
||||||
const colonTextToEnd = {
|
const colonTextToEnd = {
|
||||||
type: 'operator',
|
type: 'operator',
|
||||||
suggest: true,
|
|
||||||
then: {'': textToEnd, '\n': hiddenEnd},
|
then: {'': textToEnd, '\n': hiddenEnd},
|
||||||
};
|
};
|
||||||
const agentListToText = agentListTo({
|
const aliasListToEnd = agentListTo({
|
||||||
':': colonTextToEnd,
|
'\n': end,
|
||||||
});
|
'as': {type: 'keyword', then: {
|
||||||
const agentList2ToText = {
|
'': {type: 'variable', suggest: {known: 'Agent'}, then: {
|
||||||
type: 'variable',
|
'': 0,
|
||||||
suggest: {known: 'Agent'},
|
',': {type: 'operator', then: {'': 3}},
|
||||||
then: {
|
'\n': end,
|
||||||
'': 0,
|
|
||||||
',': {type: 'operator', suggest: true, then: {
|
|
||||||
'': agentListToText,
|
|
||||||
}},
|
}},
|
||||||
':': CM_ERROR,
|
}},
|
||||||
},
|
});
|
||||||
};
|
const agentListToText = agentListTo({':': colonTextToEnd});
|
||||||
const singleAgentToText = {
|
|
||||||
type: 'variable',
|
|
||||||
suggest: {known: 'Agent'},
|
|
||||||
then: {
|
|
||||||
'': 0,
|
|
||||||
',': CM_ERROR,
|
|
||||||
':': colonTextToEnd,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const agentToOptText = {
|
const agentToOptText = {
|
||||||
type: 'variable',
|
type: 'variable',
|
||||||
suggest: {known: 'Agent'},
|
suggest: {known: 'Agent'},
|
||||||
then: {
|
then: {
|
||||||
'': 0,
|
'': 0,
|
||||||
':': {type: 'operator', suggest: true, then: {
|
':': {type: 'operator', then: {
|
||||||
'': textToEnd,
|
'': textToEnd,
|
||||||
'\n': hiddenEnd,
|
'\n': hiddenEnd,
|
||||||
}},
|
}},
|
||||||
|
@ -707,9 +682,9 @@ define('sequence/CodeMirrorMode',['core/ArrayUtilities'], (array) => {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const referenceName = {
|
const referenceName = {
|
||||||
':': {type: 'operator', suggest: true, then: {
|
':': {type: 'operator', then: {
|
||||||
'': textTo({
|
'': textTo({
|
||||||
'as': {type: 'keyword', suggest: true, then: {
|
'as': {type: 'keyword', then: {
|
||||||
'': {
|
'': {
|
||||||
type: 'variable',
|
type: 'variable',
|
||||||
suggest: {known: 'Agent'},
|
suggest: {known: 'Agent'},
|
||||||
|
@ -722,23 +697,23 @@ define('sequence/CodeMirrorMode',['core/ArrayUtilities'], (array) => {
|
||||||
}),
|
}),
|
||||||
}},
|
}},
|
||||||
};
|
};
|
||||||
const refDef = {type: 'keyword', suggest: true, then: Object.assign({
|
const refDef = {type: 'keyword', then: Object.assign({
|
||||||
'over': {type: 'keyword', suggest: true, then: {
|
'over': {type: 'keyword', then: {
|
||||||
'': agentListTo(referenceName),
|
'': agentListTo(referenceName),
|
||||||
}},
|
}},
|
||||||
}, referenceName)};
|
}, referenceName)};
|
||||||
|
|
||||||
const divider = {
|
const divider = {
|
||||||
'\n': end,
|
'\n': end,
|
||||||
':': {type: 'operator', suggest: true, then: {
|
':': {type: 'operator', then: {
|
||||||
'': textToEnd,
|
'': textToEnd,
|
||||||
'\n': hiddenEnd,
|
'\n': hiddenEnd,
|
||||||
}},
|
}},
|
||||||
'with': {type: 'keyword', suggest: ['with height '], then: {
|
'with': {type: 'keyword', suggest: ['with height '], then: {
|
||||||
'height': {type: 'keyword', suggest: true, then: {
|
'height': {type: 'keyword', then: {
|
||||||
'': {type: 'number', suggest: ['6 ', '30 '], then: {
|
'': {type: 'number', suggest: ['6 ', '30 '], then: {
|
||||||
'\n': end,
|
'\n': end,
|
||||||
':': {type: 'operator', suggest: true, then: {
|
':': {type: 'operator', then: {
|
||||||
'': textToEnd,
|
'': textToEnd,
|
||||||
'\n': hiddenEnd,
|
'\n': hiddenEnd,
|
||||||
}},
|
}},
|
||||||
|
@ -747,15 +722,41 @@ define('sequence/CodeMirrorMode',['core/ArrayUtilities'], (array) => {
|
||||||
}},
|
}},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function simpleList(type, keywords, exit) {
|
||||||
|
const first = {};
|
||||||
|
const recur = Object.assign({}, exit);
|
||||||
|
|
||||||
|
keywords.forEach((keyword) => {
|
||||||
|
first[keyword] = {type, then: recur};
|
||||||
|
recur[keyword] = 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
function optionalKeywords(type, keywords, then) {
|
||||||
|
const result = Object.assign({}, then);
|
||||||
|
keywords.forEach((keyword) => {
|
||||||
|
result[keyword] = {type, then};
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const agentInfoList = optionalKeywords(
|
||||||
|
'keyword',
|
||||||
|
['a', 'an'],
|
||||||
|
simpleList('keyword', AGENT_INFO_TYPES, {'\n': end})
|
||||||
|
);
|
||||||
|
|
||||||
function makeSideNote(side) {
|
function makeSideNote(side) {
|
||||||
return {
|
return {
|
||||||
type: 'keyword',
|
type: 'keyword',
|
||||||
suggest: [side + ' of ', side + ': '],
|
suggest: [side + ' of ', side + ': '],
|
||||||
then: {
|
then: {
|
||||||
'of': {type: 'keyword', suggest: true, then: {
|
'of': {type: 'keyword', then: {
|
||||||
'': agentListToText,
|
'': agentListToText,
|
||||||
}},
|
}},
|
||||||
':': {type: 'operator', suggest: true, then: {
|
':': {type: 'operator', then: {
|
||||||
'': textToEnd,
|
'': textToEnd,
|
||||||
}},
|
}},
|
||||||
'': agentListToText,
|
'': agentListToText,
|
||||||
|
@ -763,8 +764,8 @@ define('sequence/CodeMirrorMode',['core/ArrayUtilities'], (array) => {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeOpBlock(exit, sourceExit) {
|
function makeOpBlock({exit, sourceExit, blankExit}) {
|
||||||
const op = {type: 'operator', suggest: true, then: {
|
const op = {type: 'operator', then: {
|
||||||
'+': CM_ERROR,
|
'+': CM_ERROR,
|
||||||
'-': CM_ERROR,
|
'-': CM_ERROR,
|
||||||
'*': CM_ERROR,
|
'*': CM_ERROR,
|
||||||
|
@ -772,14 +773,14 @@ define('sequence/CodeMirrorMode',['core/ArrayUtilities'], (array) => {
|
||||||
'': exit,
|
'': exit,
|
||||||
}};
|
}};
|
||||||
return {
|
return {
|
||||||
'+': {type: 'operator', suggest: true, then: {
|
'+': {type: 'operator', then: {
|
||||||
'+': CM_ERROR,
|
'+': CM_ERROR,
|
||||||
'-': CM_ERROR,
|
'-': CM_ERROR,
|
||||||
'*': op,
|
'*': op,
|
||||||
'!': CM_ERROR,
|
'!': CM_ERROR,
|
||||||
'': exit,
|
'': exit,
|
||||||
}},
|
}},
|
||||||
'-': {type: 'operator', suggest: true, then: {
|
'-': {type: 'operator', then: {
|
||||||
'+': CM_ERROR,
|
'+': CM_ERROR,
|
||||||
'-': CM_ERROR,
|
'-': CM_ERROR,
|
||||||
'*': op,
|
'*': op,
|
||||||
|
@ -792,27 +793,29 @@ define('sequence/CodeMirrorMode',['core/ArrayUtilities'], (array) => {
|
||||||
}},
|
}},
|
||||||
'': exit,
|
'': exit,
|
||||||
}},
|
}},
|
||||||
'*': {type: 'operator', suggest: true, then: Object.assign({
|
'*': {type: 'operator', then: Object.assign({
|
||||||
'+': op,
|
'+': op,
|
||||||
'-': op,
|
'-': op,
|
||||||
'*': CM_ERROR,
|
'*': CM_ERROR,
|
||||||
'!': CM_ERROR,
|
'!': CM_ERROR,
|
||||||
'': exit,
|
'': exit,
|
||||||
}, sourceExit)},
|
}, sourceExit || exit)},
|
||||||
'!': op,
|
'!': op,
|
||||||
'': exit,
|
'': blankExit || exit,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeCMConnect(arrows) {
|
function makeCMConnect(arrows) {
|
||||||
const connect = {
|
const connect = {
|
||||||
type: 'keyword',
|
type: 'keyword',
|
||||||
suggest: true,
|
then: Object.assign({}, makeOpBlock({
|
||||||
then: Object.assign({}, makeOpBlock(agentToOptText, {
|
exit: agentToOptText,
|
||||||
':': colonTextToEnd,
|
sourceExit: {
|
||||||
'\n': hiddenEnd,
|
':': colonTextToEnd,
|
||||||
|
'\n': hiddenEnd,
|
||||||
|
},
|
||||||
}), {
|
}), {
|
||||||
'...': {type: 'operator', suggest: true, then: {
|
'...': {type: 'operator', then: {
|
||||||
'': {
|
'': {
|
||||||
type: 'variable',
|
type: 'variable',
|
||||||
suggest: {known: 'DelayedAgent'},
|
suggest: {known: 'DelayedAgent'},
|
||||||
|
@ -831,7 +834,6 @@ define('sequence/CodeMirrorMode',['core/ArrayUtilities'], (array) => {
|
||||||
|
|
||||||
const labelIndicator = {
|
const labelIndicator = {
|
||||||
type: 'operator',
|
type: 'operator',
|
||||||
suggest: true,
|
|
||||||
override: 'Label',
|
override: 'Label',
|
||||||
then: {},
|
then: {},
|
||||||
};
|
};
|
||||||
|
@ -848,8 +850,9 @@ define('sequence/CodeMirrorMode',['core/ArrayUtilities'], (array) => {
|
||||||
suggest: {known: 'Agent'},
|
suggest: {known: 'Agent'},
|
||||||
then: Object.assign({
|
then: Object.assign({
|
||||||
'': 0,
|
'': 0,
|
||||||
|
}, connectors, {
|
||||||
':': labelIndicator,
|
':': labelIndicator,
|
||||||
}, connectors),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
const firstAgentDelayed = {
|
const firstAgentDelayed = {
|
||||||
|
@ -861,29 +864,39 @@ define('sequence/CodeMirrorMode',['core/ArrayUtilities'], (array) => {
|
||||||
}, connectors),
|
}, connectors),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const firstAgentNoFlags = Object.assign({}, firstAgent, {
|
||||||
|
then: Object.assign({}, firstAgent.then, {
|
||||||
|
'is': {type: 'keyword', then: agentInfoList},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
return Object.assign({
|
return Object.assign({
|
||||||
'...': {type: 'operator', suggest: true, then: {
|
'...': {type: 'operator', then: {
|
||||||
'': firstAgentDelayed,
|
'': firstAgentDelayed,
|
||||||
}},
|
}},
|
||||||
}, makeOpBlock(firstAgent, Object.assign({
|
}, makeOpBlock({
|
||||||
'': firstAgent,
|
exit: firstAgent,
|
||||||
':': hiddenLabelIndicator,
|
sourceExit: Object.assign({
|
||||||
}, connectors)));
|
'': firstAgent,
|
||||||
|
':': hiddenLabelIndicator,
|
||||||
|
}, connectors),
|
||||||
|
blankExit: firstAgentNoFlags,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
const group = {type: 'keyword', suggest: true, then: {
|
const group = {type: 'keyword', then: {
|
||||||
'': textToEnd,
|
'': textToEnd,
|
||||||
':': {type: 'operator', suggest: true, then: {
|
':': {type: 'operator', then: {
|
||||||
'': textToEnd,
|
'': textToEnd,
|
||||||
}},
|
}},
|
||||||
'\n': end,
|
'\n': end,
|
||||||
}};
|
}};
|
||||||
|
|
||||||
const BASE_THEN = {
|
const BASE_THEN = {
|
||||||
'title': {type: 'keyword', suggest: true, then: {
|
'title': {type: 'keyword', then: {
|
||||||
'': textToEnd,
|
'': textToEnd,
|
||||||
}},
|
}},
|
||||||
'theme': {type: 'keyword', suggest: true, then: {
|
'theme': {type: 'keyword', then: {
|
||||||
'': {
|
'': {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
suggest: {
|
suggest: {
|
||||||
|
@ -896,36 +909,36 @@ define('sequence/CodeMirrorMode',['core/ArrayUtilities'], (array) => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
'headers': {type: 'keyword', suggest: true, then: {
|
'headers': {type: 'keyword', then: {
|
||||||
'none': {type: 'keyword', suggest: true, then: {}},
|
'none': {type: 'keyword', then: {}},
|
||||||
'cross': {type: 'keyword', suggest: true, then: {}},
|
'cross': {type: 'keyword', then: {}},
|
||||||
'box': {type: 'keyword', suggest: true, then: {}},
|
'box': {type: 'keyword', then: {}},
|
||||||
'fade': {type: 'keyword', suggest: true, then: {}},
|
'fade': {type: 'keyword', then: {}},
|
||||||
'bar': {type: 'keyword', suggest: true, then: {}},
|
'bar': {type: 'keyword', then: {}},
|
||||||
}},
|
}},
|
||||||
'terminators': {type: 'keyword', suggest: true, then: {
|
'terminators': {type: 'keyword', then: {
|
||||||
'none': {type: 'keyword', suggest: true, then: {}},
|
'none': {type: 'keyword', then: {}},
|
||||||
'cross': {type: 'keyword', suggest: true, then: {}},
|
'cross': {type: 'keyword', then: {}},
|
||||||
'box': {type: 'keyword', suggest: true, then: {}},
|
'box': {type: 'keyword', then: {}},
|
||||||
'fade': {type: 'keyword', suggest: true, then: {}},
|
'fade': {type: 'keyword', then: {}},
|
||||||
'bar': {type: 'keyword', suggest: true, then: {}},
|
'bar': {type: 'keyword', then: {}},
|
||||||
}},
|
}},
|
||||||
'divider': {type: 'keyword', suggest: true, then: Object.assign({
|
'divider': {type: 'keyword', then: Object.assign({
|
||||||
'line': {type: 'keyword', suggest: true, then: divider},
|
'line': {type: 'keyword', then: divider},
|
||||||
'space': {type: 'keyword', suggest: true, then: divider},
|
'space': {type: 'keyword', then: divider},
|
||||||
'delay': {type: 'keyword', suggest: true, then: divider},
|
'delay': {type: 'keyword', then: divider},
|
||||||
'tear': {type: 'keyword', suggest: true, then: divider},
|
'tear': {type: 'keyword', then: divider},
|
||||||
}, divider)},
|
}, divider)},
|
||||||
'define': {type: 'keyword', suggest: true, then: {
|
'define': {type: 'keyword', then: {
|
||||||
'': aliasListToEnd,
|
'': aliasListToEnd,
|
||||||
'as': CM_ERROR,
|
'as': CM_ERROR,
|
||||||
}},
|
}},
|
||||||
'begin': {type: 'keyword', suggest: true, then: {
|
'begin': {type: 'keyword', then: {
|
||||||
'': aliasListToEnd,
|
'': aliasListToEnd,
|
||||||
'reference': refDef,
|
'reference': refDef,
|
||||||
'as': CM_ERROR,
|
'as': CM_ERROR,
|
||||||
}},
|
}},
|
||||||
'end': {type: 'keyword', suggest: true, then: {
|
'end': {type: 'keyword', then: {
|
||||||
'': aliasListToEnd,
|
'': aliasListToEnd,
|
||||||
'as': CM_ERROR,
|
'as': CM_ERROR,
|
||||||
'\n': end,
|
'\n': end,
|
||||||
|
@ -934,7 +947,7 @@ define('sequence/CodeMirrorMode',['core/ArrayUtilities'], (array) => {
|
||||||
'else': {type: 'keyword', suggest: ['else\n', 'else if: '], then: {
|
'else': {type: 'keyword', suggest: ['else\n', 'else if: '], then: {
|
||||||
'if': {type: 'keyword', suggest: 'if: ', then: {
|
'if': {type: 'keyword', suggest: 'if: ', then: {
|
||||||
'': textToEnd,
|
'': textToEnd,
|
||||||
':': {type: 'operator', suggest: true, then: {
|
':': {type: 'operator', then: {
|
||||||
'': textToEnd,
|
'': textToEnd,
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
|
@ -942,39 +955,47 @@ define('sequence/CodeMirrorMode',['core/ArrayUtilities'], (array) => {
|
||||||
}},
|
}},
|
||||||
'repeat': group,
|
'repeat': group,
|
||||||
'group': group,
|
'group': group,
|
||||||
'note': {type: 'keyword', suggest: true, then: {
|
'note': {type: 'keyword', then: {
|
||||||
'over': {type: 'keyword', suggest: true, then: {
|
'over': {type: 'keyword', then: {
|
||||||
'': agentListToText,
|
'': agentListToText,
|
||||||
}},
|
}},
|
||||||
'left': makeSideNote('left'),
|
'left': makeSideNote('left'),
|
||||||
'right': makeSideNote('right'),
|
'right': makeSideNote('right'),
|
||||||
'between': {type: 'keyword', suggest: true, then: {
|
'between': {type: 'keyword', then: {
|
||||||
'': agentList2ToText,
|
'': agentListTo({':': CM_ERROR}, agentListToText),
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
'state': {type: 'keyword', suggest: 'state over ', then: {
|
'state': {type: 'keyword', suggest: 'state over ', then: {
|
||||||
'over': {type: 'keyword', suggest: true, then: {
|
'over': {type: 'keyword', then: {
|
||||||
'': singleAgentToText,
|
'': {
|
||||||
|
type: 'variable',
|
||||||
|
suggest: {known: 'Agent'},
|
||||||
|
then: {
|
||||||
|
'': 0,
|
||||||
|
',': CM_ERROR,
|
||||||
|
':': colonTextToEnd,
|
||||||
|
},
|
||||||
|
},
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
'text': {type: 'keyword', suggest: true, then: {
|
'text': {type: 'keyword', then: {
|
||||||
'left': makeSideNote('left'),
|
'left': makeSideNote('left'),
|
||||||
'right': makeSideNote('right'),
|
'right': makeSideNote('right'),
|
||||||
}},
|
}},
|
||||||
'autolabel': {type: 'keyword', suggest: true, then: {
|
'autolabel': {type: 'keyword', then: {
|
||||||
'off': {type: 'keyword', suggest: true, then: {}},
|
'off': {type: 'keyword', then: {}},
|
||||||
'': textTo({'\n': end}, [
|
'': textTo({'\n': end}, [
|
||||||
{v: '<label>', suffix: '\n', q: true},
|
{v: '<label>', suffix: '\n', q: true},
|
||||||
{v: '[<inc>] <label>', suffix: '\n', q: true},
|
{v: '[<inc>] <label>', suffix: '\n', q: true},
|
||||||
{v: '[<inc 1,0.01>] <label>', suffix: '\n', q: true},
|
{v: '[<inc 1,0.01>] <label>', suffix: '\n', q: true},
|
||||||
]),
|
]),
|
||||||
}},
|
}},
|
||||||
'simultaneously': {type: 'keyword', suggest: true, then: {
|
'simultaneously': {type: 'keyword', then: {
|
||||||
':': {type: 'operator', suggest: true, then: {}},
|
':': {type: 'operator', then: {}},
|
||||||
'with': {type: 'keyword', suggest: true, then: {
|
'with': {type: 'keyword', then: {
|
||||||
'': {type: 'variable', suggest: {known: 'Label'}, then: {
|
'': {type: 'variable', suggest: {known: 'Label'}, then: {
|
||||||
'': 0,
|
'': 0,
|
||||||
':': {type: 'operator', suggest: true, then: {}},
|
':': {type: 'operator', then: {}},
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
|
@ -1003,8 +1024,8 @@ define('sequence/CodeMirrorMode',['core/ArrayUtilities'], (array) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return array.flatMap(suggestions, (suggest) => {
|
return array.flatMap(suggestions, (suggest) => {
|
||||||
if(suggest === true) {
|
if(suggest === false) {
|
||||||
return [cmCappedToken(token, current)];
|
return [];
|
||||||
} else if(typeof suggest === 'object') {
|
} else if(typeof suggest === 'object') {
|
||||||
if(suggest.known) {
|
if(suggest.known) {
|
||||||
return state['known' + suggest.known] || [];
|
return state['known' + suggest.known] || [];
|
||||||
|
@ -1014,7 +1035,7 @@ define('sequence/CodeMirrorMode',['core/ArrayUtilities'], (array) => {
|
||||||
} else if(typeof suggest === 'string' && suggest) {
|
} else if(typeof suggest === 'string' && suggest) {
|
||||||
return [{v: suggest, q: (token === '')}];
|
return [{v: suggest, q: (token === '')}];
|
||||||
} else {
|
} else {
|
||||||
return [];
|
return [cmCappedToken(token, current)];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -2213,6 +2234,31 @@ define('sequence/Parser',[
|
||||||
name: joinLabel(line, 0, line.length - 1),
|
name: joinLabel(line, 0, line.length - 1),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
(line) => { // options
|
||||||
|
const sepPos = findToken(line, 'is');
|
||||||
|
if(sepPos < 1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const indefiniteArticles = ['a', 'an'];
|
||||||
|
let optionsBegin = sepPos + 1;
|
||||||
|
if(indefiniteArticles.includes(tokenKeyword(line[optionsBegin]))) {
|
||||||
|
++ optionsBegin;
|
||||||
|
}
|
||||||
|
if(optionsBegin === line.length) {
|
||||||
|
throw makeError('Empty agent options', {b: array.last(line).e});
|
||||||
|
}
|
||||||
|
const agent = readAgent(line, 0, sepPos);
|
||||||
|
const options = [];
|
||||||
|
for(let i = optionsBegin; i < line.length; ++ i) {
|
||||||
|
options.push(line[i].v);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
type: 'agent options',
|
||||||
|
agent,
|
||||||
|
options,
|
||||||
|
};
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
function parseLine(line, {meta, stages}) {
|
function parseLine(line, {meta, stages}) {
|
||||||
|
@ -2309,7 +2355,7 @@ define('sequence/Generator',['core/ArrayUtilities'], (array) => {
|
||||||
return a.id === b.id;
|
return a.id === b.id;
|
||||||
},
|
},
|
||||||
make: (id, {anchorRight = false, isVirtualSource = false} = {}) => {
|
make: (id, {anchorRight = false, isVirtualSource = false} = {}) => {
|
||||||
return {id, anchorRight, isVirtualSource};
|
return {id, anchorRight, isVirtualSource, options: []};
|
||||||
},
|
},
|
||||||
indexOf: (list, gAgent) => {
|
indexOf: (list, gAgent) => {
|
||||||
return array.indexOf(list, gAgent, GAgent.equals);
|
return array.indexOf(list, gAgent, GAgent.equals);
|
||||||
|
@ -2523,6 +2569,7 @@ define('sequence/Generator',['core/ArrayUtilities'], (array) => {
|
||||||
'mark': this.handleMark.bind(this),
|
'mark': this.handleMark.bind(this),
|
||||||
'async': this.handleAsync.bind(this),
|
'async': this.handleAsync.bind(this),
|
||||||
'agent define': this.handleAgentDefine.bind(this),
|
'agent define': this.handleAgentDefine.bind(this),
|
||||||
|
'agent options': this.handleAgentOptions.bind(this),
|
||||||
'agent begin': this.handleAgentBegin.bind(this),
|
'agent begin': this.handleAgentBegin.bind(this),
|
||||||
'agent end': this.handleAgentEnd.bind(this),
|
'agent end': this.handleAgentEnd.bind(this),
|
||||||
'divider': this.handleDivider.bind(this),
|
'divider': this.handleDivider.bind(this),
|
||||||
|
@ -2626,23 +2673,23 @@ define('sequence/Generator',['core/ArrayUtilities'], (array) => {
|
||||||
|
|
||||||
validateGAgents(gAgents, {
|
validateGAgents(gAgents, {
|
||||||
allowGrouped = false,
|
allowGrouped = false,
|
||||||
rejectGrouped = false,
|
allowCovered = false,
|
||||||
allowVirtual = false,
|
allowVirtual = false,
|
||||||
} = {}) {
|
} = {}) {
|
||||||
/* jshint -W074 */ // agent validity checking requires several steps
|
|
||||||
gAgents.forEach((gAgent) => {
|
gAgents.forEach((gAgent) => {
|
||||||
const state = this.getGAgentState(gAgent);
|
const state = this.getGAgentState(gAgent);
|
||||||
if(state.covered) {
|
if(state.blocked && state.group === null) {
|
||||||
|
// used to be a group alias; can never be reused
|
||||||
|
throw new Error('Duplicate agent name: ' + gAgent.id);
|
||||||
|
}
|
||||||
|
if(!allowCovered && state.covered) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Agent ' + gAgent.id + ' is hidden behind group'
|
'Agent ' + gAgent.id + ' is hidden behind group'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if(rejectGrouped && state.group !== null) {
|
if(!allowGrouped && state.group !== null) {
|
||||||
throw new Error('Agent ' + gAgent.id + ' is in a group');
|
throw new Error('Agent ' + gAgent.id + ' is in a group');
|
||||||
}
|
}
|
||||||
if(state.blocked && (!allowGrouped || state.group === null)) {
|
|
||||||
throw new Error('Duplicate agent name: ' + gAgent.id);
|
|
||||||
}
|
|
||||||
if(!allowVirtual && gAgent.isVirtualSource) {
|
if(!allowVirtual && gAgent.isVirtualSource) {
|
||||||
throw new Error('cannot use message source here');
|
throw new Error('cannot use message source here');
|
||||||
}
|
}
|
||||||
|
@ -2833,7 +2880,7 @@ define('sequence/Generator',['core/ArrayUtilities'], (array) => {
|
||||||
|
|
||||||
makeGroupDetails(pAgents, alias) {
|
makeGroupDetails(pAgents, alias) {
|
||||||
const gAgents = pAgents.map(this.toGAgent);
|
const gAgents = pAgents.map(this.toGAgent);
|
||||||
this.validateGAgents(gAgents, {rejectGrouped: true});
|
this.validateGAgents(gAgents);
|
||||||
if(this.agentStates.has(alias)) {
|
if(this.agentStates.has(alias)) {
|
||||||
throw new Error('Duplicate agent name: ' + alias);
|
throw new Error('Duplicate agent name: ' + alias);
|
||||||
}
|
}
|
||||||
|
@ -3264,8 +3311,27 @@ define('sequence/Generator',['core/ArrayUtilities'], (array) => {
|
||||||
|
|
||||||
handleAgentDefine({agents}) {
|
handleAgentDefine({agents}) {
|
||||||
const gAgents = agents.map(this.toGAgent);
|
const gAgents = agents.map(this.toGAgent);
|
||||||
this.validateGAgents(gAgents);
|
this.validateGAgents(gAgents, {
|
||||||
this.defineGAgents(gAgents);
|
allowGrouped: true,
|
||||||
|
allowCovered: true,
|
||||||
|
});
|
||||||
|
array.mergeSets(this.gAgents, gAgents, GAgent.equals);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleAgentOptions({agent, options}) {
|
||||||
|
const gAgent = this.toGAgent(agent);
|
||||||
|
const gAgents = [gAgent];
|
||||||
|
this.validateGAgents(gAgents, {
|
||||||
|
allowGrouped: true,
|
||||||
|
allowCovered: true,
|
||||||
|
});
|
||||||
|
array.mergeSets(this.gAgents, gAgents, GAgent.equals);
|
||||||
|
|
||||||
|
this.gAgents
|
||||||
|
.filter(({id}) => (id === gAgent.id))
|
||||||
|
.forEach((storedGAgent) => {
|
||||||
|
array.mergeSets(storedGAgent.options, options);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleAgentBegin({agents, mode}) {
|
handleAgentBegin({agents, mode}) {
|
||||||
|
@ -4433,8 +4499,16 @@ define('sequence/components/AgentCap',[
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
class CapBox {
|
class CapBox {
|
||||||
separation({formattedLabel}, env) {
|
getConfig(options, env) {
|
||||||
const config = env.theme.agentCap.box;
|
let config = null;
|
||||||
|
if(options.includes('database')) {
|
||||||
|
config = env.theme.agentCap.database;
|
||||||
|
}
|
||||||
|
return config || env.theme.agentCap.box;
|
||||||
|
}
|
||||||
|
|
||||||
|
separation({formattedLabel, options}, env) {
|
||||||
|
const config = this.getConfig(options, env);
|
||||||
const width = (
|
const width = (
|
||||||
env.textSizer.measure(config.labelAttrs, formattedLabel).width +
|
env.textSizer.measure(config.labelAttrs, formattedLabel).width +
|
||||||
config.padding.left +
|
config.padding.left +
|
||||||
|
@ -4448,8 +4522,8 @@ define('sequence/components/AgentCap',[
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
topShift({formattedLabel}, env) {
|
topShift({formattedLabel, options}, env) {
|
||||||
const config = env.theme.agentCap.box;
|
const config = this.getConfig(options, env);
|
||||||
const height = (
|
const height = (
|
||||||
env.textSizer.measureHeight(config.labelAttrs, formattedLabel) +
|
env.textSizer.measureHeight(config.labelAttrs, formattedLabel) +
|
||||||
config.padding.top +
|
config.padding.top +
|
||||||
|
@ -4458,8 +4532,8 @@ define('sequence/components/AgentCap',[
|
||||||
return Math.max(0, height - config.arrowBottom);
|
return Math.max(0, height - config.arrowBottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
render(y, {x, formattedLabel}, env) {
|
render(y, {x, formattedLabel, options}, env) {
|
||||||
const config = env.theme.agentCap.box;
|
const config = this.getConfig(options, env);
|
||||||
const clickable = env.makeRegion();
|
const clickable = env.makeRegion();
|
||||||
const text = SVGShapes.renderBoxedText(formattedLabel, {
|
const text = SVGShapes.renderBoxedText(formattedLabel, {
|
||||||
x,
|
x,
|
||||||
|
@ -4505,13 +4579,18 @@ define('sequence/components/AgentCap',[
|
||||||
return config.size / 2;
|
return config.size / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
render(y, {x}, env) {
|
render(y, {x, options}, env) {
|
||||||
const config = env.theme.agentCap.cross;
|
const config = env.theme.agentCap.cross;
|
||||||
const d = config.size / 2;
|
const d = config.size / 2;
|
||||||
|
|
||||||
const clickable = env.makeRegion();
|
const clickable = env.makeRegion();
|
||||||
|
|
||||||
clickable.appendChild(config.render({x, y: y + d, radius: d}));
|
clickable.appendChild(config.render({
|
||||||
|
x,
|
||||||
|
y: y + d,
|
||||||
|
radius: d,
|
||||||
|
options,
|
||||||
|
}));
|
||||||
clickable.appendChild(svg.make('rect', {
|
clickable.appendChild(svg.make('rect', {
|
||||||
'x': x - d,
|
'x': x - d,
|
||||||
'y': y,
|
'y': y,
|
||||||
|
@ -4550,7 +4629,7 @@ define('sequence/components/AgentCap',[
|
||||||
return config.height / 2;
|
return config.height / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
render(y, {x, formattedLabel}, env) {
|
render(y, {x, formattedLabel, options}, env) {
|
||||||
const boxCfg = env.theme.agentCap.box;
|
const boxCfg = env.theme.agentCap.box;
|
||||||
const barCfg = env.theme.agentCap.bar;
|
const barCfg = env.theme.agentCap.bar;
|
||||||
const width = (
|
const width = (
|
||||||
|
@ -4566,6 +4645,7 @@ define('sequence/components/AgentCap',[
|
||||||
y,
|
y,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
|
options,
|
||||||
}));
|
}));
|
||||||
clickable.appendChild(svg.make('rect', {
|
clickable.appendChild(svg.make('rect', {
|
||||||
'x': x - width / 2,
|
'x': x - width / 2,
|
||||||
|
@ -4838,7 +4918,7 @@ define('sequence/components/Connect',[
|
||||||
const arrow = this.getConfig(theme);
|
const arrow = this.getConfig(theme);
|
||||||
const join = arrow.attrs['stroke-linejoin'] || 'miter';
|
const join = arrow.attrs['stroke-linejoin'] || 'miter';
|
||||||
const t = arrow.attrs['stroke-width'] * 0.5;
|
const t = arrow.attrs['stroke-width'] * 0.5;
|
||||||
const lineStroke = theme.agentLineAttrs['stroke-width'] * 0.5;
|
const lineStroke = theme.agentLineAttrs['']['stroke-width'] * 0.5;
|
||||||
if(join === 'round') {
|
if(join === 'round') {
|
||||||
return lineStroke + t;
|
return lineStroke + t;
|
||||||
} else {
|
} else {
|
||||||
|
@ -6057,6 +6137,7 @@ define('sequence/Renderer',[
|
||||||
y1: toY,
|
y1: toY,
|
||||||
width: agentInfo.currentRad * 2,
|
width: agentInfo.currentRad * 2,
|
||||||
className: 'agent-' + agentInfo.index + '-line',
|
className: 'agent-' + agentInfo.index + '-line',
|
||||||
|
options: agentInfo.options,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6193,6 +6274,7 @@ define('sequence/Renderer',[
|
||||||
formattedLabel: agent.formattedLabel,
|
formattedLabel: agent.formattedLabel,
|
||||||
anchorRight: agent.anchorRight,
|
anchorRight: agent.anchorRight,
|
||||||
isVirtualSource: agent.isVirtualSource,
|
isVirtualSource: agent.isVirtualSource,
|
||||||
|
options: agent.options,
|
||||||
index,
|
index,
|
||||||
x: null,
|
x: null,
|
||||||
latestYStart: null,
|
latestYStart: null,
|
||||||
|
@ -6784,6 +6866,14 @@ define('sequence/themes/BaseTheme',[
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function optionsAttributes(attributes, options) {
|
||||||
|
let attrs = Object.assign({}, attributes['']);
|
||||||
|
options.forEach((opt) => {
|
||||||
|
Object.assign(attrs, attributes[opt] || {});
|
||||||
|
});
|
||||||
|
return attrs;
|
||||||
|
}
|
||||||
|
|
||||||
class BaseTheme {
|
class BaseTheme {
|
||||||
constructor({name, settings, blocks, notes, dividers}) {
|
constructor({name, settings, blocks, notes, dividers}) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
@ -6811,7 +6901,12 @@ define('sequence/themes/BaseTheme',[
|
||||||
return this.dividers[type] || this.dividers[''];
|
return this.dividers[type] || this.dividers[''];
|
||||||
}
|
}
|
||||||
|
|
||||||
renderAgentLine({x, y0, y1, width, className}) {
|
optionsAttributes(attributes, options) {
|
||||||
|
return optionsAttributes(attributes, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderAgentLine({x, y0, y1, width, className, options}) {
|
||||||
|
const attrs = this.optionsAttributes(this.agentLineAttrs, options);
|
||||||
if(width > 0) {
|
if(width > 0) {
|
||||||
return svg.make('rect', Object.assign({
|
return svg.make('rect', Object.assign({
|
||||||
'x': x - width / 2,
|
'x': x - width / 2,
|
||||||
|
@ -6819,7 +6914,7 @@ define('sequence/themes/BaseTheme',[
|
||||||
'width': width,
|
'width': width,
|
||||||
'height': y1 - y0,
|
'height': y1 - y0,
|
||||||
'class': className,
|
'class': className,
|
||||||
}, this.agentLineAttrs));
|
}, attrs));
|
||||||
} else {
|
} else {
|
||||||
return svg.make('line', Object.assign({
|
return svg.make('line', Object.assign({
|
||||||
'x1': x,
|
'x1': x,
|
||||||
|
@ -6827,7 +6922,7 @@ define('sequence/themes/BaseTheme',[
|
||||||
'x2': x,
|
'x2': x,
|
||||||
'y2': y1,
|
'y2': y1,
|
||||||
'class': className,
|
'class': className,
|
||||||
}, this.agentLineAttrs));
|
}, attrs));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6877,6 +6972,27 @@ define('sequence/themes/BaseTheme',[
|
||||||
return g;
|
return g;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
BaseTheme.renderDB = (attrs, {x, y, width, height}) => {
|
||||||
|
const z = attrs['db-z'];
|
||||||
|
return svg.make('g', {}, [
|
||||||
|
svg.make('rect', Object.assign({
|
||||||
|
'x': x,
|
||||||
|
'y': y,
|
||||||
|
'width': width,
|
||||||
|
'height': height,
|
||||||
|
'rx': width / 2,
|
||||||
|
'ry': z,
|
||||||
|
}, attrs)),
|
||||||
|
svg.make('path', Object.assign({
|
||||||
|
'd': (
|
||||||
|
'M' + x + ' ' + (y + z) +
|
||||||
|
'a' + (width / 2) + ' ' + z +
|
||||||
|
' 0 0 0 ' + width + ' 0'
|
||||||
|
),
|
||||||
|
}, attrs, {'fill': 'none'})),
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
BaseTheme.renderCross = (attrs, {x, y, radius}) => {
|
BaseTheme.renderCross = (attrs, {x, y, radius}) => {
|
||||||
return svg.make('path', Object.assign({
|
return svg.make('path', Object.assign({
|
||||||
'd': (
|
'd': (
|
||||||
|
@ -7165,6 +7281,27 @@ define('sequence/themes/Basic',[
|
||||||
'text-anchor': 'middle',
|
'text-anchor': 'middle',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
database: {
|
||||||
|
padding: {
|
||||||
|
top: 15,
|
||||||
|
left: 10,
|
||||||
|
right: 10,
|
||||||
|
bottom: 5,
|
||||||
|
},
|
||||||
|
arrowBottom: 5 + 12 * 1.3 / 2,
|
||||||
|
boxRenderer: BaseTheme.renderDB.bind(null, {
|
||||||
|
'fill': '#FFFFFF',
|
||||||
|
'stroke': '#000000',
|
||||||
|
'stroke-width': 1,
|
||||||
|
'db-z': 5,
|
||||||
|
}),
|
||||||
|
labelAttrs: {
|
||||||
|
'font-family': FONT,
|
||||||
|
'font-size': 12,
|
||||||
|
'line-height': LINE_HEIGHT,
|
||||||
|
'text-anchor': 'middle',
|
||||||
|
},
|
||||||
|
},
|
||||||
cross: {
|
cross: {
|
||||||
size: 20,
|
size: 20,
|
||||||
render: BaseTheme.renderCross.bind(null, {
|
render: BaseTheme.renderCross.bind(null, {
|
||||||
|
@ -7304,9 +7441,14 @@ define('sequence/themes/Basic',[
|
||||||
},
|
},
|
||||||
|
|
||||||
agentLineAttrs: {
|
agentLineAttrs: {
|
||||||
'fill': 'none',
|
'': {
|
||||||
'stroke': '#000000',
|
'fill': 'none',
|
||||||
'stroke-width': 1,
|
'stroke': '#000000',
|
||||||
|
'stroke-width': 1,
|
||||||
|
},
|
||||||
|
'red': {
|
||||||
|
'stroke': '#CC0000',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -7563,6 +7705,27 @@ define('sequence/themes/Monospace',[
|
||||||
'text-anchor': 'middle',
|
'text-anchor': 'middle',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
database: {
|
||||||
|
padding: {
|
||||||
|
top: 12,
|
||||||
|
left: 8,
|
||||||
|
right: 8,
|
||||||
|
bottom: 4,
|
||||||
|
},
|
||||||
|
arrowBottom: 4 + 12 * 1.3 / 2,
|
||||||
|
boxRenderer: BaseTheme.renderDB.bind(null, {
|
||||||
|
'fill': '#FFFFFF',
|
||||||
|
'stroke': '#000000',
|
||||||
|
'stroke-width': 1,
|
||||||
|
'db-z': 4,
|
||||||
|
}),
|
||||||
|
labelAttrs: {
|
||||||
|
'font-family': FONT,
|
||||||
|
'font-size': 12,
|
||||||
|
'line-height': LINE_HEIGHT,
|
||||||
|
'text-anchor': 'middle',
|
||||||
|
},
|
||||||
|
},
|
||||||
cross: {
|
cross: {
|
||||||
size: 16,
|
size: 16,
|
||||||
render: BaseTheme.renderCross.bind(null, {
|
render: BaseTheme.renderCross.bind(null, {
|
||||||
|
@ -7700,9 +7863,14 @@ define('sequence/themes/Monospace',[
|
||||||
},
|
},
|
||||||
|
|
||||||
agentLineAttrs: {
|
agentLineAttrs: {
|
||||||
'fill': 'none',
|
'': {
|
||||||
'stroke': '#000000',
|
'fill': 'none',
|
||||||
'stroke-width': 1,
|
'stroke': '#000000',
|
||||||
|
'stroke-width': 1,
|
||||||
|
},
|
||||||
|
'red': {
|
||||||
|
'stroke': '#AA0000',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -7947,6 +8115,28 @@ define('sequence/themes/Chunky',[
|
||||||
'text-anchor': 'middle',
|
'text-anchor': 'middle',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
database: {
|
||||||
|
padding: {
|
||||||
|
top: 5,
|
||||||
|
left: 3,
|
||||||
|
right: 3,
|
||||||
|
bottom: 1,
|
||||||
|
},
|
||||||
|
arrowBottom: 1 + 12 * 1.3 / 2,
|
||||||
|
boxRenderer: BaseTheme.renderDB.bind(null, {
|
||||||
|
'fill': '#FFFFFF',
|
||||||
|
'stroke': '#000000',
|
||||||
|
'stroke-width': 3,
|
||||||
|
'db-z': 2,
|
||||||
|
}),
|
||||||
|
labelAttrs: {
|
||||||
|
'font-family': FONT,
|
||||||
|
'font-weight': 'bold',
|
||||||
|
'font-size': 14,
|
||||||
|
'line-height': LINE_HEIGHT,
|
||||||
|
'text-anchor': 'middle',
|
||||||
|
},
|
||||||
|
},
|
||||||
cross: {
|
cross: {
|
||||||
size: 20,
|
size: 20,
|
||||||
render: BaseTheme.renderCross.bind(null, {
|
render: BaseTheme.renderCross.bind(null, {
|
||||||
|
@ -8094,9 +8284,14 @@ define('sequence/themes/Chunky',[
|
||||||
},
|
},
|
||||||
|
|
||||||
agentLineAttrs: {
|
agentLineAttrs: {
|
||||||
'fill': 'none',
|
'': {
|
||||||
'stroke': '#000000',
|
'fill': 'none',
|
||||||
'stroke-width': 3,
|
'stroke': '#000000',
|
||||||
|
'stroke-width': 3,
|
||||||
|
},
|
||||||
|
'red': {
|
||||||
|
'stroke': '#DD0000',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -8797,6 +8992,25 @@ define('sequence/themes/Sketch',[
|
||||||
},
|
},
|
||||||
boxRenderer: null,
|
boxRenderer: null,
|
||||||
},
|
},
|
||||||
|
database: {
|
||||||
|
padding: {
|
||||||
|
top: 15,
|
||||||
|
left: 10,
|
||||||
|
right: 10,
|
||||||
|
bottom: 5,
|
||||||
|
},
|
||||||
|
arrowBottom: 5 + 12 * 1.3 / 2,
|
||||||
|
boxRenderer: BaseTheme.renderDB.bind(null, Object.assign({
|
||||||
|
'fill': '#FFFFFF',
|
||||||
|
'db-z': 5,
|
||||||
|
}, PENCIL.normal)),
|
||||||
|
labelAttrs: {
|
||||||
|
'font-family': FONT,
|
||||||
|
'font-size': 12,
|
||||||
|
'line-height': LINE_HEIGHT,
|
||||||
|
'text-anchor': 'middle',
|
||||||
|
},
|
||||||
|
},
|
||||||
cross: {
|
cross: {
|
||||||
size: 15,
|
size: 15,
|
||||||
render: null,
|
render: null,
|
||||||
|
@ -8913,9 +9127,12 @@ define('sequence/themes/Sketch',[
|
||||||
},
|
},
|
||||||
|
|
||||||
agentLineAttrs: {
|
agentLineAttrs: {
|
||||||
'fill': 'none',
|
'': Object.assign({
|
||||||
'stroke': '#000000',
|
'fill': 'none',
|
||||||
'stroke-width': 1,
|
}, PENCIL.normal),
|
||||||
|
'red': {
|
||||||
|
'stroke': 'rgba(200,40,0,0.8)',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -9287,7 +9504,9 @@ define('sequence/themes/Sketch',[
|
||||||
'd': line.nodes,
|
'd': line.nodes,
|
||||||
'fill': 'none',
|
'fill': 'none',
|
||||||
'stroke-dasharray': lineOptions.dash ? '6, 5' : 'none',
|
'stroke-dasharray': lineOptions.dash ? '6, 5' : 'none',
|
||||||
}, lineOptions.thick ? PENCIL.thick : PENCIL.normal));
|
}, lineOptions.attrs || (
|
||||||
|
lineOptions.thick ? PENCIL.thick : PENCIL.normal
|
||||||
|
)));
|
||||||
return shape;
|
return shape;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9316,11 +9535,11 @@ define('sequence/themes/Sketch',[
|
||||||
return lT.nodes + lR.nodes + lB.nodes + lL.nodes;
|
return lT.nodes + lR.nodes + lB.nodes + lL.nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderBox(position, {fill = null, thick = false} = {}) {
|
renderBox(position, {fill = null, thick = false, attrs = null} = {}) {
|
||||||
return svg.make('path', Object.assign({
|
return svg.make('path', Object.assign({
|
||||||
'd': this.boxNodes(position),
|
'd': this.boxNodes(position),
|
||||||
'fill': fill || '#FFFFFF',
|
'fill': fill || '#FFFFFF',
|
||||||
}, thick ? PENCIL.thick : PENCIL.normal));
|
}, attrs || (thick ? PENCIL.thick : PENCIL.normal)));
|
||||||
}
|
}
|
||||||
|
|
||||||
renderNote({x, y, width, height}) {
|
renderNote({x, y, width, height}) {
|
||||||
|
@ -9646,21 +9865,22 @@ define('sequence/themes/Sketch',[
|
||||||
}, PENCIL.normal));
|
}, PENCIL.normal));
|
||||||
}
|
}
|
||||||
|
|
||||||
renderAgentLine({x, y0, y1, width, className}) {
|
renderAgentLine({x, y0, y1, width, className, options}) {
|
||||||
|
const attrs = this.optionsAttributes(this.agentLineAttrs, options);
|
||||||
if(width > 0) {
|
if(width > 0) {
|
||||||
const shape = this.renderBox({
|
const shape = this.renderBox({
|
||||||
x: x - width / 2,
|
x: x - width / 2,
|
||||||
y: y0,
|
y: y0,
|
||||||
width,
|
width,
|
||||||
height: y1 - y0,
|
height: y1 - y0,
|
||||||
}, {fill: 'none'});
|
}, {fill: 'none', attrs});
|
||||||
shape.setAttribute('class', className);
|
shape.setAttribute('class', className);
|
||||||
return shape;
|
return shape;
|
||||||
} else {
|
} else {
|
||||||
const shape = this.renderLine(
|
const shape = this.renderLine(
|
||||||
{x, y: y0},
|
{x, y: y0},
|
||||||
{x, y: y1},
|
{x, y: y1},
|
||||||
{varY: 0.3}
|
{varY: 0.3, attrs}
|
||||||
);
|
);
|
||||||
shape.setAttribute('class', className);
|
shape.setAttribute('class', className);
|
||||||
return shape;
|
return shape;
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -249,6 +249,16 @@ define([], [
|
||||||
code: '`{text}`',
|
code: '`{text}`',
|
||||||
preview: 'A -> B: `mono`',
|
preview: 'A -> B: `mono`',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'Red agent line',
|
||||||
|
code: '{Agent} is red',
|
||||||
|
preview: 'headers box\nA is red\nbegin A',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Database indicator',
|
||||||
|
code: '{Agent} is a database',
|
||||||
|
preview: 'headers box\nA is a database\nbegin A',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: 'Monospace theme',
|
title: 'Monospace theme',
|
||||||
code: 'theme monospace',
|
code: 'theme monospace',
|
||||||
|
|
|
@ -1,7 +1,15 @@
|
||||||
define(['core/ArrayUtilities'], (array) => {
|
define(['core/ArrayUtilities'], (array) => {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const CM_ERROR = {type: 'error line-error', then: {'': 0}};
|
const CM_ERROR = {type: 'error line-error', suggest: false, then: {'': 0}};
|
||||||
|
|
||||||
|
function textTo(exit, suggest = false) {
|
||||||
|
return {
|
||||||
|
type: 'string',
|
||||||
|
suggest,
|
||||||
|
then: Object.assign({'': 0}, exit),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function suggestionsEqual(a, b) {
|
function suggestionsEqual(a, b) {
|
||||||
return (
|
return (
|
||||||
|
@ -12,6 +20,11 @@ define(['core/ArrayUtilities'], (array) => {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const AGENT_INFO_TYPES = [
|
||||||
|
'database',
|
||||||
|
'red',
|
||||||
|
];
|
||||||
|
|
||||||
const makeCommands = ((() => {
|
const makeCommands = ((() => {
|
||||||
// The order of commands inside "then" blocks directly influences the
|
// The order of commands inside "then" blocks directly influences the
|
||||||
// order they are displayed to the user in autocomplete menus.
|
// order they are displayed to the user in autocomplete menus.
|
||||||
|
@ -20,36 +33,7 @@ define(['core/ArrayUtilities'], (array) => {
|
||||||
// to use Map objects instead for strict compliance, at the cost of
|
// to use Map objects instead for strict compliance, at the cost of
|
||||||
// extra syntax.
|
// extra syntax.
|
||||||
|
|
||||||
const end = {type: '', suggest: '\n', then: {}};
|
function agentListTo(exit, next = 1) {
|
||||||
const hiddenEnd = {type: '', then: {}};
|
|
||||||
|
|
||||||
function textTo(exit, suggest) {
|
|
||||||
return {
|
|
||||||
type: 'string',
|
|
||||||
suggest,
|
|
||||||
then: Object.assign({'': 0}, exit),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const textToEnd = textTo({'\n': end});
|
|
||||||
const aliasListToEnd = {
|
|
||||||
type: 'variable',
|
|
||||||
suggest: {known: 'Agent'},
|
|
||||||
then: {
|
|
||||||
'': 0,
|
|
||||||
'\n': end,
|
|
||||||
',': {type: 'operator', suggest: true, then: {'': 1}},
|
|
||||||
'as': {type: 'keyword', suggest: true, then: {
|
|
||||||
'': {type: 'variable', suggest: {known: 'Agent'}, then: {
|
|
||||||
'': 0,
|
|
||||||
',': {type: 'operator', suggest: true, then: {'': 3}},
|
|
||||||
'\n': end,
|
|
||||||
}},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
function agentListTo(exit) {
|
|
||||||
return {
|
return {
|
||||||
type: 'variable',
|
type: 'variable',
|
||||||
suggest: {known: 'Agent'},
|
suggest: {known: 'Agent'},
|
||||||
|
@ -57,46 +41,37 @@ define(['core/ArrayUtilities'], (array) => {
|
||||||
exit,
|
exit,
|
||||||
{
|
{
|
||||||
'': 0,
|
'': 0,
|
||||||
',': {type: 'operator', suggest: true, then: {'': 1}},
|
',': {type: 'operator', then: {'': next}},
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const end = {type: '', suggest: '\n', then: {}};
|
||||||
|
const hiddenEnd = {type: '', suggest: false, then: {}};
|
||||||
|
const textToEnd = textTo({'\n': end});
|
||||||
const colonTextToEnd = {
|
const colonTextToEnd = {
|
||||||
type: 'operator',
|
type: 'operator',
|
||||||
suggest: true,
|
|
||||||
then: {'': textToEnd, '\n': hiddenEnd},
|
then: {'': textToEnd, '\n': hiddenEnd},
|
||||||
};
|
};
|
||||||
const agentListToText = agentListTo({
|
const aliasListToEnd = agentListTo({
|
||||||
':': colonTextToEnd,
|
'\n': end,
|
||||||
});
|
'as': {type: 'keyword', then: {
|
||||||
const agentList2ToText = {
|
'': {type: 'variable', suggest: {known: 'Agent'}, then: {
|
||||||
type: 'variable',
|
'': 0,
|
||||||
suggest: {known: 'Agent'},
|
',': {type: 'operator', then: {'': 3}},
|
||||||
then: {
|
'\n': end,
|
||||||
'': 0,
|
|
||||||
',': {type: 'operator', suggest: true, then: {
|
|
||||||
'': agentListToText,
|
|
||||||
}},
|
}},
|
||||||
':': CM_ERROR,
|
}},
|
||||||
},
|
});
|
||||||
};
|
const agentListToText = agentListTo({':': colonTextToEnd});
|
||||||
const singleAgentToText = {
|
|
||||||
type: 'variable',
|
|
||||||
suggest: {known: 'Agent'},
|
|
||||||
then: {
|
|
||||||
'': 0,
|
|
||||||
',': CM_ERROR,
|
|
||||||
':': colonTextToEnd,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const agentToOptText = {
|
const agentToOptText = {
|
||||||
type: 'variable',
|
type: 'variable',
|
||||||
suggest: {known: 'Agent'},
|
suggest: {known: 'Agent'},
|
||||||
then: {
|
then: {
|
||||||
'': 0,
|
'': 0,
|
||||||
':': {type: 'operator', suggest: true, then: {
|
':': {type: 'operator', then: {
|
||||||
'': textToEnd,
|
'': textToEnd,
|
||||||
'\n': hiddenEnd,
|
'\n': hiddenEnd,
|
||||||
}},
|
}},
|
||||||
|
@ -104,9 +79,9 @@ define(['core/ArrayUtilities'], (array) => {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const referenceName = {
|
const referenceName = {
|
||||||
':': {type: 'operator', suggest: true, then: {
|
':': {type: 'operator', then: {
|
||||||
'': textTo({
|
'': textTo({
|
||||||
'as': {type: 'keyword', suggest: true, then: {
|
'as': {type: 'keyword', then: {
|
||||||
'': {
|
'': {
|
||||||
type: 'variable',
|
type: 'variable',
|
||||||
suggest: {known: 'Agent'},
|
suggest: {known: 'Agent'},
|
||||||
|
@ -119,23 +94,23 @@ define(['core/ArrayUtilities'], (array) => {
|
||||||
}),
|
}),
|
||||||
}},
|
}},
|
||||||
};
|
};
|
||||||
const refDef = {type: 'keyword', suggest: true, then: Object.assign({
|
const refDef = {type: 'keyword', then: Object.assign({
|
||||||
'over': {type: 'keyword', suggest: true, then: {
|
'over': {type: 'keyword', then: {
|
||||||
'': agentListTo(referenceName),
|
'': agentListTo(referenceName),
|
||||||
}},
|
}},
|
||||||
}, referenceName)};
|
}, referenceName)};
|
||||||
|
|
||||||
const divider = {
|
const divider = {
|
||||||
'\n': end,
|
'\n': end,
|
||||||
':': {type: 'operator', suggest: true, then: {
|
':': {type: 'operator', then: {
|
||||||
'': textToEnd,
|
'': textToEnd,
|
||||||
'\n': hiddenEnd,
|
'\n': hiddenEnd,
|
||||||
}},
|
}},
|
||||||
'with': {type: 'keyword', suggest: ['with height '], then: {
|
'with': {type: 'keyword', suggest: ['with height '], then: {
|
||||||
'height': {type: 'keyword', suggest: true, then: {
|
'height': {type: 'keyword', then: {
|
||||||
'': {type: 'number', suggest: ['6 ', '30 '], then: {
|
'': {type: 'number', suggest: ['6 ', '30 '], then: {
|
||||||
'\n': end,
|
'\n': end,
|
||||||
':': {type: 'operator', suggest: true, then: {
|
':': {type: 'operator', then: {
|
||||||
'': textToEnd,
|
'': textToEnd,
|
||||||
'\n': hiddenEnd,
|
'\n': hiddenEnd,
|
||||||
}},
|
}},
|
||||||
|
@ -144,15 +119,41 @@ define(['core/ArrayUtilities'], (array) => {
|
||||||
}},
|
}},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function simpleList(type, keywords, exit) {
|
||||||
|
const first = {};
|
||||||
|
const recur = Object.assign({}, exit);
|
||||||
|
|
||||||
|
keywords.forEach((keyword) => {
|
||||||
|
first[keyword] = {type, then: recur};
|
||||||
|
recur[keyword] = 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
function optionalKeywords(type, keywords, then) {
|
||||||
|
const result = Object.assign({}, then);
|
||||||
|
keywords.forEach((keyword) => {
|
||||||
|
result[keyword] = {type, then};
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const agentInfoList = optionalKeywords(
|
||||||
|
'keyword',
|
||||||
|
['a', 'an'],
|
||||||
|
simpleList('keyword', AGENT_INFO_TYPES, {'\n': end})
|
||||||
|
);
|
||||||
|
|
||||||
function makeSideNote(side) {
|
function makeSideNote(side) {
|
||||||
return {
|
return {
|
||||||
type: 'keyword',
|
type: 'keyword',
|
||||||
suggest: [side + ' of ', side + ': '],
|
suggest: [side + ' of ', side + ': '],
|
||||||
then: {
|
then: {
|
||||||
'of': {type: 'keyword', suggest: true, then: {
|
'of': {type: 'keyword', then: {
|
||||||
'': agentListToText,
|
'': agentListToText,
|
||||||
}},
|
}},
|
||||||
':': {type: 'operator', suggest: true, then: {
|
':': {type: 'operator', then: {
|
||||||
'': textToEnd,
|
'': textToEnd,
|
||||||
}},
|
}},
|
||||||
'': agentListToText,
|
'': agentListToText,
|
||||||
|
@ -160,8 +161,8 @@ define(['core/ArrayUtilities'], (array) => {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeOpBlock(exit, sourceExit) {
|
function makeOpBlock({exit, sourceExit, blankExit}) {
|
||||||
const op = {type: 'operator', suggest: true, then: {
|
const op = {type: 'operator', then: {
|
||||||
'+': CM_ERROR,
|
'+': CM_ERROR,
|
||||||
'-': CM_ERROR,
|
'-': CM_ERROR,
|
||||||
'*': CM_ERROR,
|
'*': CM_ERROR,
|
||||||
|
@ -169,14 +170,14 @@ define(['core/ArrayUtilities'], (array) => {
|
||||||
'': exit,
|
'': exit,
|
||||||
}};
|
}};
|
||||||
return {
|
return {
|
||||||
'+': {type: 'operator', suggest: true, then: {
|
'+': {type: 'operator', then: {
|
||||||
'+': CM_ERROR,
|
'+': CM_ERROR,
|
||||||
'-': CM_ERROR,
|
'-': CM_ERROR,
|
||||||
'*': op,
|
'*': op,
|
||||||
'!': CM_ERROR,
|
'!': CM_ERROR,
|
||||||
'': exit,
|
'': exit,
|
||||||
}},
|
}},
|
||||||
'-': {type: 'operator', suggest: true, then: {
|
'-': {type: 'operator', then: {
|
||||||
'+': CM_ERROR,
|
'+': CM_ERROR,
|
||||||
'-': CM_ERROR,
|
'-': CM_ERROR,
|
||||||
'*': op,
|
'*': op,
|
||||||
|
@ -189,27 +190,29 @@ define(['core/ArrayUtilities'], (array) => {
|
||||||
}},
|
}},
|
||||||
'': exit,
|
'': exit,
|
||||||
}},
|
}},
|
||||||
'*': {type: 'operator', suggest: true, then: Object.assign({
|
'*': {type: 'operator', then: Object.assign({
|
||||||
'+': op,
|
'+': op,
|
||||||
'-': op,
|
'-': op,
|
||||||
'*': CM_ERROR,
|
'*': CM_ERROR,
|
||||||
'!': CM_ERROR,
|
'!': CM_ERROR,
|
||||||
'': exit,
|
'': exit,
|
||||||
}, sourceExit)},
|
}, sourceExit || exit)},
|
||||||
'!': op,
|
'!': op,
|
||||||
'': exit,
|
'': blankExit || exit,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeCMConnect(arrows) {
|
function makeCMConnect(arrows) {
|
||||||
const connect = {
|
const connect = {
|
||||||
type: 'keyword',
|
type: 'keyword',
|
||||||
suggest: true,
|
then: Object.assign({}, makeOpBlock({
|
||||||
then: Object.assign({}, makeOpBlock(agentToOptText, {
|
exit: agentToOptText,
|
||||||
':': colonTextToEnd,
|
sourceExit: {
|
||||||
'\n': hiddenEnd,
|
':': colonTextToEnd,
|
||||||
|
'\n': hiddenEnd,
|
||||||
|
},
|
||||||
}), {
|
}), {
|
||||||
'...': {type: 'operator', suggest: true, then: {
|
'...': {type: 'operator', then: {
|
||||||
'': {
|
'': {
|
||||||
type: 'variable',
|
type: 'variable',
|
||||||
suggest: {known: 'DelayedAgent'},
|
suggest: {known: 'DelayedAgent'},
|
||||||
|
@ -228,7 +231,6 @@ define(['core/ArrayUtilities'], (array) => {
|
||||||
|
|
||||||
const labelIndicator = {
|
const labelIndicator = {
|
||||||
type: 'operator',
|
type: 'operator',
|
||||||
suggest: true,
|
|
||||||
override: 'Label',
|
override: 'Label',
|
||||||
then: {},
|
then: {},
|
||||||
};
|
};
|
||||||
|
@ -245,8 +247,9 @@ define(['core/ArrayUtilities'], (array) => {
|
||||||
suggest: {known: 'Agent'},
|
suggest: {known: 'Agent'},
|
||||||
then: Object.assign({
|
then: Object.assign({
|
||||||
'': 0,
|
'': 0,
|
||||||
|
}, connectors, {
|
||||||
':': labelIndicator,
|
':': labelIndicator,
|
||||||
}, connectors),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
const firstAgentDelayed = {
|
const firstAgentDelayed = {
|
||||||
|
@ -258,29 +261,39 @@ define(['core/ArrayUtilities'], (array) => {
|
||||||
}, connectors),
|
}, connectors),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const firstAgentNoFlags = Object.assign({}, firstAgent, {
|
||||||
|
then: Object.assign({}, firstAgent.then, {
|
||||||
|
'is': {type: 'keyword', then: agentInfoList},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
return Object.assign({
|
return Object.assign({
|
||||||
'...': {type: 'operator', suggest: true, then: {
|
'...': {type: 'operator', then: {
|
||||||
'': firstAgentDelayed,
|
'': firstAgentDelayed,
|
||||||
}},
|
}},
|
||||||
}, makeOpBlock(firstAgent, Object.assign({
|
}, makeOpBlock({
|
||||||
'': firstAgent,
|
exit: firstAgent,
|
||||||
':': hiddenLabelIndicator,
|
sourceExit: Object.assign({
|
||||||
}, connectors)));
|
'': firstAgent,
|
||||||
|
':': hiddenLabelIndicator,
|
||||||
|
}, connectors),
|
||||||
|
blankExit: firstAgentNoFlags,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
const group = {type: 'keyword', suggest: true, then: {
|
const group = {type: 'keyword', then: {
|
||||||
'': textToEnd,
|
'': textToEnd,
|
||||||
':': {type: 'operator', suggest: true, then: {
|
':': {type: 'operator', then: {
|
||||||
'': textToEnd,
|
'': textToEnd,
|
||||||
}},
|
}},
|
||||||
'\n': end,
|
'\n': end,
|
||||||
}};
|
}};
|
||||||
|
|
||||||
const BASE_THEN = {
|
const BASE_THEN = {
|
||||||
'title': {type: 'keyword', suggest: true, then: {
|
'title': {type: 'keyword', then: {
|
||||||
'': textToEnd,
|
'': textToEnd,
|
||||||
}},
|
}},
|
||||||
'theme': {type: 'keyword', suggest: true, then: {
|
'theme': {type: 'keyword', then: {
|
||||||
'': {
|
'': {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
suggest: {
|
suggest: {
|
||||||
|
@ -293,36 +306,36 @@ define(['core/ArrayUtilities'], (array) => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
'headers': {type: 'keyword', suggest: true, then: {
|
'headers': {type: 'keyword', then: {
|
||||||
'none': {type: 'keyword', suggest: true, then: {}},
|
'none': {type: 'keyword', then: {}},
|
||||||
'cross': {type: 'keyword', suggest: true, then: {}},
|
'cross': {type: 'keyword', then: {}},
|
||||||
'box': {type: 'keyword', suggest: true, then: {}},
|
'box': {type: 'keyword', then: {}},
|
||||||
'fade': {type: 'keyword', suggest: true, then: {}},
|
'fade': {type: 'keyword', then: {}},
|
||||||
'bar': {type: 'keyword', suggest: true, then: {}},
|
'bar': {type: 'keyword', then: {}},
|
||||||
}},
|
}},
|
||||||
'terminators': {type: 'keyword', suggest: true, then: {
|
'terminators': {type: 'keyword', then: {
|
||||||
'none': {type: 'keyword', suggest: true, then: {}},
|
'none': {type: 'keyword', then: {}},
|
||||||
'cross': {type: 'keyword', suggest: true, then: {}},
|
'cross': {type: 'keyword', then: {}},
|
||||||
'box': {type: 'keyword', suggest: true, then: {}},
|
'box': {type: 'keyword', then: {}},
|
||||||
'fade': {type: 'keyword', suggest: true, then: {}},
|
'fade': {type: 'keyword', then: {}},
|
||||||
'bar': {type: 'keyword', suggest: true, then: {}},
|
'bar': {type: 'keyword', then: {}},
|
||||||
}},
|
}},
|
||||||
'divider': {type: 'keyword', suggest: true, then: Object.assign({
|
'divider': {type: 'keyword', then: Object.assign({
|
||||||
'line': {type: 'keyword', suggest: true, then: divider},
|
'line': {type: 'keyword', then: divider},
|
||||||
'space': {type: 'keyword', suggest: true, then: divider},
|
'space': {type: 'keyword', then: divider},
|
||||||
'delay': {type: 'keyword', suggest: true, then: divider},
|
'delay': {type: 'keyword', then: divider},
|
||||||
'tear': {type: 'keyword', suggest: true, then: divider},
|
'tear': {type: 'keyword', then: divider},
|
||||||
}, divider)},
|
}, divider)},
|
||||||
'define': {type: 'keyword', suggest: true, then: {
|
'define': {type: 'keyword', then: {
|
||||||
'': aliasListToEnd,
|
'': aliasListToEnd,
|
||||||
'as': CM_ERROR,
|
'as': CM_ERROR,
|
||||||
}},
|
}},
|
||||||
'begin': {type: 'keyword', suggest: true, then: {
|
'begin': {type: 'keyword', then: {
|
||||||
'': aliasListToEnd,
|
'': aliasListToEnd,
|
||||||
'reference': refDef,
|
'reference': refDef,
|
||||||
'as': CM_ERROR,
|
'as': CM_ERROR,
|
||||||
}},
|
}},
|
||||||
'end': {type: 'keyword', suggest: true, then: {
|
'end': {type: 'keyword', then: {
|
||||||
'': aliasListToEnd,
|
'': aliasListToEnd,
|
||||||
'as': CM_ERROR,
|
'as': CM_ERROR,
|
||||||
'\n': end,
|
'\n': end,
|
||||||
|
@ -331,7 +344,7 @@ define(['core/ArrayUtilities'], (array) => {
|
||||||
'else': {type: 'keyword', suggest: ['else\n', 'else if: '], then: {
|
'else': {type: 'keyword', suggest: ['else\n', 'else if: '], then: {
|
||||||
'if': {type: 'keyword', suggest: 'if: ', then: {
|
'if': {type: 'keyword', suggest: 'if: ', then: {
|
||||||
'': textToEnd,
|
'': textToEnd,
|
||||||
':': {type: 'operator', suggest: true, then: {
|
':': {type: 'operator', then: {
|
||||||
'': textToEnd,
|
'': textToEnd,
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
|
@ -339,39 +352,47 @@ define(['core/ArrayUtilities'], (array) => {
|
||||||
}},
|
}},
|
||||||
'repeat': group,
|
'repeat': group,
|
||||||
'group': group,
|
'group': group,
|
||||||
'note': {type: 'keyword', suggest: true, then: {
|
'note': {type: 'keyword', then: {
|
||||||
'over': {type: 'keyword', suggest: true, then: {
|
'over': {type: 'keyword', then: {
|
||||||
'': agentListToText,
|
'': agentListToText,
|
||||||
}},
|
}},
|
||||||
'left': makeSideNote('left'),
|
'left': makeSideNote('left'),
|
||||||
'right': makeSideNote('right'),
|
'right': makeSideNote('right'),
|
||||||
'between': {type: 'keyword', suggest: true, then: {
|
'between': {type: 'keyword', then: {
|
||||||
'': agentList2ToText,
|
'': agentListTo({':': CM_ERROR}, agentListToText),
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
'state': {type: 'keyword', suggest: 'state over ', then: {
|
'state': {type: 'keyword', suggest: 'state over ', then: {
|
||||||
'over': {type: 'keyword', suggest: true, then: {
|
'over': {type: 'keyword', then: {
|
||||||
'': singleAgentToText,
|
'': {
|
||||||
|
type: 'variable',
|
||||||
|
suggest: {known: 'Agent'},
|
||||||
|
then: {
|
||||||
|
'': 0,
|
||||||
|
',': CM_ERROR,
|
||||||
|
':': colonTextToEnd,
|
||||||
|
},
|
||||||
|
},
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
'text': {type: 'keyword', suggest: true, then: {
|
'text': {type: 'keyword', then: {
|
||||||
'left': makeSideNote('left'),
|
'left': makeSideNote('left'),
|
||||||
'right': makeSideNote('right'),
|
'right': makeSideNote('right'),
|
||||||
}},
|
}},
|
||||||
'autolabel': {type: 'keyword', suggest: true, then: {
|
'autolabel': {type: 'keyword', then: {
|
||||||
'off': {type: 'keyword', suggest: true, then: {}},
|
'off': {type: 'keyword', then: {}},
|
||||||
'': textTo({'\n': end}, [
|
'': textTo({'\n': end}, [
|
||||||
{v: '<label>', suffix: '\n', q: true},
|
{v: '<label>', suffix: '\n', q: true},
|
||||||
{v: '[<inc>] <label>', suffix: '\n', q: true},
|
{v: '[<inc>] <label>', suffix: '\n', q: true},
|
||||||
{v: '[<inc 1,0.01>] <label>', suffix: '\n', q: true},
|
{v: '[<inc 1,0.01>] <label>', suffix: '\n', q: true},
|
||||||
]),
|
]),
|
||||||
}},
|
}},
|
||||||
'simultaneously': {type: 'keyword', suggest: true, then: {
|
'simultaneously': {type: 'keyword', then: {
|
||||||
':': {type: 'operator', suggest: true, then: {}},
|
':': {type: 'operator', then: {}},
|
||||||
'with': {type: 'keyword', suggest: true, then: {
|
'with': {type: 'keyword', then: {
|
||||||
'': {type: 'variable', suggest: {known: 'Label'}, then: {
|
'': {type: 'variable', suggest: {known: 'Label'}, then: {
|
||||||
'': 0,
|
'': 0,
|
||||||
':': {type: 'operator', suggest: true, then: {}},
|
':': {type: 'operator', then: {}},
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
|
@ -400,8 +421,8 @@ define(['core/ArrayUtilities'], (array) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return array.flatMap(suggestions, (suggest) => {
|
return array.flatMap(suggestions, (suggest) => {
|
||||||
if(suggest === true) {
|
if(suggest === false) {
|
||||||
return [cmCappedToken(token, current)];
|
return [];
|
||||||
} else if(typeof suggest === 'object') {
|
} else if(typeof suggest === 'object') {
|
||||||
if(suggest.known) {
|
if(suggest.known) {
|
||||||
return state['known' + suggest.known] || [];
|
return state['known' + suggest.known] || [];
|
||||||
|
@ -411,7 +432,7 @@ define(['core/ArrayUtilities'], (array) => {
|
||||||
} else if(typeof suggest === 'string' && suggest) {
|
} else if(typeof suggest === 'string' && suggest) {
|
||||||
return [{v: suggest, q: (token === '')}];
|
return [{v: suggest, q: (token === '')}];
|
||||||
} else {
|
} else {
|
||||||
return [];
|
return [cmCappedToken(token, current)];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -405,6 +405,22 @@ defineDescribe('Code Mirror Mode', [
|
||||||
{v: ' stuff', type: 'string'},
|
{v: ' stuff', type: 'string'},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('highlights agent info statements', () => {
|
||||||
|
cm.getDoc().setValue('A is a red database');
|
||||||
|
expect(getTokens(0)).toEqual([
|
||||||
|
{v: 'A', type: 'variable'},
|
||||||
|
{v: ' is', type: 'keyword'},
|
||||||
|
{v: ' a', type: 'keyword'},
|
||||||
|
{v: ' red', type: 'keyword'},
|
||||||
|
{v: ' database', type: 'keyword'},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects unknown info statements', () => {
|
||||||
|
cm.getDoc().setValue('A is a foobar');
|
||||||
|
expect(getTokens(0)[3].type).toContain('line-error');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('autocomplete', () => {
|
describe('autocomplete', () => {
|
||||||
|
@ -619,5 +635,31 @@ defineDescribe('Code Mirror Mode', [
|
||||||
const hints = getHintTexts({line: 1, ch: 4});
|
const hints = getHintTexts({line: 1, ch: 4});
|
||||||
expect(hints).toEqual(['woo ']);
|
expect(hints).toEqual(['woo ']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('suggests agent properties', () => {
|
||||||
|
cm.getDoc().setValue('A is a ');
|
||||||
|
const hints = getHintTexts({line: 0, ch: 7});
|
||||||
|
expect(hints).toContain('database ');
|
||||||
|
expect(hints).toContain('red ');
|
||||||
|
expect(hints).not.toContain('\n');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('suggests indefinite articles for agent properties', () => {
|
||||||
|
cm.getDoc().setValue('A is ');
|
||||||
|
const hints = getHintTexts({line: 0, ch: 5});
|
||||||
|
expect(hints).toContain('database ');
|
||||||
|
expect(hints).toContain('a ');
|
||||||
|
expect(hints).toContain('an ');
|
||||||
|
expect(hints).not.toContain('\n');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('suggests more agent properties after the first', () => {
|
||||||
|
cm.getDoc().setValue('A is a red ');
|
||||||
|
const hints = getHintTexts({line: 0, ch: 11});
|
||||||
|
expect(hints).toContain('database ');
|
||||||
|
expect(hints).toContain('\n');
|
||||||
|
expect(hints).not.toContain('a ');
|
||||||
|
expect(hints).not.toContain('an ');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -37,7 +37,7 @@ define(['core/ArrayUtilities'], (array) => {
|
||||||
return a.id === b.id;
|
return a.id === b.id;
|
||||||
},
|
},
|
||||||
make: (id, {anchorRight = false, isVirtualSource = false} = {}) => {
|
make: (id, {anchorRight = false, isVirtualSource = false} = {}) => {
|
||||||
return {id, anchorRight, isVirtualSource};
|
return {id, anchorRight, isVirtualSource, options: []};
|
||||||
},
|
},
|
||||||
indexOf: (list, gAgent) => {
|
indexOf: (list, gAgent) => {
|
||||||
return array.indexOf(list, gAgent, GAgent.equals);
|
return array.indexOf(list, gAgent, GAgent.equals);
|
||||||
|
@ -251,6 +251,7 @@ define(['core/ArrayUtilities'], (array) => {
|
||||||
'mark': this.handleMark.bind(this),
|
'mark': this.handleMark.bind(this),
|
||||||
'async': this.handleAsync.bind(this),
|
'async': this.handleAsync.bind(this),
|
||||||
'agent define': this.handleAgentDefine.bind(this),
|
'agent define': this.handleAgentDefine.bind(this),
|
||||||
|
'agent options': this.handleAgentOptions.bind(this),
|
||||||
'agent begin': this.handleAgentBegin.bind(this),
|
'agent begin': this.handleAgentBegin.bind(this),
|
||||||
'agent end': this.handleAgentEnd.bind(this),
|
'agent end': this.handleAgentEnd.bind(this),
|
||||||
'divider': this.handleDivider.bind(this),
|
'divider': this.handleDivider.bind(this),
|
||||||
|
@ -354,23 +355,23 @@ define(['core/ArrayUtilities'], (array) => {
|
||||||
|
|
||||||
validateGAgents(gAgents, {
|
validateGAgents(gAgents, {
|
||||||
allowGrouped = false,
|
allowGrouped = false,
|
||||||
rejectGrouped = false,
|
allowCovered = false,
|
||||||
allowVirtual = false,
|
allowVirtual = false,
|
||||||
} = {}) {
|
} = {}) {
|
||||||
/* jshint -W074 */ // agent validity checking requires several steps
|
|
||||||
gAgents.forEach((gAgent) => {
|
gAgents.forEach((gAgent) => {
|
||||||
const state = this.getGAgentState(gAgent);
|
const state = this.getGAgentState(gAgent);
|
||||||
if(state.covered) {
|
if(state.blocked && state.group === null) {
|
||||||
|
// used to be a group alias; can never be reused
|
||||||
|
throw new Error('Duplicate agent name: ' + gAgent.id);
|
||||||
|
}
|
||||||
|
if(!allowCovered && state.covered) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Agent ' + gAgent.id + ' is hidden behind group'
|
'Agent ' + gAgent.id + ' is hidden behind group'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if(rejectGrouped && state.group !== null) {
|
if(!allowGrouped && state.group !== null) {
|
||||||
throw new Error('Agent ' + gAgent.id + ' is in a group');
|
throw new Error('Agent ' + gAgent.id + ' is in a group');
|
||||||
}
|
}
|
||||||
if(state.blocked && (!allowGrouped || state.group === null)) {
|
|
||||||
throw new Error('Duplicate agent name: ' + gAgent.id);
|
|
||||||
}
|
|
||||||
if(!allowVirtual && gAgent.isVirtualSource) {
|
if(!allowVirtual && gAgent.isVirtualSource) {
|
||||||
throw new Error('cannot use message source here');
|
throw new Error('cannot use message source here');
|
||||||
}
|
}
|
||||||
|
@ -561,7 +562,7 @@ define(['core/ArrayUtilities'], (array) => {
|
||||||
|
|
||||||
makeGroupDetails(pAgents, alias) {
|
makeGroupDetails(pAgents, alias) {
|
||||||
const gAgents = pAgents.map(this.toGAgent);
|
const gAgents = pAgents.map(this.toGAgent);
|
||||||
this.validateGAgents(gAgents, {rejectGrouped: true});
|
this.validateGAgents(gAgents);
|
||||||
if(this.agentStates.has(alias)) {
|
if(this.agentStates.has(alias)) {
|
||||||
throw new Error('Duplicate agent name: ' + alias);
|
throw new Error('Duplicate agent name: ' + alias);
|
||||||
}
|
}
|
||||||
|
@ -992,8 +993,27 @@ define(['core/ArrayUtilities'], (array) => {
|
||||||
|
|
||||||
handleAgentDefine({agents}) {
|
handleAgentDefine({agents}) {
|
||||||
const gAgents = agents.map(this.toGAgent);
|
const gAgents = agents.map(this.toGAgent);
|
||||||
this.validateGAgents(gAgents);
|
this.validateGAgents(gAgents, {
|
||||||
this.defineGAgents(gAgents);
|
allowGrouped: true,
|
||||||
|
allowCovered: true,
|
||||||
|
});
|
||||||
|
array.mergeSets(this.gAgents, gAgents, GAgent.equals);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleAgentOptions({agent, options}) {
|
||||||
|
const gAgent = this.toGAgent(agent);
|
||||||
|
const gAgents = [gAgent];
|
||||||
|
this.validateGAgents(gAgents, {
|
||||||
|
allowGrouped: true,
|
||||||
|
allowCovered: true,
|
||||||
|
});
|
||||||
|
array.mergeSets(this.gAgents, gAgents, GAgent.equals);
|
||||||
|
|
||||||
|
this.gAgents
|
||||||
|
.filter(({id}) => (id === gAgent.id))
|
||||||
|
.forEach((storedGAgent) => {
|
||||||
|
array.mergeSets(storedGAgent.options, options);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleAgentBegin({agents, mode}) {
|
handleAgentBegin({agents, mode}) {
|
||||||
|
|
|
@ -58,6 +58,15 @@ defineDescribe('Sequence Generator', ['./Generator'], (Generator) => {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
agentOptions: (agentID, options, {ln = 0} = {}) => {
|
||||||
|
return {
|
||||||
|
type: 'agent options',
|
||||||
|
agent: makeParsedAgents([agentID])[0],
|
||||||
|
options,
|
||||||
|
ln,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
beginAgents: (agentIDs, {mode = 'box', ln = 0} = {}) => {
|
beginAgents: (agentIDs, {mode = 'box', ln = 0} = {}) => {
|
||||||
return {
|
return {
|
||||||
type: 'agent begin',
|
type: 'agent begin',
|
||||||
|
@ -159,8 +168,9 @@ defineDescribe('Sequence Generator', ['./Generator'], (Generator) => {
|
||||||
formattedLabel = any(),
|
formattedLabel = any(),
|
||||||
anchorRight = any(),
|
anchorRight = any(),
|
||||||
isVirtualSource = any(),
|
isVirtualSource = any(),
|
||||||
|
options = any(),
|
||||||
} = {}) => {
|
} = {}) => {
|
||||||
return {id, formattedLabel, anchorRight, isVirtualSource};
|
return {id, formattedLabel, anchorRight, isVirtualSource, options};
|
||||||
},
|
},
|
||||||
|
|
||||||
beginAgents: (agentIDs, {
|
beginAgents: (agentIDs, {
|
||||||
|
@ -452,6 +462,31 @@ defineDescribe('Sequence Generator', ['./Generator'], (Generator) => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('applies options to agents', () => {
|
||||||
|
const sequence = invoke([
|
||||||
|
PARSED.agentOptions('A', ['foo']),
|
||||||
|
]);
|
||||||
|
expect(sequence.agents).toEqual([
|
||||||
|
any(),
|
||||||
|
GENERATED.agent('A', {options: ['foo']}),
|
||||||
|
any(),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('combines agent options', () => {
|
||||||
|
const sequence = invoke([
|
||||||
|
PARSED.agentOptions('A', ['foo', 'bar']),
|
||||||
|
PARSED.agentOptions('B', ['zig']),
|
||||||
|
PARSED.agentOptions('A', ['zag', 'bar']),
|
||||||
|
]);
|
||||||
|
expect(sequence.agents).toEqual([
|
||||||
|
any(),
|
||||||
|
GENERATED.agent('A', {options: ['foo', 'bar', 'zag']}),
|
||||||
|
GENERATED.agent('B', {options: ['zig']}),
|
||||||
|
any(),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
it('converts aliases', () => {
|
it('converts aliases', () => {
|
||||||
const sequence = invoke([
|
const sequence = invoke([
|
||||||
PARSED.defineAgents([{name: 'Baz', alias: 'B', flags: []}]),
|
PARSED.defineAgents([{name: 'Baz', alias: 'B', flags: []}]),
|
||||||
|
@ -1268,6 +1303,24 @@ defineDescribe('Sequence Generator', ['./Generator'], (Generator) => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('ignores defines when setting block bounds', () => {
|
||||||
|
const sequence = invoke([
|
||||||
|
PARSED.blockBegin('if', 'abc'),
|
||||||
|
PARSED.connect(['A', 'B']),
|
||||||
|
PARSED.defineAgents(['C']),
|
||||||
|
PARSED.blockEnd(),
|
||||||
|
]);
|
||||||
|
expect(sequence.agents).toEqual([
|
||||||
|
GENERATED.agent('['),
|
||||||
|
GENERATED.agent('__BLOCK0['),
|
||||||
|
GENERATED.agent('A'),
|
||||||
|
GENERATED.agent('B'),
|
||||||
|
GENERATED.agent('__BLOCK0]'),
|
||||||
|
GENERATED.agent('C'),
|
||||||
|
GENERATED.agent(']'),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
it('ignores side agents when calculating block bounds', () => {
|
it('ignores side agents when calculating block bounds', () => {
|
||||||
const sequence = invoke([
|
const sequence = invoke([
|
||||||
PARSED.beginAgents(['A', 'B', 'C']),
|
PARSED.beginAgents(['A', 'B', 'C']),
|
||||||
|
@ -1755,6 +1808,24 @@ defineDescribe('Sequence Generator', ['./Generator'], (Generator) => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('rejects interactions with agents involved in references', () => {
|
||||||
|
expect(() => invoke([
|
||||||
|
PARSED.beginAgents(['A', 'B', 'C']),
|
||||||
|
PARSED.groupBegin('Bar', ['A', 'C']),
|
||||||
|
PARSED.endAgents(['A']),
|
||||||
|
PARSED.endAgents(['Bar']),
|
||||||
|
])).toThrow(new Error('Agent A is in a group at line 1'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects flags on agents involved in references', () => {
|
||||||
|
expect(() => invoke([
|
||||||
|
PARSED.beginAgents(['A', 'B', 'C', 'D']),
|
||||||
|
PARSED.groupBegin('Bar', ['A', 'C']),
|
||||||
|
PARSED.connect([{name: 'A', alias: '', flags: ['start']}, 'D']),
|
||||||
|
PARSED.endAgents(['Bar']),
|
||||||
|
])).toThrow(new Error('Agent A is in a group at line 1'));
|
||||||
|
});
|
||||||
|
|
||||||
it('rejects interactions with agents hidden beneath references', () => {
|
it('rejects interactions with agents hidden beneath references', () => {
|
||||||
expect(() => invoke([
|
expect(() => invoke([
|
||||||
PARSED.beginAgents(['A', 'B', 'C', 'D']),
|
PARSED.beginAgents(['A', 'B', 'C', 'D']),
|
||||||
|
@ -1762,6 +1833,20 @@ defineDescribe('Sequence Generator', ['./Generator'], (Generator) => {
|
||||||
PARSED.connect(['B', 'D']),
|
PARSED.connect(['B', 'D']),
|
||||||
PARSED.endAgents(['AC']),
|
PARSED.endAgents(['AC']),
|
||||||
])).toThrow(new Error('Agent B is hidden behind group at line 1'));
|
])).toThrow(new Error('Agent B is hidden behind group at line 1'));
|
||||||
|
|
||||||
|
expect(() => invoke([
|
||||||
|
PARSED.beginAgents(['A', 'B', 'C']),
|
||||||
|
PARSED.groupBegin('Bar', ['A', 'C']),
|
||||||
|
PARSED.endAgents(['B']),
|
||||||
|
PARSED.endAgents(['Bar']),
|
||||||
|
])).toThrow(new Error('Agent B is hidden behind group at line 1'));
|
||||||
|
|
||||||
|
expect(() => invoke([
|
||||||
|
PARSED.beginAgents(['A', 'B', 'C']),
|
||||||
|
PARSED.groupBegin('Bar', ['A', 'C']),
|
||||||
|
PARSED.note('note over', ['B']),
|
||||||
|
PARSED.endAgents(['Bar']),
|
||||||
|
])).toThrow(new Error('Agent B is hidden behind group at line 1'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('encompasses entire reference boxes in block statements', () => {
|
it('encompasses entire reference boxes in block statements', () => {
|
||||||
|
|
|
@ -562,6 +562,31 @@ define([
|
||||||
name: joinLabel(line, 0, line.length - 1),
|
name: joinLabel(line, 0, line.length - 1),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
(line) => { // options
|
||||||
|
const sepPos = findToken(line, 'is');
|
||||||
|
if(sepPos < 1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const indefiniteArticles = ['a', 'an'];
|
||||||
|
let optionsBegin = sepPos + 1;
|
||||||
|
if(indefiniteArticles.includes(tokenKeyword(line[optionsBegin]))) {
|
||||||
|
++ optionsBegin;
|
||||||
|
}
|
||||||
|
if(optionsBegin === line.length) {
|
||||||
|
throw makeError('Empty agent options', {b: array.last(line).e});
|
||||||
|
}
|
||||||
|
const agent = readAgent(line, 0, sepPos);
|
||||||
|
const options = [];
|
||||||
|
for(let i = optionsBegin; i < line.length; ++ i) {
|
||||||
|
options.push(line[i].v);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
type: 'agent options',
|
||||||
|
agent,
|
||||||
|
options,
|
||||||
|
};
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
function parseLine(line, {meta, stages}) {
|
function parseLine(line, {meta, stages}) {
|
||||||
|
|
|
@ -142,6 +142,57 @@ defineDescribe('Sequence Parser', ['./Parser'], (Parser) => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('propagates agent options', () => {
|
||||||
|
const parsed = parser.parse('Foo bar is zig zag');
|
||||||
|
expect(parsed.stages).toEqual([
|
||||||
|
{
|
||||||
|
type: 'agent options',
|
||||||
|
ln: jasmine.anything(),
|
||||||
|
agent: {
|
||||||
|
name: 'Foo bar',
|
||||||
|
alias: '',
|
||||||
|
flags: [],
|
||||||
|
},
|
||||||
|
options: ['zig', 'zag'],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('ignores indefinite articles in agent options', () => {
|
||||||
|
const parsed = parser.parse('Foo is a zig\nBar is an oom');
|
||||||
|
expect(parsed.stages).toEqual([
|
||||||
|
{
|
||||||
|
type: 'agent options',
|
||||||
|
ln: jasmine.anything(),
|
||||||
|
agent: {
|
||||||
|
name: 'Foo',
|
||||||
|
alias: '',
|
||||||
|
flags: [],
|
||||||
|
},
|
||||||
|
options: ['zig'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'agent options',
|
||||||
|
ln: jasmine.anything(),
|
||||||
|
agent: {
|
||||||
|
name: 'Bar',
|
||||||
|
alias: '',
|
||||||
|
flags: [],
|
||||||
|
},
|
||||||
|
options: ['oom'],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects empty agent options', () => {
|
||||||
|
expect(() => parser.parse('Foo is')).toThrow(new Error(
|
||||||
|
'Empty agent options at line 1, character 6'
|
||||||
|
));
|
||||||
|
expect(() => parser.parse('Foo is a')).toThrow(new Error(
|
||||||
|
'Empty agent options at line 1, character 8'
|
||||||
|
));
|
||||||
|
});
|
||||||
|
|
||||||
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([
|
||||||
|
|
|
@ -338,6 +338,7 @@ define([
|
||||||
y1: toY,
|
y1: toY,
|
||||||
width: agentInfo.currentRad * 2,
|
width: agentInfo.currentRad * 2,
|
||||||
className: 'agent-' + agentInfo.index + '-line',
|
className: 'agent-' + agentInfo.index + '-line',
|
||||||
|
options: agentInfo.options,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -474,6 +475,7 @@ define([
|
||||||
formattedLabel: agent.formattedLabel,
|
formattedLabel: agent.formattedLabel,
|
||||||
anchorRight: agent.anchorRight,
|
anchorRight: agent.anchorRight,
|
||||||
isVirtualSource: agent.isVirtualSource,
|
isVirtualSource: agent.isVirtualSource,
|
||||||
|
options: agent.options,
|
||||||
index,
|
index,
|
||||||
x: null,
|
x: null,
|
||||||
latestYStart: null,
|
latestYStart: null,
|
||||||
|
|
|
@ -56,18 +56,22 @@ defineDescribe('Sequence Renderer', [
|
||||||
id: '[',
|
id: '[',
|
||||||
formattedLabel: null,
|
formattedLabel: null,
|
||||||
anchorRight: true,
|
anchorRight: true,
|
||||||
|
options: [],
|
||||||
}, {
|
}, {
|
||||||
id: 'Col 1',
|
id: 'Col 1',
|
||||||
formattedLabel: format('Col 1!'),
|
formattedLabel: format('Col 1!'),
|
||||||
anchorRight: false,
|
anchorRight: false,
|
||||||
|
options: [],
|
||||||
}, {
|
}, {
|
||||||
id: 'Col 2',
|
id: 'Col 2',
|
||||||
formattedLabel: format('Col 2!'),
|
formattedLabel: format('Col 2!'),
|
||||||
anchorRight: false,
|
anchorRight: false,
|
||||||
|
options: [],
|
||||||
}, {
|
}, {
|
||||||
id: ']',
|
id: ']',
|
||||||
formattedLabel: null,
|
formattedLabel: null,
|
||||||
anchorRight: false,
|
anchorRight: false,
|
||||||
|
options: [],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
stages: [],
|
stages: [],
|
||||||
|
@ -81,8 +85,17 @@ defineDescribe('Sequence Renderer', [
|
||||||
renderer.render({
|
renderer.render({
|
||||||
meta: {title: [], code: 'hello'},
|
meta: {title: [], code: 'hello'},
|
||||||
agents: [
|
agents: [
|
||||||
{id: '[', formattedLabel: null, anchorRight: true},
|
{
|
||||||
{id: ']', formattedLabel: null, anchorRight: false},
|
id: '[',
|
||||||
|
formattedLabel: null,
|
||||||
|
anchorRight: true,
|
||||||
|
options: [],
|
||||||
|
}, {
|
||||||
|
id: ']',
|
||||||
|
formattedLabel: null,
|
||||||
|
anchorRight: false,
|
||||||
|
options: [],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
stages: [],
|
stages: [],
|
||||||
});
|
});
|
||||||
|
@ -99,10 +112,27 @@ defineDescribe('Sequence Renderer', [
|
||||||
renderer.render({
|
renderer.render({
|
||||||
meta: {title: []},
|
meta: {title: []},
|
||||||
agents: [
|
agents: [
|
||||||
{id: '[', formattedLabel: null, anchorRight: true},
|
{
|
||||||
{id: 'A', formattedLabel: format('A!'), anchorRight: false},
|
id: '[',
|
||||||
{id: 'B', formattedLabel: format('B!'), anchorRight: false},
|
formattedLabel: null,
|
||||||
{id: ']', formattedLabel: null, anchorRight: false},
|
anchorRight: true,
|
||||||
|
options: [],
|
||||||
|
}, {
|
||||||
|
id: 'A',
|
||||||
|
formattedLabel: format('A!'),
|
||||||
|
anchorRight: false,
|
||||||
|
options: [],
|
||||||
|
}, {
|
||||||
|
id: 'B',
|
||||||
|
formattedLabel: format('B!'),
|
||||||
|
anchorRight: false,
|
||||||
|
options: [],
|
||||||
|
}, {
|
||||||
|
id: ']',
|
||||||
|
formattedLabel: null,
|
||||||
|
anchorRight: false,
|
||||||
|
options: [],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
stages: [
|
stages: [
|
||||||
{type: 'agent begin', agentIDs: ['A', 'B'], mode: 'box'},
|
{type: 'agent begin', agentIDs: ['A', 'B'], mode: 'box'},
|
||||||
|
@ -129,11 +159,32 @@ defineDescribe('Sequence Renderer', [
|
||||||
renderer.render({
|
renderer.render({
|
||||||
meta: {title: []},
|
meta: {title: []},
|
||||||
agents: [
|
agents: [
|
||||||
{id: '[', formattedLabel: null, anchorRight: true},
|
{
|
||||||
{id: 'A', formattedLabel: format('A!'), anchorRight: false},
|
id: '[',
|
||||||
{id: 'B', formattedLabel: format('B!'), anchorRight: false},
|
formattedLabel: null,
|
||||||
{id: 'C', formattedLabel: format('C!'), anchorRight: false},
|
anchorRight: true,
|
||||||
{id: ']', formattedLabel: null, anchorRight: false},
|
options: [],
|
||||||
|
}, {
|
||||||
|
id: 'A',
|
||||||
|
formattedLabel: format('A!'),
|
||||||
|
anchorRight: false,
|
||||||
|
options: [],
|
||||||
|
}, {
|
||||||
|
id: 'B',
|
||||||
|
formattedLabel: format('B!'),
|
||||||
|
anchorRight: false,
|
||||||
|
options: [],
|
||||||
|
}, {
|
||||||
|
id: 'C',
|
||||||
|
formattedLabel: format('C!'),
|
||||||
|
anchorRight: false,
|
||||||
|
options: [],
|
||||||
|
}, {
|
||||||
|
id: ']',
|
||||||
|
formattedLabel: null,
|
||||||
|
anchorRight: false,
|
||||||
|
options: [],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
stages: [
|
stages: [
|
||||||
{
|
{
|
||||||
|
@ -178,12 +229,37 @@ defineDescribe('Sequence Renderer', [
|
||||||
renderer.render({
|
renderer.render({
|
||||||
meta: {title: []},
|
meta: {title: []},
|
||||||
agents: [
|
agents: [
|
||||||
{id: '[', formattedLabel: null, anchorRight: true},
|
{
|
||||||
{id: 'A', formattedLabel: format('A!'), anchorRight: false},
|
id: '[',
|
||||||
{id: 'B', formattedLabel: format('B!'), anchorRight: false},
|
formattedLabel: null,
|
||||||
{id: 'C', formattedLabel: format('C!'), anchorRight: false},
|
anchorRight: true,
|
||||||
{id: 'D', formattedLabel: format('D!'), anchorRight: false},
|
options: [],
|
||||||
{id: ']', formattedLabel: null, anchorRight: false},
|
}, {
|
||||||
|
id: 'A',
|
||||||
|
formattedLabel: format('A!'),
|
||||||
|
anchorRight: false,
|
||||||
|
options: [],
|
||||||
|
}, {
|
||||||
|
id: 'B',
|
||||||
|
formattedLabel: format('B!'),
|
||||||
|
anchorRight: false,
|
||||||
|
options: [],
|
||||||
|
}, {
|
||||||
|
id: 'C',
|
||||||
|
formattedLabel: format('C!'),
|
||||||
|
anchorRight: false,
|
||||||
|
options: [],
|
||||||
|
}, {
|
||||||
|
id: 'D',
|
||||||
|
formattedLabel: format('D!'),
|
||||||
|
anchorRight: false,
|
||||||
|
options: [],
|
||||||
|
}, {
|
||||||
|
id: ']',
|
||||||
|
formattedLabel: null,
|
||||||
|
anchorRight: false,
|
||||||
|
options: [],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
stages: [
|
stages: [
|
||||||
{type: 'agent begin', agentIDs: ['A', 'B'], mode: 'box'},
|
{type: 'agent begin', agentIDs: ['A', 'B'], mode: 'box'},
|
||||||
|
|
|
@ -12,8 +12,16 @@ define([
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
class CapBox {
|
class CapBox {
|
||||||
separation({formattedLabel}, env) {
|
getConfig(options, env) {
|
||||||
const config = env.theme.agentCap.box;
|
let config = null;
|
||||||
|
if(options.includes('database')) {
|
||||||
|
config = env.theme.agentCap.database;
|
||||||
|
}
|
||||||
|
return config || env.theme.agentCap.box;
|
||||||
|
}
|
||||||
|
|
||||||
|
separation({formattedLabel, options}, env) {
|
||||||
|
const config = this.getConfig(options, env);
|
||||||
const width = (
|
const width = (
|
||||||
env.textSizer.measure(config.labelAttrs, formattedLabel).width +
|
env.textSizer.measure(config.labelAttrs, formattedLabel).width +
|
||||||
config.padding.left +
|
config.padding.left +
|
||||||
|
@ -27,8 +35,8 @@ define([
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
topShift({formattedLabel}, env) {
|
topShift({formattedLabel, options}, env) {
|
||||||
const config = env.theme.agentCap.box;
|
const config = this.getConfig(options, env);
|
||||||
const height = (
|
const height = (
|
||||||
env.textSizer.measureHeight(config.labelAttrs, formattedLabel) +
|
env.textSizer.measureHeight(config.labelAttrs, formattedLabel) +
|
||||||
config.padding.top +
|
config.padding.top +
|
||||||
|
@ -37,8 +45,8 @@ define([
|
||||||
return Math.max(0, height - config.arrowBottom);
|
return Math.max(0, height - config.arrowBottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
render(y, {x, formattedLabel}, env) {
|
render(y, {x, formattedLabel, options}, env) {
|
||||||
const config = env.theme.agentCap.box;
|
const config = this.getConfig(options, env);
|
||||||
const clickable = env.makeRegion();
|
const clickable = env.makeRegion();
|
||||||
const text = SVGShapes.renderBoxedText(formattedLabel, {
|
const text = SVGShapes.renderBoxedText(formattedLabel, {
|
||||||
x,
|
x,
|
||||||
|
@ -84,13 +92,18 @@ define([
|
||||||
return config.size / 2;
|
return config.size / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
render(y, {x}, env) {
|
render(y, {x, options}, env) {
|
||||||
const config = env.theme.agentCap.cross;
|
const config = env.theme.agentCap.cross;
|
||||||
const d = config.size / 2;
|
const d = config.size / 2;
|
||||||
|
|
||||||
const clickable = env.makeRegion();
|
const clickable = env.makeRegion();
|
||||||
|
|
||||||
clickable.appendChild(config.render({x, y: y + d, radius: d}));
|
clickable.appendChild(config.render({
|
||||||
|
x,
|
||||||
|
y: y + d,
|
||||||
|
radius: d,
|
||||||
|
options,
|
||||||
|
}));
|
||||||
clickable.appendChild(svg.make('rect', {
|
clickable.appendChild(svg.make('rect', {
|
||||||
'x': x - d,
|
'x': x - d,
|
||||||
'y': y,
|
'y': y,
|
||||||
|
@ -129,7 +142,7 @@ define([
|
||||||
return config.height / 2;
|
return config.height / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
render(y, {x, formattedLabel}, env) {
|
render(y, {x, formattedLabel, options}, env) {
|
||||||
const boxCfg = env.theme.agentCap.box;
|
const boxCfg = env.theme.agentCap.box;
|
||||||
const barCfg = env.theme.agentCap.bar;
|
const barCfg = env.theme.agentCap.bar;
|
||||||
const width = (
|
const width = (
|
||||||
|
@ -145,6 +158,7 @@ define([
|
||||||
y,
|
y,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
|
options,
|
||||||
}));
|
}));
|
||||||
clickable.appendChild(svg.make('rect', {
|
clickable.appendChild(svg.make('rect', {
|
||||||
'x': x - width / 2,
|
'x': x - width / 2,
|
||||||
|
|
|
@ -24,7 +24,7 @@ define([
|
||||||
const arrow = this.getConfig(theme);
|
const arrow = this.getConfig(theme);
|
||||||
const join = arrow.attrs['stroke-linejoin'] || 'miter';
|
const join = arrow.attrs['stroke-linejoin'] || 'miter';
|
||||||
const t = arrow.attrs['stroke-width'] * 0.5;
|
const t = arrow.attrs['stroke-width'] * 0.5;
|
||||||
const lineStroke = theme.agentLineAttrs['stroke-width'] * 0.5;
|
const lineStroke = theme.agentLineAttrs['']['stroke-width'] * 0.5;
|
||||||
if(join === 'round') {
|
if(join === 'round') {
|
||||||
return lineStroke + t;
|
return lineStroke + t;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
<svg width="134.673828125" height="65.6" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="-5 -5 134.673828125 65.6"><metadata>begin A, B, C
|
||||||
|
A is a database
|
||||||
|
B is red
|
||||||
|
C is a red database
|
||||||
|
</metadata><defs></defs><defs><mask id="R0FullMask" maskUnits="userSpaceOnUse"><rect fill="#FFFFFF" x="-5" y="-5" width="134.673828125" height="65.6"></rect></mask><mask id="R0LineMask" maskUnits="userSpaceOnUse"><rect fill="#FFFFFF" x="-5" y="-5" width="134.673828125" height="65.6"></rect></mask></defs><g></g><g mask="url(#R0FullMask)"><g mask="url(#R0LineMask)"><line x1="24.001953125" y1="35.6" x2="24.001953125" y2="55.6" class="agent-1-line" fill="none" stroke="#000000" stroke-width="1"></line><line x1="62.005859375" y1="35.6" x2="62.005859375" y2="55.6" class="agent-2-line" fill="none" stroke="#CC0000" stroke-width="1"></line><line x1="100.3408203125" y1="35.6" x2="100.3408203125" y2="55.6" class="agent-3-line" fill="none" stroke="#CC0000" stroke-width="1"></line></g><g></g><g><g class="region"><g><rect x="10" y="0" width="28.00390625" height="35.6" rx="14.001953125" ry="5" fill="#FFFFFF" stroke="#000000" stroke-width="1" db-z="5"></rect><path d="M10 5a14.001953125 5 0 0 0 28.00390625 0" fill="none" stroke="#000000" stroke-width="1" db-z="5"></path></g><rect x="10" y="0" width="28.00390625" height="35.6" fill="transparent" class="outline"></rect><text x="24.001953125" font-family="sans-serif" font-size="12" line-height="1.3" text-anchor="middle" y="27">A</text></g><g class="region"><rect x="48.00390625" y="10" width="28.00390625" height="25.6" fill="#FFFFFF" stroke="#000000" stroke-width="1"></rect><rect x="48.00390625" y="10" width="28.00390625" height="25.6" fill="transparent" class="outline"></rect><text x="62.005859375" font-family="sans-serif" font-size="12" line-height="1.3" text-anchor="middle" y="27">B</text></g><g class="region"><g><rect x="86.0078125" y="0" width="28.666015625" height="35.6" rx="14.3330078125" ry="5" fill="#FFFFFF" stroke="#000000" stroke-width="1" db-z="5"></rect><path d="M86.0078125 5a14.3330078125 5 0 0 0 28.666015625 0" fill="none" stroke="#000000" stroke-width="1" db-z="5"></path></g><rect x="86.0078125" y="0" width="28.666015625" height="35.6" fill="transparent" class="outline"></rect><text x="100.3408203125" font-family="sans-serif" font-size="12" line-height="1.3" text-anchor="middle" y="27">C</text></g><g class="region"><rect x="19.001953125" y="45.6" width="10" height="10" fill="transparent" class="outline"></rect></g><g class="region"><rect x="57.005859375" y="45.6" width="10" height="10" fill="transparent" class="outline"></rect></g><g class="region"><rect x="95.3408203125" y="45.6" width="10" height="10" fill="transparent" class="outline"></rect></g></g></g><g></g></svg>
|
After Width: | Height: | Size: 2.7 KiB |
|
@ -9,4 +9,5 @@ define([], [
|
||||||
'Reference.svg',
|
'Reference.svg',
|
||||||
'ReferenceLayering.svg',
|
'ReferenceLayering.svg',
|
||||||
'Markdown.svg',
|
'Markdown.svg',
|
||||||
|
'AgentOptions.svg',
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -20,6 +20,14 @@ define([
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function optionsAttributes(attributes, options) {
|
||||||
|
let attrs = Object.assign({}, attributes['']);
|
||||||
|
options.forEach((opt) => {
|
||||||
|
Object.assign(attrs, attributes[opt] || {});
|
||||||
|
});
|
||||||
|
return attrs;
|
||||||
|
}
|
||||||
|
|
||||||
class BaseTheme {
|
class BaseTheme {
|
||||||
constructor({name, settings, blocks, notes, dividers}) {
|
constructor({name, settings, blocks, notes, dividers}) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
@ -47,7 +55,12 @@ define([
|
||||||
return this.dividers[type] || this.dividers[''];
|
return this.dividers[type] || this.dividers[''];
|
||||||
}
|
}
|
||||||
|
|
||||||
renderAgentLine({x, y0, y1, width, className}) {
|
optionsAttributes(attributes, options) {
|
||||||
|
return optionsAttributes(attributes, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderAgentLine({x, y0, y1, width, className, options}) {
|
||||||
|
const attrs = this.optionsAttributes(this.agentLineAttrs, options);
|
||||||
if(width > 0) {
|
if(width > 0) {
|
||||||
return svg.make('rect', Object.assign({
|
return svg.make('rect', Object.assign({
|
||||||
'x': x - width / 2,
|
'x': x - width / 2,
|
||||||
|
@ -55,7 +68,7 @@ define([
|
||||||
'width': width,
|
'width': width,
|
||||||
'height': y1 - y0,
|
'height': y1 - y0,
|
||||||
'class': className,
|
'class': className,
|
||||||
}, this.agentLineAttrs));
|
}, attrs));
|
||||||
} else {
|
} else {
|
||||||
return svg.make('line', Object.assign({
|
return svg.make('line', Object.assign({
|
||||||
'x1': x,
|
'x1': x,
|
||||||
|
@ -63,7 +76,7 @@ define([
|
||||||
'x2': x,
|
'x2': x,
|
||||||
'y2': y1,
|
'y2': y1,
|
||||||
'class': className,
|
'class': className,
|
||||||
}, this.agentLineAttrs));
|
}, attrs));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,6 +126,27 @@ define([
|
||||||
return g;
|
return g;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
BaseTheme.renderDB = (attrs, {x, y, width, height}) => {
|
||||||
|
const z = attrs['db-z'];
|
||||||
|
return svg.make('g', {}, [
|
||||||
|
svg.make('rect', Object.assign({
|
||||||
|
'x': x,
|
||||||
|
'y': y,
|
||||||
|
'width': width,
|
||||||
|
'height': height,
|
||||||
|
'rx': width / 2,
|
||||||
|
'ry': z,
|
||||||
|
}, attrs)),
|
||||||
|
svg.make('path', Object.assign({
|
||||||
|
'd': (
|
||||||
|
'M' + x + ' ' + (y + z) +
|
||||||
|
'a' + (width / 2) + ' ' + z +
|
||||||
|
' 0 0 0 ' + width + ' 0'
|
||||||
|
),
|
||||||
|
}, attrs, {'fill': 'none'})),
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
BaseTheme.renderCross = (attrs, {x, y, radius}) => {
|
BaseTheme.renderCross = (attrs, {x, y, radius}) => {
|
||||||
return svg.make('path', Object.assign({
|
return svg.make('path', Object.assign({
|
||||||
'd': (
|
'd': (
|
||||||
|
|
|
@ -43,6 +43,27 @@ define([
|
||||||
'text-anchor': 'middle',
|
'text-anchor': 'middle',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
database: {
|
||||||
|
padding: {
|
||||||
|
top: 15,
|
||||||
|
left: 10,
|
||||||
|
right: 10,
|
||||||
|
bottom: 5,
|
||||||
|
},
|
||||||
|
arrowBottom: 5 + 12 * 1.3 / 2,
|
||||||
|
boxRenderer: BaseTheme.renderDB.bind(null, {
|
||||||
|
'fill': '#FFFFFF',
|
||||||
|
'stroke': '#000000',
|
||||||
|
'stroke-width': 1,
|
||||||
|
'db-z': 5,
|
||||||
|
}),
|
||||||
|
labelAttrs: {
|
||||||
|
'font-family': FONT,
|
||||||
|
'font-size': 12,
|
||||||
|
'line-height': LINE_HEIGHT,
|
||||||
|
'text-anchor': 'middle',
|
||||||
|
},
|
||||||
|
},
|
||||||
cross: {
|
cross: {
|
||||||
size: 20,
|
size: 20,
|
||||||
render: BaseTheme.renderCross.bind(null, {
|
render: BaseTheme.renderCross.bind(null, {
|
||||||
|
@ -182,9 +203,14 @@ define([
|
||||||
},
|
},
|
||||||
|
|
||||||
agentLineAttrs: {
|
agentLineAttrs: {
|
||||||
'fill': 'none',
|
'': {
|
||||||
'stroke': '#000000',
|
'fill': 'none',
|
||||||
'stroke-width': 1,
|
'stroke': '#000000',
|
||||||
|
'stroke-width': 1,
|
||||||
|
},
|
||||||
|
'red': {
|
||||||
|
'stroke': '#CC0000',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,28 @@ define([
|
||||||
'text-anchor': 'middle',
|
'text-anchor': 'middle',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
database: {
|
||||||
|
padding: {
|
||||||
|
top: 5,
|
||||||
|
left: 3,
|
||||||
|
right: 3,
|
||||||
|
bottom: 1,
|
||||||
|
},
|
||||||
|
arrowBottom: 1 + 12 * 1.3 / 2,
|
||||||
|
boxRenderer: BaseTheme.renderDB.bind(null, {
|
||||||
|
'fill': '#FFFFFF',
|
||||||
|
'stroke': '#000000',
|
||||||
|
'stroke-width': 3,
|
||||||
|
'db-z': 2,
|
||||||
|
}),
|
||||||
|
labelAttrs: {
|
||||||
|
'font-family': FONT,
|
||||||
|
'font-weight': 'bold',
|
||||||
|
'font-size': 14,
|
||||||
|
'line-height': LINE_HEIGHT,
|
||||||
|
'text-anchor': 'middle',
|
||||||
|
},
|
||||||
|
},
|
||||||
cross: {
|
cross: {
|
||||||
size: 20,
|
size: 20,
|
||||||
render: BaseTheme.renderCross.bind(null, {
|
render: BaseTheme.renderCross.bind(null, {
|
||||||
|
@ -193,9 +215,14 @@ define([
|
||||||
},
|
},
|
||||||
|
|
||||||
agentLineAttrs: {
|
agentLineAttrs: {
|
||||||
'fill': 'none',
|
'': {
|
||||||
'stroke': '#000000',
|
'fill': 'none',
|
||||||
'stroke-width': 3,
|
'stroke': '#000000',
|
||||||
|
'stroke-width': 3,
|
||||||
|
},
|
||||||
|
'red': {
|
||||||
|
'stroke': '#DD0000',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,27 @@ define([
|
||||||
'text-anchor': 'middle',
|
'text-anchor': 'middle',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
database: {
|
||||||
|
padding: {
|
||||||
|
top: 12,
|
||||||
|
left: 8,
|
||||||
|
right: 8,
|
||||||
|
bottom: 4,
|
||||||
|
},
|
||||||
|
arrowBottom: 4 + 12 * 1.3 / 2,
|
||||||
|
boxRenderer: BaseTheme.renderDB.bind(null, {
|
||||||
|
'fill': '#FFFFFF',
|
||||||
|
'stroke': '#000000',
|
||||||
|
'stroke-width': 1,
|
||||||
|
'db-z': 4,
|
||||||
|
}),
|
||||||
|
labelAttrs: {
|
||||||
|
'font-family': FONT,
|
||||||
|
'font-size': 12,
|
||||||
|
'line-height': LINE_HEIGHT,
|
||||||
|
'text-anchor': 'middle',
|
||||||
|
},
|
||||||
|
},
|
||||||
cross: {
|
cross: {
|
||||||
size: 16,
|
size: 16,
|
||||||
render: BaseTheme.renderCross.bind(null, {
|
render: BaseTheme.renderCross.bind(null, {
|
||||||
|
@ -189,9 +210,14 @@ define([
|
||||||
},
|
},
|
||||||
|
|
||||||
agentLineAttrs: {
|
agentLineAttrs: {
|
||||||
'fill': 'none',
|
'': {
|
||||||
'stroke': '#000000',
|
'fill': 'none',
|
||||||
'stroke-width': 1,
|
'stroke': '#000000',
|
||||||
|
'stroke-width': 1,
|
||||||
|
},
|
||||||
|
'red': {
|
||||||
|
'stroke': '#AA0000',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,25 @@ define([
|
||||||
},
|
},
|
||||||
boxRenderer: null,
|
boxRenderer: null,
|
||||||
},
|
},
|
||||||
|
database: {
|
||||||
|
padding: {
|
||||||
|
top: 15,
|
||||||
|
left: 10,
|
||||||
|
right: 10,
|
||||||
|
bottom: 5,
|
||||||
|
},
|
||||||
|
arrowBottom: 5 + 12 * 1.3 / 2,
|
||||||
|
boxRenderer: BaseTheme.renderDB.bind(null, Object.assign({
|
||||||
|
'fill': '#FFFFFF',
|
||||||
|
'db-z': 5,
|
||||||
|
}, PENCIL.normal)),
|
||||||
|
labelAttrs: {
|
||||||
|
'font-family': FONT,
|
||||||
|
'font-size': 12,
|
||||||
|
'line-height': LINE_HEIGHT,
|
||||||
|
'text-anchor': 'middle',
|
||||||
|
},
|
||||||
|
},
|
||||||
cross: {
|
cross: {
|
||||||
size: 15,
|
size: 15,
|
||||||
render: null,
|
render: null,
|
||||||
|
@ -172,9 +191,12 @@ define([
|
||||||
},
|
},
|
||||||
|
|
||||||
agentLineAttrs: {
|
agentLineAttrs: {
|
||||||
'fill': 'none',
|
'': Object.assign({
|
||||||
'stroke': '#000000',
|
'fill': 'none',
|
||||||
'stroke-width': 1,
|
}, PENCIL.normal),
|
||||||
|
'red': {
|
||||||
|
'stroke': 'rgba(200,40,0,0.8)',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -546,7 +568,9 @@ define([
|
||||||
'd': line.nodes,
|
'd': line.nodes,
|
||||||
'fill': 'none',
|
'fill': 'none',
|
||||||
'stroke-dasharray': lineOptions.dash ? '6, 5' : 'none',
|
'stroke-dasharray': lineOptions.dash ? '6, 5' : 'none',
|
||||||
}, lineOptions.thick ? PENCIL.thick : PENCIL.normal));
|
}, lineOptions.attrs || (
|
||||||
|
lineOptions.thick ? PENCIL.thick : PENCIL.normal
|
||||||
|
)));
|
||||||
return shape;
|
return shape;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -575,11 +599,11 @@ define([
|
||||||
return lT.nodes + lR.nodes + lB.nodes + lL.nodes;
|
return lT.nodes + lR.nodes + lB.nodes + lL.nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderBox(position, {fill = null, thick = false} = {}) {
|
renderBox(position, {fill = null, thick = false, attrs = null} = {}) {
|
||||||
return svg.make('path', Object.assign({
|
return svg.make('path', Object.assign({
|
||||||
'd': this.boxNodes(position),
|
'd': this.boxNodes(position),
|
||||||
'fill': fill || '#FFFFFF',
|
'fill': fill || '#FFFFFF',
|
||||||
}, thick ? PENCIL.thick : PENCIL.normal));
|
}, attrs || (thick ? PENCIL.thick : PENCIL.normal)));
|
||||||
}
|
}
|
||||||
|
|
||||||
renderNote({x, y, width, height}) {
|
renderNote({x, y, width, height}) {
|
||||||
|
@ -905,21 +929,22 @@ define([
|
||||||
}, PENCIL.normal));
|
}, PENCIL.normal));
|
||||||
}
|
}
|
||||||
|
|
||||||
renderAgentLine({x, y0, y1, width, className}) {
|
renderAgentLine({x, y0, y1, width, className, options}) {
|
||||||
|
const attrs = this.optionsAttributes(this.agentLineAttrs, options);
|
||||||
if(width > 0) {
|
if(width > 0) {
|
||||||
const shape = this.renderBox({
|
const shape = this.renderBox({
|
||||||
x: x - width / 2,
|
x: x - width / 2,
|
||||||
y: y0,
|
y: y0,
|
||||||
width,
|
width,
|
||||||
height: y1 - y0,
|
height: y1 - y0,
|
||||||
}, {fill: 'none'});
|
}, {fill: 'none', attrs});
|
||||||
shape.setAttribute('class', className);
|
shape.setAttribute('class', className);
|
||||||
return shape;
|
return shape;
|
||||||
} else {
|
} else {
|
||||||
const shape = this.renderLine(
|
const shape = this.renderLine(
|
||||||
{x, y: y0},
|
{x, y: y0},
|
||||||
{x, y: y1},
|
{x, y: y1},
|
||||||
{varY: 0.3}
|
{varY: 0.3, attrs}
|
||||||
);
|
);
|
||||||
shape.setAttribute('class', className);
|
shape.setAttribute('class', className);
|
||||||
return shape;
|
return shape;
|
||||||
|
|
Loading…
Reference in New Issue