Linter fixes
This commit is contained in:
parent
2e708ebb4d
commit
c58b8f7a22
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
@ -1,12 +1,18 @@
|
||||||
/* eslint-disable max-lines */
|
/*
|
||||||
/* eslint-disable sort-keys */ // Maybe later
|
* The order of commands inside "then" blocks directly influences the
|
||||||
/* eslint-disable complexity */ // Temporary ignore while switching linter
|
* order they are displayed to the user in autocomplete menus.
|
||||||
|
* This relies on the fact that common JS engines maintain insertion
|
||||||
|
* order in objects, though this is not guaranteed. It could be switched
|
||||||
|
* to use Map objects instead for strict compliance, at the cost of
|
||||||
|
* extra syntax.
|
||||||
|
*/
|
||||||
|
/* eslint-disable sort-keys */
|
||||||
|
|
||||||
import {flatMap, last, mergeSets} from '../../core/ArrayUtilities.mjs';
|
import {flatMap, last, mergeSets} from '../../core/ArrayUtilities.mjs';
|
||||||
|
|
||||||
const CM_ERROR = {type: 'error line-error', suggest: false, then: {'': 0}};
|
const CM_ERROR = {type: 'error line-error', suggest: [], then: {'': 0}};
|
||||||
|
|
||||||
function textTo(exit, suggest = false) {
|
function textTo(exit, suggest = []) {
|
||||||
return {
|
return {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
suggest,
|
suggest,
|
||||||
|
@ -29,19 +35,10 @@ const AGENT_INFO_TYPES = [
|
||||||
];
|
];
|
||||||
|
|
||||||
const makeCommands = ((() => {
|
const makeCommands = ((() => {
|
||||||
/*
|
|
||||||
* The order of commands inside "then" blocks directly influences the
|
|
||||||
* order they are displayed to the user in autocomplete menus.
|
|
||||||
* This relies on the fact that common JS engines maintain insertion
|
|
||||||
* order in objects, though this is not guaranteed. It could be switched
|
|
||||||
* to use Map objects instead for strict compliance, at the cost of
|
|
||||||
* extra syntax.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function agentListTo(exit, next = 1) {
|
function agentListTo(exit, next = 1) {
|
||||||
return {
|
return {
|
||||||
type: 'variable',
|
type: 'variable',
|
||||||
suggest: {known: 'Agent'},
|
suggest: [{known: 'Agent'}],
|
||||||
then: Object.assign({}, exit, {
|
then: Object.assign({}, exit, {
|
||||||
'': 0,
|
'': 0,
|
||||||
',': {type: 'operator', then: {'': next}},
|
',': {type: 'operator', then: {'': next}},
|
||||||
|
@ -49,8 +46,8 @@ const makeCommands = ((() => {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const end = {type: '', suggest: '\n', then: {}};
|
const end = {type: '', suggest: ['\n'], then: {}};
|
||||||
const hiddenEnd = {type: '', suggest: false, then: {}};
|
const hiddenEnd = {type: '', suggest: [], then: {}};
|
||||||
const textToEnd = textTo({'\n': end});
|
const textToEnd = textTo({'\n': end});
|
||||||
const colonTextToEnd = {
|
const colonTextToEnd = {
|
||||||
type: 'operator',
|
type: 'operator',
|
||||||
|
@ -59,7 +56,7 @@ const makeCommands = ((() => {
|
||||||
const aliasListToEnd = agentListTo({
|
const aliasListToEnd = agentListTo({
|
||||||
'\n': end,
|
'\n': end,
|
||||||
'as': {type: 'keyword', then: {
|
'as': {type: 'keyword', then: {
|
||||||
'': {type: 'variable', suggest: {known: 'Agent'}, then: {
|
'': {type: 'variable', suggest: [{known: 'Agent'}], then: {
|
||||||
'': 0,
|
'': 0,
|
||||||
',': {type: 'operator', then: {'': 3}},
|
',': {type: 'operator', then: {'': 3}},
|
||||||
'\n': end,
|
'\n': end,
|
||||||
|
@ -70,7 +67,7 @@ const makeCommands = ((() => {
|
||||||
|
|
||||||
const agentToOptText = {
|
const agentToOptText = {
|
||||||
type: 'variable',
|
type: 'variable',
|
||||||
suggest: {known: 'Agent'},
|
suggest: [{known: 'Agent'}],
|
||||||
then: {
|
then: {
|
||||||
'': 0,
|
'': 0,
|
||||||
':': {type: 'operator', then: {
|
':': {type: 'operator', then: {
|
||||||
|
@ -86,7 +83,7 @@ const makeCommands = ((() => {
|
||||||
'as': {type: 'keyword', then: {
|
'as': {type: 'keyword', then: {
|
||||||
'': {
|
'': {
|
||||||
type: 'variable',
|
type: 'variable',
|
||||||
suggest: {known: 'Agent'},
|
suggest: [{known: 'Agent'}],
|
||||||
then: {
|
then: {
|
||||||
'': 0,
|
'': 0,
|
||||||
'\n': end,
|
'\n': end,
|
||||||
|
@ -217,7 +214,7 @@ const makeCommands = ((() => {
|
||||||
'...': {type: 'operator', then: {
|
'...': {type: 'operator', then: {
|
||||||
'': {
|
'': {
|
||||||
type: 'variable',
|
type: 'variable',
|
||||||
suggest: {known: 'DelayedAgent'},
|
suggest: [{known: 'DelayedAgent'}],
|
||||||
then: {
|
then: {
|
||||||
'': 0,
|
'': 0,
|
||||||
':': CM_ERROR,
|
':': CM_ERROR,
|
||||||
|
@ -239,14 +236,14 @@ const makeCommands = ((() => {
|
||||||
|
|
||||||
const hiddenLabelIndicator = {
|
const hiddenLabelIndicator = {
|
||||||
type: 'operator',
|
type: 'operator',
|
||||||
suggest: false,
|
suggest: [],
|
||||||
override: 'Label',
|
override: 'Label',
|
||||||
then: {},
|
then: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
const firstAgent = {
|
const firstAgent = {
|
||||||
type: 'variable',
|
type: 'variable',
|
||||||
suggest: {known: 'Agent'},
|
suggest: [{known: 'Agent'}],
|
||||||
then: Object.assign({
|
then: Object.assign({
|
||||||
'': 0,
|
'': 0,
|
||||||
}, connectors, {
|
}, connectors, {
|
||||||
|
@ -256,7 +253,7 @@ const makeCommands = ((() => {
|
||||||
|
|
||||||
const firstAgentDelayed = {
|
const firstAgentDelayed = {
|
||||||
type: 'variable',
|
type: 'variable',
|
||||||
suggest: {known: 'DelayedAgent'},
|
suggest: [{known: 'DelayedAgent'}],
|
||||||
then: Object.assign({
|
then: Object.assign({
|
||||||
'': 0,
|
'': 0,
|
||||||
':': hiddenLabelIndicator,
|
':': hiddenLabelIndicator,
|
||||||
|
@ -298,10 +295,7 @@ const makeCommands = ((() => {
|
||||||
'theme': {type: 'keyword', then: {
|
'theme': {type: 'keyword', then: {
|
||||||
'': {
|
'': {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
suggest: {
|
suggest: [{global: 'themes', suffix: '\n'}],
|
||||||
global: 'themes',
|
|
||||||
suffix: '\n',
|
|
||||||
},
|
|
||||||
then: {
|
then: {
|
||||||
'': 0,
|
'': 0,
|
||||||
'\n': end,
|
'\n': end,
|
||||||
|
@ -344,7 +338,7 @@ const makeCommands = ((() => {
|
||||||
}},
|
}},
|
||||||
'if': commonGroup,
|
'if': commonGroup,
|
||||||
'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', then: {
|
':': {type: 'operator', then: {
|
||||||
'': textToEnd,
|
'': textToEnd,
|
||||||
|
@ -364,11 +358,11 @@ const makeCommands = ((() => {
|
||||||
'': agentListTo({':': CM_ERROR}, agentListToText),
|
'': agentListTo({':': CM_ERROR}, agentListToText),
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
'state': {type: 'keyword', suggest: 'state over ', then: {
|
'state': {type: 'keyword', suggest: ['state over '], then: {
|
||||||
'over': {type: 'keyword', then: {
|
'over': {type: 'keyword', then: {
|
||||||
'': {
|
'': {
|
||||||
type: 'variable',
|
type: 'variable',
|
||||||
suggest: {known: 'Agent'},
|
suggest: [{known: 'Agent'}],
|
||||||
then: {
|
then: {
|
||||||
'': 0,
|
'': 0,
|
||||||
',': CM_ERROR,
|
',': CM_ERROR,
|
||||||
|
@ -392,7 +386,7 @@ const makeCommands = ((() => {
|
||||||
'simultaneously': {type: 'keyword', then: {
|
'simultaneously': {type: 'keyword', then: {
|
||||||
':': {type: 'operator', then: {}},
|
':': {type: 'operator', then: {}},
|
||||||
'with': {type: 'keyword', then: {
|
'with': {type: 'keyword', then: {
|
||||||
'': {type: 'variable', suggest: {known: 'Label'}, then: {
|
'': {type: 'variable', suggest: [{known: 'Label'}], then: {
|
||||||
'': 0,
|
'': 0,
|
||||||
':': {type: 'operator', then: {}},
|
':': {type: 'operator', then: {}},
|
||||||
}},
|
}},
|
||||||
|
@ -406,33 +400,32 @@ const makeCommands = ((() => {
|
||||||
});
|
});
|
||||||
})());
|
})());
|
||||||
|
|
||||||
|
/* eslint-enable sort-keys */
|
||||||
|
|
||||||
function cmCappedToken(token, current) {
|
function cmCappedToken(token, current) {
|
||||||
if(Object.keys(current.then).length > 0) {
|
if(Object.keys(current.then).length > 0) {
|
||||||
return {v: token, suffix: ' ', q: false};
|
return {q: false, suffix: ' ', v: token};
|
||||||
} else {
|
} else {
|
||||||
return {v: token, suffix: '\n', q: false};
|
return {q: false, suffix: '\n', v: token};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function cmGetSuggestions(state, token, current) {
|
function cmGetSuggestions(state, token, current) {
|
||||||
let suggestions = current.suggest;
|
const suggestions = current.suggest || [''];
|
||||||
if(!Array.isArray(suggestions)) {
|
|
||||||
suggestions = [suggestions];
|
|
||||||
}
|
|
||||||
|
|
||||||
return flatMap(suggestions, (suggest) => {
|
return flatMap(suggestions, (suggest) => {
|
||||||
if(suggest === false) {
|
if(typeof suggest === 'object') {
|
||||||
return [];
|
|
||||||
} else if(typeof suggest === 'object') {
|
|
||||||
if(suggest.known) {
|
if(suggest.known) {
|
||||||
return state['known' + suggest.known] || [];
|
return state['known' + suggest.known] || [];
|
||||||
} else {
|
} else {
|
||||||
return [suggest];
|
return [suggest];
|
||||||
}
|
}
|
||||||
} else if(typeof suggest === 'string' && suggest) {
|
} else if(suggest === '') {
|
||||||
return [{v: suggest, q: (token === '')}];
|
|
||||||
} else {
|
|
||||||
return [cmCappedToken(token, current)];
|
return [cmCappedToken(token, current)];
|
||||||
|
} else if(typeof suggest === 'string') {
|
||||||
|
return [{q: (token === ''), v: suggest}];
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid suggestion type ' + suggest);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -454,30 +447,40 @@ function cmMakeCompletions(state, path) {
|
||||||
return comp;
|
return comp;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateSuggestion(state, locals, token, {suggest, override}) {
|
function getSuggestionCategory(suggestions) {
|
||||||
let known = null;
|
for(const suggestion of suggestions) {
|
||||||
if(typeof suggest === 'object' && suggest.known) {
|
if(typeof suggestion === 'object' && suggestion.known) {
|
||||||
known = suggest.known;
|
return suggestion.known;
|
||||||
}
|
}
|
||||||
if(locals.type && known !== locals.type) {
|
|
||||||
if(override) {
|
|
||||||
locals.type = override;
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function appendToken(base, token) {
|
||||||
|
return base + (base ? token.s : '') + token.v;
|
||||||
|
}
|
||||||
|
|
||||||
|
function storeKnownEntity(state, type, value) {
|
||||||
mergeSets(
|
mergeSets(
|
||||||
state['known' + locals.type],
|
state['known' + type],
|
||||||
[{v: locals.value, suffix: ' ', q: true}],
|
[{q: true, suffix: ' ', v: value}],
|
||||||
suggestionsEqual
|
suggestionsEqual
|
||||||
);
|
);
|
||||||
locals.type = '';
|
}
|
||||||
|
|
||||||
|
function updateKnownEntities(state, locals, token, current) {
|
||||||
|
const known = getSuggestionCategory(current.suggest || ['']);
|
||||||
|
|
||||||
|
if(locals.type && known !== locals.type) {
|
||||||
|
storeKnownEntity(state, current.override || locals.type, locals.value);
|
||||||
locals.value = '';
|
locals.value = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if(known) {
|
if(known) {
|
||||||
|
locals.value = appendToken(locals.value, token);
|
||||||
|
}
|
||||||
|
|
||||||
locals.type = known;
|
locals.type = known;
|
||||||
if(locals.value) {
|
|
||||||
locals.value += token.s;
|
|
||||||
}
|
|
||||||
locals.value += token.v;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function cmCheckToken(state, eol, commands) {
|
function cmCheckToken(state, eol, commands) {
|
||||||
|
@ -506,10 +509,10 @@ function cmCheckToken(state, eol, commands) {
|
||||||
path.push(found || CM_ERROR);
|
path.push(found || CM_ERROR);
|
||||||
}
|
}
|
||||||
current = last(path);
|
current = last(path);
|
||||||
updateSuggestion(state, suggestions, token, current);
|
updateKnownEntities(state, suggestions, token, current);
|
||||||
});
|
});
|
||||||
if(eol) {
|
if(eol) {
|
||||||
updateSuggestion(state, suggestions, null, {});
|
updateKnownEntities(state, suggestions, null, {});
|
||||||
}
|
}
|
||||||
state.nextCompletions = cmMakeCompletions(state, path);
|
state.nextCompletions = cmMakeCompletions(state, path);
|
||||||
state.valid = (
|
state.valid = (
|
||||||
|
@ -522,11 +525,13 @@ function cmCheckToken(state, eol, commands) {
|
||||||
function getInitialToken(block) {
|
function getInitialToken(block) {
|
||||||
const baseToken = (block.baseToken || {});
|
const baseToken = (block.baseToken || {});
|
||||||
return {
|
return {
|
||||||
value: baseToken.v || '',
|
|
||||||
quoted: baseToken.q || false,
|
quoted: baseToken.q || false,
|
||||||
|
value: baseToken.v || '',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const NO_TOKEN = -1;
|
||||||
|
|
||||||
export default class Mode {
|
export default class Mode {
|
||||||
constructor(tokenDefinitions, arrows) {
|
constructor(tokenDefinitions, arrows) {
|
||||||
this.tokenDefinitions = tokenDefinitions;
|
this.tokenDefinitions = tokenDefinitions;
|
||||||
|
@ -536,20 +541,20 @@ export default class Mode {
|
||||||
|
|
||||||
startState() {
|
startState() {
|
||||||
return {
|
return {
|
||||||
currentType: -1,
|
beginCompletions: cmMakeCompletions({}, [this.commands]),
|
||||||
|
completions: [],
|
||||||
current: '',
|
current: '',
|
||||||
currentSpace: '',
|
|
||||||
currentQuoted: false,
|
currentQuoted: false,
|
||||||
|
currentSpace: '',
|
||||||
|
currentType: NO_TOKEN,
|
||||||
|
indent: 0,
|
||||||
|
isVar: true,
|
||||||
knownAgent: [],
|
knownAgent: [],
|
||||||
knownDelayedAgent: [],
|
knownDelayedAgent: [],
|
||||||
knownLabel: [],
|
knownLabel: [],
|
||||||
beginCompletions: cmMakeCompletions({}, [this.commands]),
|
line: [],
|
||||||
completions: [],
|
|
||||||
nextCompletions: [],
|
nextCompletions: [],
|
||||||
valid: true,
|
valid: true,
|
||||||
isVar: true,
|
|
||||||
line: [],
|
|
||||||
indent: 0,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -588,14 +593,14 @@ export default class Mode {
|
||||||
|
|
||||||
_addToken(state) {
|
_addToken(state) {
|
||||||
state.line.push({
|
state.line.push({
|
||||||
v: state.current,
|
|
||||||
s: state.currentSpace,
|
|
||||||
q: state.currentQuoted,
|
q: state.currentQuoted,
|
||||||
|
s: state.currentSpace,
|
||||||
|
v: state.current,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_tokenEndFound(stream, state, block, match) {
|
_tokenEndFound(stream, state, block, match) {
|
||||||
state.currentType = -1;
|
state.currentType = NO_TOKEN;
|
||||||
if(block.includeEnd) {
|
if(block.includeEnd) {
|
||||||
state.current += match[0];
|
state.current += match[0];
|
||||||
}
|
}
|
||||||
|
@ -636,21 +641,33 @@ export default class Mode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_tokenContinueOrBegin(stream, state) {
|
||||||
|
if(state.currentType === NO_TOKEN) {
|
||||||
|
if(stream.sol()) {
|
||||||
|
state.line.length = 0;
|
||||||
|
}
|
||||||
|
if(!this._tokenBegin(stream, state)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this._tokenEnd(stream, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
_isLineTerminated(state) {
|
||||||
|
return state.currentType !== NO_TOKEN || state.valid;
|
||||||
|
}
|
||||||
|
|
||||||
token(stream, state) {
|
token(stream, state) {
|
||||||
state.completions = state.nextCompletions;
|
state.completions = state.nextCompletions;
|
||||||
state.isVar = true;
|
state.isVar = true;
|
||||||
if(stream.sol() && state.currentType === -1) {
|
|
||||||
state.line.length = 0;
|
const type = this._tokenContinueOrBegin(stream, state);
|
||||||
}
|
|
||||||
let type = '';
|
if(stream.eol() && !this._isLineTerminated(state)) {
|
||||||
if(state.currentType !== -1 || this._tokenBegin(stream, state)) {
|
|
||||||
type = this._tokenEnd(stream, state);
|
|
||||||
}
|
|
||||||
if(state.currentType === -1 && stream.eol() && !state.valid) {
|
|
||||||
return 'line-error ' + type;
|
return 'line-error ' + type;
|
||||||
} else {
|
|
||||||
return type;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
indent(state) {
|
indent(state) {
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
/* eslint-disable max-lines */
|
|
||||||
/* eslint-disable max-statements */
|
/* eslint-disable max-statements */
|
||||||
/* eslint-disable sort-keys */ // Maybe later
|
|
||||||
|
|
||||||
import SequenceDiagram from '../SequenceDiagram.mjs';
|
import SequenceDiagram from '../SequenceDiagram.mjs';
|
||||||
|
|
||||||
|
@ -10,17 +8,17 @@ describe('Code Mirror Mode', () => {
|
||||||
SequenceDiagram.registerCodeMirrorMode(CM);
|
SequenceDiagram.registerCodeMirrorMode(CM);
|
||||||
|
|
||||||
const cm = new CM(null, {
|
const cm = new CM(null, {
|
||||||
value: '',
|
|
||||||
mode: 'sequence',
|
|
||||||
globals: {
|
globals: {
|
||||||
themes: ['Theme', 'Other Theme'],
|
themes: ['Theme', 'Other Theme'],
|
||||||
},
|
},
|
||||||
|
mode: 'sequence',
|
||||||
|
value: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
function getTokens(line) {
|
function getTokens(line) {
|
||||||
return cm.getLineTokens(line).map((token) => ({
|
return cm.getLineTokens(line).map((token) => ({
|
||||||
v: token.string,
|
|
||||||
type: token.type,
|
type: token.type,
|
||||||
|
v: token.string,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +27,7 @@ describe('Code Mirror Mode', () => {
|
||||||
cm.getDoc().setValue('# foo');
|
cm.getDoc().setValue('# foo');
|
||||||
|
|
||||||
expect(getTokens(0)).toEqual([
|
expect(getTokens(0)).toEqual([
|
||||||
{v: '# foo', type: 'comment'},
|
{type: 'comment', v: '# foo'},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -37,8 +35,8 @@ describe('Code Mirror Mode', () => {
|
||||||
cm.getDoc().setValue('terminators cross');
|
cm.getDoc().setValue('terminators cross');
|
||||||
|
|
||||||
expect(getTokens(0)).toEqual([
|
expect(getTokens(0)).toEqual([
|
||||||
{v: 'terminators', type: 'keyword'},
|
{type: 'keyword', v: 'terminators'},
|
||||||
{v: ' cross', type: 'keyword'},
|
{type: 'keyword', v: ' cross'},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -46,9 +44,9 @@ describe('Code Mirror Mode', () => {
|
||||||
cm.getDoc().setValue('terminators cross # foo');
|
cm.getDoc().setValue('terminators cross # foo');
|
||||||
|
|
||||||
expect(getTokens(0)).toEqual([
|
expect(getTokens(0)).toEqual([
|
||||||
{v: 'terminators', type: 'keyword'},
|
{type: 'keyword', v: 'terminators'},
|
||||||
{v: ' cross', type: 'keyword'},
|
{type: 'keyword', v: ' cross'},
|
||||||
{v: ' # foo', type: 'comment'},
|
{type: 'comment', v: ' # foo'},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -68,10 +66,10 @@ describe('Code Mirror Mode', () => {
|
||||||
cm.getDoc().setValue('title my free text');
|
cm.getDoc().setValue('title my free text');
|
||||||
|
|
||||||
expect(getTokens(0)).toEqual([
|
expect(getTokens(0)).toEqual([
|
||||||
{v: 'title', type: 'keyword'},
|
{type: 'keyword', v: 'title'},
|
||||||
{v: ' my', type: 'string'},
|
{type: 'string', v: ' my'},
|
||||||
{v: ' free', type: 'string'},
|
{type: 'string', v: ' free'},
|
||||||
{v: ' text', type: 'string'},
|
{type: 'string', v: ' text'},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -79,8 +77,8 @@ describe('Code Mirror Mode', () => {
|
||||||
cm.getDoc().setValue('title "my free text"');
|
cm.getDoc().setValue('title "my free text"');
|
||||||
|
|
||||||
expect(getTokens(0)).toEqual([
|
expect(getTokens(0)).toEqual([
|
||||||
{v: 'title', type: 'keyword'},
|
{type: 'keyword', v: 'title'},
|
||||||
{v: ' "my free text"', type: 'string'},
|
{type: 'string', v: ' "my free text"'},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -88,9 +86,9 @@ describe('Code Mirror Mode', () => {
|
||||||
cm.getDoc().setValue('A -> B');
|
cm.getDoc().setValue('A -> B');
|
||||||
|
|
||||||
expect(getTokens(0)).toEqual([
|
expect(getTokens(0)).toEqual([
|
||||||
{v: 'A', type: 'variable'},
|
{type: 'variable', v: 'A'},
|
||||||
{v: ' ->', type: 'keyword'},
|
{type: 'keyword', v: ' ->'},
|
||||||
{v: ' B', type: 'variable'},
|
{type: 'variable', v: ' B'},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -98,10 +96,10 @@ describe('Code Mirror Mode', () => {
|
||||||
cm.getDoc().setValue('A "->" -> B');
|
cm.getDoc().setValue('A "->" -> B');
|
||||||
|
|
||||||
expect(getTokens(0)).toEqual([
|
expect(getTokens(0)).toEqual([
|
||||||
{v: 'A', type: 'variable'},
|
{type: 'variable', v: 'A'},
|
||||||
{v: ' "->"', type: 'variable'},
|
{type: 'variable', v: ' "->"'},
|
||||||
{v: ' ->', type: 'keyword'},
|
{type: 'keyword', v: ' ->'},
|
||||||
{v: ' B', type: 'variable'},
|
{type: 'variable', v: ' B'},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -109,14 +107,14 @@ describe('Code Mirror Mode', () => {
|
||||||
cm.getDoc().setValue('define A as B, C as D');
|
cm.getDoc().setValue('define A as B, C as D');
|
||||||
|
|
||||||
expect(getTokens(0)).toEqual([
|
expect(getTokens(0)).toEqual([
|
||||||
{v: 'define', type: 'keyword'},
|
{type: 'keyword', v: 'define'},
|
||||||
{v: ' A', type: 'variable'},
|
{type: 'variable', v: ' A'},
|
||||||
{v: ' as', type: 'keyword'},
|
{type: 'keyword', v: ' as'},
|
||||||
{v: ' B', type: 'variable'},
|
{type: 'variable', v: ' B'},
|
||||||
{v: ',', type: 'operator'},
|
{type: 'operator', v: ','},
|
||||||
{v: ' C', type: 'variable'},
|
{type: 'variable', v: ' C'},
|
||||||
{v: ' as', type: 'keyword'},
|
{type: 'keyword', v: ' as'},
|
||||||
{v: ' D', type: 'variable'},
|
{type: 'variable', v: ' D'},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -124,11 +122,11 @@ describe('Code Mirror Mode', () => {
|
||||||
cm.getDoc().setValue('Foo Bar -> Zig Zag');
|
cm.getDoc().setValue('Foo Bar -> Zig Zag');
|
||||||
|
|
||||||
expect(getTokens(0)).toEqual([
|
expect(getTokens(0)).toEqual([
|
||||||
{v: 'Foo', type: 'variable'},
|
{type: 'variable', v: 'Foo'},
|
||||||
{v: ' Bar', type: 'variable'},
|
{type: 'variable', v: ' Bar'},
|
||||||
{v: ' ->', type: 'keyword'},
|
{type: 'keyword', v: ' ->'},
|
||||||
{v: ' Zig', type: 'variable'},
|
{type: 'variable', v: ' Zig'},
|
||||||
{v: ' Zag', type: 'variable'},
|
{type: 'variable', v: ' Zag'},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -136,9 +134,9 @@ describe('Code Mirror Mode', () => {
|
||||||
cm.getDoc().setValue('abc->xyz');
|
cm.getDoc().setValue('abc->xyz');
|
||||||
|
|
||||||
expect(getTokens(0)).toEqual([
|
expect(getTokens(0)).toEqual([
|
||||||
{v: 'abc', type: 'variable'},
|
{type: 'variable', v: 'abc'},
|
||||||
{v: '->', type: 'keyword'},
|
{type: 'keyword', v: '->'},
|
||||||
{v: 'xyz', type: 'variable'},
|
{type: 'variable', v: 'xyz'},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -146,9 +144,9 @@ describe('Code Mirror Mode', () => {
|
||||||
cm.getDoc().setValue('abc-xxyz');
|
cm.getDoc().setValue('abc-xxyz');
|
||||||
|
|
||||||
expect(getTokens(0)).toEqual([
|
expect(getTokens(0)).toEqual([
|
||||||
{v: 'abc', type: 'variable'},
|
{type: 'variable', v: 'abc'},
|
||||||
{v: '-x', type: 'keyword'},
|
{type: 'keyword', v: '-x'},
|
||||||
{v: 'xyz', type: 'variable'},
|
{type: 'variable', v: 'xyz'},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -156,10 +154,10 @@ describe('Code Mirror Mode', () => {
|
||||||
cm.getDoc().setValue('Foo -> *Bar');
|
cm.getDoc().setValue('Foo -> *Bar');
|
||||||
|
|
||||||
expect(getTokens(0)).toEqual([
|
expect(getTokens(0)).toEqual([
|
||||||
{v: 'Foo', type: 'variable'},
|
{type: 'variable', v: 'Foo'},
|
||||||
{v: ' ->', type: 'keyword'},
|
{type: 'keyword', v: ' ->'},
|
||||||
{v: ' *', type: 'operator'},
|
{type: 'operator', v: ' *'},
|
||||||
{v: 'Bar', type: 'variable'},
|
{type: 'variable', v: 'Bar'},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -167,10 +165,10 @@ describe('Code Mirror Mode', () => {
|
||||||
cm.getDoc().setValue('*Foo -> Bar');
|
cm.getDoc().setValue('*Foo -> Bar');
|
||||||
|
|
||||||
expect(getTokens(0)).toEqual([
|
expect(getTokens(0)).toEqual([
|
||||||
{v: '*', type: 'operator'},
|
{type: 'operator', v: '*'},
|
||||||
{v: 'Foo', type: 'variable'},
|
{type: 'variable', v: 'Foo'},
|
||||||
{v: ' ->', type: 'keyword'},
|
{type: 'keyword', v: ' ->'},
|
||||||
{v: ' Bar', type: 'variable'},
|
{type: 'variable', v: ' Bar'},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -198,11 +196,11 @@ describe('Code Mirror Mode', () => {
|
||||||
cm.getDoc().setValue('Foo -> +*Bar');
|
cm.getDoc().setValue('Foo -> +*Bar');
|
||||||
|
|
||||||
expect(getTokens(0)).toEqual([
|
expect(getTokens(0)).toEqual([
|
||||||
{v: 'Foo', type: 'variable'},
|
{type: 'variable', v: 'Foo'},
|
||||||
{v: ' ->', type: 'keyword'},
|
{type: 'keyword', v: ' ->'},
|
||||||
{v: ' +', type: 'operator'},
|
{type: 'operator', v: ' +'},
|
||||||
{v: '*', type: 'operator'},
|
{type: 'operator', v: '*'},
|
||||||
{v: 'Bar', type: 'variable'},
|
{type: 'variable', v: 'Bar'},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -210,11 +208,11 @@ describe('Code Mirror Mode', () => {
|
||||||
cm.getDoc().setValue('Foo -> Bar: hello');
|
cm.getDoc().setValue('Foo -> Bar: hello');
|
||||||
|
|
||||||
expect(getTokens(0)).toEqual([
|
expect(getTokens(0)).toEqual([
|
||||||
{v: 'Foo', type: 'variable'},
|
{type: 'variable', v: 'Foo'},
|
||||||
{v: ' ->', type: 'keyword'},
|
{type: 'keyword', v: ' ->'},
|
||||||
{v: ' Bar', type: 'variable'},
|
{type: 'variable', v: ' Bar'},
|
||||||
{v: ':', type: 'operator'},
|
{type: 'operator', v: ':'},
|
||||||
{v: ' hello', type: 'string'},
|
{type: 'string', v: ' hello'},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -236,19 +234,19 @@ describe('Code Mirror Mode', () => {
|
||||||
cm.getDoc().setValue('A -> ...x\n...x -> B: hello');
|
cm.getDoc().setValue('A -> ...x\n...x -> B: hello');
|
||||||
|
|
||||||
expect(getTokens(0)).toEqual([
|
expect(getTokens(0)).toEqual([
|
||||||
{v: 'A', type: 'variable'},
|
{type: 'variable', v: 'A'},
|
||||||
{v: ' ->', type: 'keyword'},
|
{type: 'keyword', v: ' ->'},
|
||||||
{v: ' ...', type: 'operator'},
|
{type: 'operator', v: ' ...'},
|
||||||
{v: 'x', type: 'variable'},
|
{type: 'variable', v: 'x'},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(getTokens(1)).toEqual([
|
expect(getTokens(1)).toEqual([
|
||||||
{v: '...', type: 'operator'},
|
{type: 'operator', v: '...'},
|
||||||
{v: 'x', type: 'variable'},
|
{type: 'variable', v: 'x'},
|
||||||
{v: ' ->', type: 'keyword'},
|
{type: 'keyword', v: ' ->'},
|
||||||
{v: ' B', type: 'variable'},
|
{type: 'variable', v: ' B'},
|
||||||
{v: ':', type: 'operator'},
|
{type: 'operator', v: ':'},
|
||||||
{v: ' hello', type: 'string'},
|
{type: 'string', v: ' hello'},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -270,39 +268,39 @@ describe('Code Mirror Mode', () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(getTokens(0)).toEqual([
|
expect(getTokens(0)).toEqual([
|
||||||
{v: 'if', type: 'keyword'},
|
{type: 'keyword', v: 'if'},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(getTokens(1)).toEqual([
|
expect(getTokens(1)).toEqual([
|
||||||
{v: 'if', type: 'keyword'},
|
{type: 'keyword', v: 'if'},
|
||||||
{v: ' something', type: 'string'},
|
{type: 'string', v: ' something'},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(getTokens(2)).toEqual([
|
expect(getTokens(2)).toEqual([
|
||||||
{v: 'else', type: 'keyword'},
|
{type: 'keyword', v: 'else'},
|
||||||
{v: ' if', type: 'keyword'},
|
{type: 'keyword', v: ' if'},
|
||||||
{v: ' another', type: 'string'},
|
{type: 'string', v: ' another'},
|
||||||
{v: ' thing', type: 'string'},
|
{type: 'string', v: ' thing'},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(getTokens(3)).toEqual([
|
expect(getTokens(3)).toEqual([
|
||||||
{v: 'else', type: 'keyword'},
|
{type: 'keyword', v: 'else'},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(getTokens(4)).toEqual([
|
expect(getTokens(4)).toEqual([
|
||||||
{v: 'end', type: 'keyword'},
|
{type: 'keyword', v: 'end'},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(getTokens(5)).toEqual([
|
expect(getTokens(5)).toEqual([
|
||||||
{v: 'repeat', type: 'keyword'},
|
{type: 'keyword', v: 'repeat'},
|
||||||
{v: ' a', type: 'string'},
|
{type: 'string', v: ' a'},
|
||||||
{v: ' few', type: 'string'},
|
{type: 'string', v: ' few'},
|
||||||
{v: ' times', type: 'string'},
|
{type: 'string', v: ' times'},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(getTokens(6)).toEqual([
|
expect(getTokens(6)).toEqual([
|
||||||
{v: 'group', type: 'keyword'},
|
{type: 'keyword', v: 'group'},
|
||||||
{v: ' foo', type: 'string'},
|
{type: 'string', v: ' foo'},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -314,25 +312,25 @@ describe('Code Mirror Mode', () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(getTokens(0)).toEqual([
|
expect(getTokens(0)).toEqual([
|
||||||
{v: 'if', type: 'keyword'},
|
{type: 'keyword', v: 'if'},
|
||||||
{v: ':', type: 'operator'},
|
{type: 'operator', v: ':'},
|
||||||
{v: ' something', type: 'string'},
|
{type: 'string', v: ' something'},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(getTokens(1)).toEqual([
|
expect(getTokens(1)).toEqual([
|
||||||
{v: 'else', type: 'keyword'},
|
{type: 'keyword', v: 'else'},
|
||||||
{v: ' if', type: 'keyword'},
|
{type: 'keyword', v: ' if'},
|
||||||
{v: ':', type: 'operator'},
|
{type: 'operator', v: ':'},
|
||||||
{v: ' another', type: 'string'},
|
{type: 'string', v: ' another'},
|
||||||
{v: ' thing', type: 'string'},
|
{type: 'string', v: ' thing'},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(getTokens(2)).toEqual([
|
expect(getTokens(2)).toEqual([
|
||||||
{v: 'repeat', type: 'keyword'},
|
{type: 'keyword', v: 'repeat'},
|
||||||
{v: ':', type: 'operator'},
|
{type: 'operator', v: ':'},
|
||||||
{v: ' a', type: 'string'},
|
{type: 'string', v: ' a'},
|
||||||
{v: ' few', type: 'string'},
|
{type: 'string', v: ' few'},
|
||||||
{v: ' times', type: 'string'},
|
{type: 'string', v: ' times'},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -346,53 +344,53 @@ describe('Code Mirror Mode', () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(getTokens(0)).toEqual([
|
expect(getTokens(0)).toEqual([
|
||||||
{v: 'note', type: 'keyword'},
|
{type: 'keyword', v: 'note'},
|
||||||
{v: ' over', type: 'keyword'},
|
{type: 'keyword', v: ' over'},
|
||||||
{v: ' A', type: 'variable'},
|
{type: 'variable', v: ' A'},
|
||||||
{v: ':', type: 'operator'},
|
{type: 'operator', v: ':'},
|
||||||
{v: ' hi', type: 'string'},
|
{type: 'string', v: ' hi'},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(getTokens(1)).toEqual([
|
expect(getTokens(1)).toEqual([
|
||||||
{v: 'note', type: 'keyword'},
|
{type: 'keyword', v: 'note'},
|
||||||
{v: ' over', type: 'keyword'},
|
{type: 'keyword', v: ' over'},
|
||||||
{v: ' A', type: 'variable'},
|
{type: 'variable', v: ' A'},
|
||||||
{v: ',', type: 'operator'},
|
{type: 'operator', v: ','},
|
||||||
{v: ' B', type: 'variable'},
|
{type: 'variable', v: ' B'},
|
||||||
{v: ':', type: 'operator'},
|
{type: 'operator', v: ':'},
|
||||||
{v: ' hi', type: 'string'},
|
{type: 'string', v: ' hi'},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(getTokens(2)).toEqual([
|
expect(getTokens(2)).toEqual([
|
||||||
{v: 'note', type: 'keyword'},
|
{type: 'keyword', v: 'note'},
|
||||||
{v: ' left', type: 'keyword'},
|
{type: 'keyword', v: ' left'},
|
||||||
{v: ' of', type: 'keyword'},
|
{type: 'keyword', v: ' of'},
|
||||||
{v: ' A', type: 'variable'},
|
{type: 'variable', v: ' A'},
|
||||||
{v: ',', type: 'operator'},
|
{type: 'operator', v: ','},
|
||||||
{v: ' B', type: 'variable'},
|
{type: 'variable', v: ' B'},
|
||||||
{v: ':', type: 'operator'},
|
{type: 'operator', v: ':'},
|
||||||
{v: ' hi', type: 'string'},
|
{type: 'string', v: ' hi'},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(getTokens(3)).toEqual([
|
expect(getTokens(3)).toEqual([
|
||||||
{v: 'note', type: 'keyword'},
|
{type: 'keyword', v: 'note'},
|
||||||
{v: ' right', type: 'keyword'},
|
{type: 'keyword', v: ' right'},
|
||||||
{v: ' of', type: 'keyword'},
|
{type: 'keyword', v: ' of'},
|
||||||
{v: ' A', type: 'variable'},
|
{type: 'variable', v: ' A'},
|
||||||
{v: ',', type: 'operator'},
|
{type: 'operator', v: ','},
|
||||||
{v: ' B', type: 'variable'},
|
{type: 'variable', v: ' B'},
|
||||||
{v: ':', type: 'operator'},
|
{type: 'operator', v: ':'},
|
||||||
{v: ' hi', type: 'string'},
|
{type: 'string', v: ' hi'},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(getTokens(4)).toEqual([
|
expect(getTokens(4)).toEqual([
|
||||||
{v: 'note', type: 'keyword'},
|
{type: 'keyword', v: 'note'},
|
||||||
{v: ' between', type: 'keyword'},
|
{type: 'keyword', v: ' between'},
|
||||||
{v: ' A', type: 'variable'},
|
{type: 'variable', v: ' A'},
|
||||||
{v: ',', type: 'operator'},
|
{type: 'operator', v: ','},
|
||||||
{v: ' B', type: 'variable'},
|
{type: 'variable', v: ' B'},
|
||||||
{v: ':', type: 'operator'},
|
{type: 'operator', v: ':'},
|
||||||
{v: ' hi', type: 'string'},
|
{type: 'string', v: ' hi'},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -406,11 +404,11 @@ describe('Code Mirror Mode', () => {
|
||||||
cm.getDoc().setValue('state over A: hi');
|
cm.getDoc().setValue('state over A: hi');
|
||||||
|
|
||||||
expect(getTokens(0)).toEqual([
|
expect(getTokens(0)).toEqual([
|
||||||
{v: 'state', type: 'keyword'},
|
{type: 'keyword', v: 'state'},
|
||||||
{v: ' over', type: 'keyword'},
|
{type: 'keyword', v: ' over'},
|
||||||
{v: ' A', type: 'variable'},
|
{type: 'variable', v: ' A'},
|
||||||
{v: ':', type: 'operator'},
|
{type: 'operator', v: ':'},
|
||||||
{v: ' hi', type: 'string'},
|
{type: 'string', v: ' hi'},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -424,13 +422,13 @@ describe('Code Mirror Mode', () => {
|
||||||
cm.getDoc().setValue('divider tear with height 60: stuff');
|
cm.getDoc().setValue('divider tear with height 60: stuff');
|
||||||
|
|
||||||
expect(getTokens(0)).toEqual([
|
expect(getTokens(0)).toEqual([
|
||||||
{v: 'divider', type: 'keyword'},
|
{type: 'keyword', v: 'divider'},
|
||||||
{v: ' tear', type: 'keyword'},
|
{type: 'keyword', v: ' tear'},
|
||||||
{v: ' with', type: 'keyword'},
|
{type: 'keyword', v: ' with'},
|
||||||
{v: ' height', type: 'keyword'},
|
{type: 'keyword', v: ' height'},
|
||||||
{v: ' 60', type: 'number'},
|
{type: 'number', v: ' 60'},
|
||||||
{v: ':', type: 'operator'},
|
{type: 'operator', v: ':'},
|
||||||
{v: ' stuff', type: 'string'},
|
{type: 'string', v: ' stuff'},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -438,11 +436,11 @@ describe('Code Mirror Mode', () => {
|
||||||
cm.getDoc().setValue('A is a red database');
|
cm.getDoc().setValue('A is a red database');
|
||||||
|
|
||||||
expect(getTokens(0)).toEqual([
|
expect(getTokens(0)).toEqual([
|
||||||
{v: 'A', type: 'variable'},
|
{type: 'variable', v: 'A'},
|
||||||
{v: ' is', type: 'keyword'},
|
{type: 'keyword', v: ' is'},
|
||||||
{v: ' a', type: 'keyword'},
|
{type: 'keyword', v: ' a'},
|
||||||
{v: ' red', type: 'keyword'},
|
{type: 'keyword', v: ' red'},
|
||||||
{v: ' database', type: 'keyword'},
|
{type: 'keyword', v: ' database'},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -467,7 +465,7 @@ describe('Code Mirror Mode', () => {
|
||||||
|
|
||||||
it('suggests commands when used at the start of a line', () => {
|
it('suggests commands when used at the start of a line', () => {
|
||||||
cm.getDoc().setValue('');
|
cm.getDoc().setValue('');
|
||||||
const hints = getHintTexts({line: 0, ch: 0});
|
const hints = getHintTexts({ch: 0, line: 0});
|
||||||
|
|
||||||
expect(hints).toContain('theme ');
|
expect(hints).toContain('theme ');
|
||||||
expect(hints).toContain('title ');
|
expect(hints).toContain('title ');
|
||||||
|
@ -491,7 +489,7 @@ describe('Code Mirror Mode', () => {
|
||||||
|
|
||||||
it('ignores indentation', () => {
|
it('ignores indentation', () => {
|
||||||
cm.getDoc().setValue(' ');
|
cm.getDoc().setValue(' ');
|
||||||
const hints = getHintTexts({line: 0, ch: 2});
|
const hints = getHintTexts({ch: 2, line: 0});
|
||||||
|
|
||||||
expect(hints).toContain('theme ');
|
expect(hints).toContain('theme ');
|
||||||
expect(hints).toContain('title ');
|
expect(hints).toContain('title ');
|
||||||
|
@ -499,7 +497,7 @@ describe('Code Mirror Mode', () => {
|
||||||
|
|
||||||
it('suggests known header types', () => {
|
it('suggests known header types', () => {
|
||||||
cm.getDoc().setValue('headers ');
|
cm.getDoc().setValue('headers ');
|
||||||
const hints = getHintTexts({line: 0, ch: 8});
|
const hints = getHintTexts({ch: 8, line: 0});
|
||||||
|
|
||||||
expect(hints).toEqual([
|
expect(hints).toEqual([
|
||||||
'none\n',
|
'none\n',
|
||||||
|
@ -512,7 +510,7 @@ describe('Code Mirror Mode', () => {
|
||||||
|
|
||||||
it('suggests known terminator types', () => {
|
it('suggests known terminator types', () => {
|
||||||
cm.getDoc().setValue('terminators ');
|
cm.getDoc().setValue('terminators ');
|
||||||
const hints = getHintTexts({line: 0, ch: 12});
|
const hints = getHintTexts({ch: 12, line: 0});
|
||||||
|
|
||||||
expect(hints).toEqual([
|
expect(hints).toEqual([
|
||||||
'none\n',
|
'none\n',
|
||||||
|
@ -525,7 +523,7 @@ describe('Code Mirror Mode', () => {
|
||||||
|
|
||||||
it('suggests divider types', () => {
|
it('suggests divider types', () => {
|
||||||
cm.getDoc().setValue('divider ');
|
cm.getDoc().setValue('divider ');
|
||||||
const hints = getHintTexts({line: 0, ch: 8});
|
const hints = getHintTexts({ch: 8, line: 0});
|
||||||
|
|
||||||
expect(hints).toEqual([
|
expect(hints).toEqual([
|
||||||
'line ',
|
'line ',
|
||||||
|
@ -540,7 +538,7 @@ describe('Code Mirror Mode', () => {
|
||||||
|
|
||||||
it('suggests divider sizes', () => {
|
it('suggests divider sizes', () => {
|
||||||
cm.getDoc().setValue('divider space with height ');
|
cm.getDoc().setValue('divider space with height ');
|
||||||
const hints = getHintTexts({line: 0, ch: 26});
|
const hints = getHintTexts({ch: 26, line: 0});
|
||||||
|
|
||||||
expect(hints).toEqual([
|
expect(hints).toEqual([
|
||||||
'6 ',
|
'6 ',
|
||||||
|
@ -550,7 +548,7 @@ describe('Code Mirror Mode', () => {
|
||||||
|
|
||||||
it('suggests useful autolabel values', () => {
|
it('suggests useful autolabel values', () => {
|
||||||
cm.getDoc().setValue('autolabel ');
|
cm.getDoc().setValue('autolabel ');
|
||||||
const hints = getHintTexts({line: 0, ch: 10});
|
const hints = getHintTexts({ch: 10, line: 0});
|
||||||
|
|
||||||
expect(hints).toContain('off\n');
|
expect(hints).toContain('off\n');
|
||||||
expect(hints).toContain('"<label>"\n');
|
expect(hints).toContain('"<label>"\n');
|
||||||
|
@ -559,7 +557,7 @@ describe('Code Mirror Mode', () => {
|
||||||
|
|
||||||
it('suggests note positioning', () => {
|
it('suggests note positioning', () => {
|
||||||
cm.getDoc().setValue('note ');
|
cm.getDoc().setValue('note ');
|
||||||
const hints = getHintTexts({line: 0, ch: 5});
|
const hints = getHintTexts({ch: 5, line: 0});
|
||||||
|
|
||||||
expect(hints).toEqual([
|
expect(hints).toEqual([
|
||||||
'over ',
|
'over ',
|
||||||
|
@ -573,14 +571,14 @@ describe('Code Mirror Mode', () => {
|
||||||
|
|
||||||
it('filters suggestions', () => {
|
it('filters suggestions', () => {
|
||||||
cm.getDoc().setValue('term');
|
cm.getDoc().setValue('term');
|
||||||
const hints = getHintTexts({line: 0, ch: 4});
|
const hints = getHintTexts({ch: 4, line: 0});
|
||||||
|
|
||||||
expect(hints).toEqual(['terminators ']);
|
expect(hints).toEqual(['terminators ']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('suggests known agent names and flags', () => {
|
it('suggests known agent names and flags', () => {
|
||||||
cm.getDoc().setValue('Foo -> ');
|
cm.getDoc().setValue('Foo -> ');
|
||||||
const hints = getHintTexts({line: 0, ch: 7});
|
const hints = getHintTexts({ch: 7, line: 0});
|
||||||
|
|
||||||
expect(hints).toEqual([
|
expect(hints).toEqual([
|
||||||
'+ ',
|
'+ ',
|
||||||
|
@ -594,7 +592,7 @@ describe('Code Mirror Mode', () => {
|
||||||
|
|
||||||
it('only suggests valid flag combinations', () => {
|
it('only suggests valid flag combinations', () => {
|
||||||
cm.getDoc().setValue('Foo -> + ');
|
cm.getDoc().setValue('Foo -> + ');
|
||||||
const hints = getHintTexts({line: 0, ch: 10});
|
const hints = getHintTexts({ch: 10, line: 0});
|
||||||
|
|
||||||
expect(hints).toContain('* ');
|
expect(hints).toContain('* ');
|
||||||
expect(hints).not.toContain('! ');
|
expect(hints).not.toContain('! ');
|
||||||
|
@ -605,7 +603,7 @@ describe('Code Mirror Mode', () => {
|
||||||
|
|
||||||
it('suggests known agent names at the start of lines', () => {
|
it('suggests known agent names at the start of lines', () => {
|
||||||
cm.getDoc().setValue('Foo -> Bar\n');
|
cm.getDoc().setValue('Foo -> Bar\n');
|
||||||
const hints = getHintTexts({line: 1, ch: 0});
|
const hints = getHintTexts({ch: 0, line: 1});
|
||||||
|
|
||||||
expect(hints).toContain('Foo ');
|
expect(hints).toContain('Foo ');
|
||||||
expect(hints).toContain('Bar ');
|
expect(hints).toContain('Bar ');
|
||||||
|
@ -613,21 +611,21 @@ describe('Code Mirror Mode', () => {
|
||||||
|
|
||||||
it('suggests known labels', () => {
|
it('suggests known labels', () => {
|
||||||
cm.getDoc().setValue('Abc:\nsimultaneously with ');
|
cm.getDoc().setValue('Abc:\nsimultaneously with ');
|
||||||
const hints = getHintTexts({line: 1, ch: 20});
|
const hints = getHintTexts({ch: 20, line: 1});
|
||||||
|
|
||||||
expect(hints).toEqual(['Abc ']);
|
expect(hints).toEqual(['Abc ']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('suggests known themes', () => {
|
it('suggests known themes', () => {
|
||||||
cm.getDoc().setValue('theme ');
|
cm.getDoc().setValue('theme ');
|
||||||
const hints = getHintTexts({line: 0, ch: 6});
|
const hints = getHintTexts({ch: 6, line: 0});
|
||||||
|
|
||||||
expect(hints).toEqual(['Theme\n', 'Other Theme\n']);
|
expect(hints).toEqual(['Theme\n', 'Other Theme\n']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('suggests filtered multi-word themes', () => {
|
it('suggests filtered multi-word themes', () => {
|
||||||
cm.getDoc().setValue('theme Other ');
|
cm.getDoc().setValue('theme Other ');
|
||||||
const hints = getHintTexts({line: 0, ch: 12});
|
const hints = getHintTexts({ch: 12, line: 0});
|
||||||
|
|
||||||
expect(hints).toContain('Other Theme\n');
|
expect(hints).toContain('Other Theme\n');
|
||||||
expect(hints).not.toContain('Theme\n');
|
expect(hints).not.toContain('Theme\n');
|
||||||
|
@ -635,7 +633,7 @@ describe('Code Mirror Mode', () => {
|
||||||
|
|
||||||
it('suggests multi-word agents', () => {
|
it('suggests multi-word agents', () => {
|
||||||
cm.getDoc().setValue('Zig Zag -> Meh\nFoo Bar -> ');
|
cm.getDoc().setValue('Zig Zag -> Meh\nFoo Bar -> ');
|
||||||
const hints = getHintTexts({line: 1, ch: 11});
|
const hints = getHintTexts({ch: 11, line: 1});
|
||||||
|
|
||||||
expect(hints).toContain('Zig Zag ');
|
expect(hints).toContain('Zig Zag ');
|
||||||
expect(hints).toContain('Meh ');
|
expect(hints).toContain('Meh ');
|
||||||
|
@ -644,7 +642,7 @@ describe('Code Mirror Mode', () => {
|
||||||
|
|
||||||
it('suggests quoted agent names if a quote is typed', () => {
|
it('suggests quoted agent names if a quote is typed', () => {
|
||||||
cm.getDoc().setValue('Zig Zag -> Meh\nFoo Bar -> "');
|
cm.getDoc().setValue('Zig Zag -> Meh\nFoo Bar -> "');
|
||||||
const hints = getHintTexts({line: 1, ch: 12});
|
const hints = getHintTexts({ch: 12, line: 1});
|
||||||
|
|
||||||
expect(hints).toEqual([
|
expect(hints).toEqual([
|
||||||
'"Zig Zag" ',
|
'"Zig Zag" ',
|
||||||
|
@ -655,7 +653,7 @@ describe('Code Mirror Mode', () => {
|
||||||
|
|
||||||
it('suggests filtered multi-word agents', () => {
|
it('suggests filtered multi-word agents', () => {
|
||||||
cm.getDoc().setValue('Zig Zag -> Meh\nFoo Bar -> Foo ');
|
cm.getDoc().setValue('Zig Zag -> Meh\nFoo Bar -> Foo ');
|
||||||
const hints = getHintTexts({line: 1, ch: 15});
|
const hints = getHintTexts({ch: 15, line: 1});
|
||||||
|
|
||||||
expect(hints).toContain('Foo Bar ');
|
expect(hints).toContain('Foo Bar ');
|
||||||
expect(hints).not.toContain('Zig Zag ');
|
expect(hints).not.toContain('Zig Zag ');
|
||||||
|
@ -664,33 +662,33 @@ describe('Code Mirror Mode', () => {
|
||||||
|
|
||||||
it('suggests quoted names where required', () => {
|
it('suggests quoted names where required', () => {
|
||||||
cm.getDoc().setValue('"Zig -> Zag" -> ');
|
cm.getDoc().setValue('"Zig -> Zag" -> ');
|
||||||
const hints = getHintTexts({line: 0, ch: 16});
|
const hints = getHintTexts({ch: 16, line: 0});
|
||||||
|
|
||||||
expect(hints).toContain('"Zig -> Zag" ');
|
expect(hints).toContain('"Zig -> Zag" ');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('filters quoted names ignoring quotes', () => {
|
it('filters quoted names ignoring quotes', () => {
|
||||||
cm.getDoc().setValue('"Zig -> Zag" -> Zig');
|
cm.getDoc().setValue('"Zig -> Zag" -> Zig');
|
||||||
let hints = getHintTexts({line: 0, ch: 19});
|
let hints = getHintTexts({ch: 19, line: 0});
|
||||||
|
|
||||||
expect(hints).toContain('"Zig -> Zag" ');
|
expect(hints).toContain('"Zig -> Zag" ');
|
||||||
|
|
||||||
cm.getDoc().setValue('"Zig -> Zag" -> Zag');
|
cm.getDoc().setValue('"Zig -> Zag" -> Zag');
|
||||||
hints = getHintTexts({line: 0, ch: 19});
|
hints = getHintTexts({ch: 19, line: 0});
|
||||||
|
|
||||||
expect(hints).not.toContain('"Zig -> Zag" ');
|
expect(hints).not.toContain('"Zig -> Zag" ');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('suggests known delayed agents', () => {
|
it('suggests known delayed agents', () => {
|
||||||
cm.getDoc().setValue('A -> ...woo\n... ');
|
cm.getDoc().setValue('A -> ...woo\n... ');
|
||||||
const hints = getHintTexts({line: 1, ch: 4});
|
const hints = getHintTexts({ch: 4, line: 1});
|
||||||
|
|
||||||
expect(hints).toEqual(['woo ']);
|
expect(hints).toEqual(['woo ']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('suggests agent properties', () => {
|
it('suggests agent properties', () => {
|
||||||
cm.getDoc().setValue('A is a ');
|
cm.getDoc().setValue('A is a ');
|
||||||
const hints = getHintTexts({line: 0, ch: 7});
|
const hints = getHintTexts({ch: 7, line: 0});
|
||||||
|
|
||||||
expect(hints).toContain('database ');
|
expect(hints).toContain('database ');
|
||||||
expect(hints).toContain('red ');
|
expect(hints).toContain('red ');
|
||||||
|
@ -699,7 +697,7 @@ describe('Code Mirror Mode', () => {
|
||||||
|
|
||||||
it('suggests indefinite articles for agent properties', () => {
|
it('suggests indefinite articles for agent properties', () => {
|
||||||
cm.getDoc().setValue('A is ');
|
cm.getDoc().setValue('A is ');
|
||||||
const hints = getHintTexts({line: 0, ch: 5});
|
const hints = getHintTexts({ch: 5, line: 0});
|
||||||
|
|
||||||
expect(hints).toContain('database ');
|
expect(hints).toContain('database ');
|
||||||
expect(hints).toContain('a ');
|
expect(hints).toContain('a ');
|
||||||
|
@ -709,7 +707,7 @@ describe('Code Mirror Mode', () => {
|
||||||
|
|
||||||
it('suggests more agent properties after the first', () => {
|
it('suggests more agent properties after the first', () => {
|
||||||
cm.getDoc().setValue('A is a red ');
|
cm.getDoc().setValue('A is a red ');
|
||||||
const hints = getHintTexts({line: 0, ch: 11});
|
const hints = getHintTexts({ch: 11, line: 0});
|
||||||
|
|
||||||
expect(hints).toContain('database ');
|
expect(hints).toContain('database ');
|
||||||
expect(hints).toContain('\n');
|
expect(hints).toContain('\n');
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
/* eslint-disable complexity */ // Temporary ignore while switching linter
|
|
||||||
|
|
||||||
import {last, mergeSets} from '../../core/ArrayUtilities.mjs';
|
import {last, mergeSets} from '../../core/ArrayUtilities.mjs';
|
||||||
|
|
||||||
const TRIMMER = /^([ \t]*)(.*)$/;
|
const TRIMMER = /^([ \t]*)(.*)$/;
|
||||||
|
@ -12,7 +10,7 @@ const ONGOING_QUOTE = /^"(\\.|[^"])*$/;
|
||||||
const REQUIRED_QUOTED = /[\r\n:,"<>\-~]/;
|
const REQUIRED_QUOTED = /[\r\n:,"<>\-~]/;
|
||||||
const QUOTE_ESCAPE = /["\\]/g;
|
const QUOTE_ESCAPE = /["\\]/g;
|
||||||
|
|
||||||
function suggestionsEqual(a, b) {
|
function completionsEqual(a, b) {
|
||||||
return (
|
return (
|
||||||
(a.v === b.v) &&
|
(a.v === b.v) &&
|
||||||
(a.prefix === b.prefix) &&
|
(a.prefix === b.prefix) &&
|
||||||
|
@ -89,12 +87,12 @@ function getGlobals({global, prefix = '', suffix = ''}, globals) {
|
||||||
return identified.map((item) => ({prefix, q: true, suffix, v: item}));
|
return identified.map((item) => ({prefix, q: true, suffix, v: item}));
|
||||||
}
|
}
|
||||||
|
|
||||||
function populateGlobals(suggestions, globals = {}) {
|
function populateGlobals(completions, globals = {}) {
|
||||||
for(let i = 0; i < suggestions.length;) {
|
for(let i = 0; i < completions.length;) {
|
||||||
if(suggestions[i].global) {
|
if(completions[i].global) {
|
||||||
const identified = getGlobals(suggestions[i], globals);
|
const identified = getGlobals(completions[i], globals);
|
||||||
mergeSets(suggestions, identified, suggestionsEqual);
|
mergeSets(completions, identified, completionsEqual);
|
||||||
suggestions.splice(i, 1);
|
completions.splice(i, 1);
|
||||||
} else {
|
} else {
|
||||||
++ i;
|
++ i;
|
||||||
}
|
}
|
||||||
|
@ -176,6 +174,18 @@ function partialMatch(v, p) {
|
||||||
return p.valid && v.startsWith(p.partial);
|
return p.valid && v.startsWith(p.partial);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getCompletions(cur, token, globals) {
|
||||||
|
let completions = null;
|
||||||
|
if(cur.ch > 0 && token.state.line.length > 0) {
|
||||||
|
completions = token.state.completions.slice();
|
||||||
|
} else {
|
||||||
|
completions = token.state.beginCompletions
|
||||||
|
.concat(token.state.knownAgent);
|
||||||
|
}
|
||||||
|
populateGlobals(completions, globals);
|
||||||
|
return completions;
|
||||||
|
}
|
||||||
|
|
||||||
export function getHints(cm, options) {
|
export function getHints(cm, options) {
|
||||||
const cur = cm.getCursor();
|
const cur = cm.getCursor();
|
||||||
const tokens = getTokensUpTo(cm, cur);
|
const tokens = getTokensUpTo(cm, cur);
|
||||||
|
@ -183,16 +193,7 @@ export function getHints(cm, options) {
|
||||||
const pVar = getVariablePartial(tokens, cur);
|
const pVar = getVariablePartial(tokens, cur);
|
||||||
const pKey = getKeywordPartial(token, cur);
|
const pKey = getKeywordPartial(token, cur);
|
||||||
|
|
||||||
const continuation = (cur.ch > 0 && token.state.line.length > 0);
|
const completions = getCompletions(cur, token, cm.options.globals);
|
||||||
let comp = (continuation ?
|
|
||||||
token.state.completions :
|
|
||||||
token.state.beginCompletions
|
|
||||||
);
|
|
||||||
if(!continuation) {
|
|
||||||
comp = comp.concat(token.state.knownAgent);
|
|
||||||
}
|
|
||||||
|
|
||||||
populateGlobals(comp, cm.options.globals);
|
|
||||||
|
|
||||||
const ranges = {
|
const ranges = {
|
||||||
fromKey: makeRangeFrom(cm, cur.line, pKey.from),
|
fromKey: makeRangeFrom(cm, cur.line, pKey.from),
|
||||||
|
@ -200,7 +201,7 @@ export function getHints(cm, options) {
|
||||||
to: makeRangeTo(cm, cur.line, token.end),
|
to: makeRangeTo(cm, cur.line, token.end),
|
||||||
};
|
};
|
||||||
let selfValid = null;
|
let selfValid = null;
|
||||||
const list = (comp
|
const list = (completions
|
||||||
.filter((o) => (
|
.filter((o) => (
|
||||||
(o.q || !pVar.quote) &&
|
(o.q || !pVar.quote) &&
|
||||||
partialMatch(o.v, o.q ? pVar : pKey)
|
partialMatch(o.v, o.q ? pVar : pKey)
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/* eslint-disable max-lines */
|
/* eslint-disable max-lines */
|
||||||
/* eslint-disable sort-keys */ // Maybe later
|
/* eslint-disable sort-keys */ // Maybe later
|
||||||
/* eslint-disable complexity */ // Temporary ignore while switching linter
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
flatMap,
|
flatMap,
|
||||||
|
@ -41,15 +40,6 @@ const PAgent = {
|
||||||
|
|
||||||
// Agent from Generator: {id, formattedLabel, anchorRight}
|
// Agent from Generator: {id, formattedLabel, anchorRight}
|
||||||
const GAgent = {
|
const GAgent = {
|
||||||
equals: (a, b) => (a.id === b.id),
|
|
||||||
make: (id, {anchorRight = false, isVirtualSource = false} = {}) => ({
|
|
||||||
anchorRight,
|
|
||||||
id,
|
|
||||||
isVirtualSource,
|
|
||||||
options: [],
|
|
||||||
}),
|
|
||||||
indexOf: (list, gAgent) => indexOf(list, gAgent, GAgent.equals),
|
|
||||||
hasIntersection: (a, b) => hasIntersection(a, b, GAgent.equals),
|
|
||||||
addNearby: (target, reference, item, offset) => {
|
addNearby: (target, reference, item, offset) => {
|
||||||
const p = indexOf(target, reference, GAgent.equals);
|
const p = indexOf(target, reference, GAgent.equals);
|
||||||
if(p === -1) {
|
if(p === -1) {
|
||||||
|
@ -58,11 +48,28 @@ const GAgent = {
|
||||||
target.splice(p + offset, 0, item);
|
target.splice(p + offset, 0, item);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
equals: (a, b) => (a.id === b.id),
|
||||||
|
hasIntersection: (a, b) => hasIntersection(a, b, GAgent.equals),
|
||||||
|
indexOf: (list, gAgent) => indexOf(list, gAgent, GAgent.equals),
|
||||||
|
make: (id, {anchorRight = false, isVirtualSource = false} = {}) => ({
|
||||||
|
anchorRight,
|
||||||
|
id,
|
||||||
|
isVirtualSource,
|
||||||
|
options: [],
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function isExpiredGroupAlias(state) {
|
||||||
|
return state.blocked && state.group === null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isReservedAgentName(name) {
|
||||||
|
return name.startsWith('__');
|
||||||
|
}
|
||||||
|
|
||||||
const NOTE_DEFAULT_G_AGENTS = {
|
const NOTE_DEFAULT_G_AGENTS = {
|
||||||
'note over': [GAgent.make('['), GAgent.make(']')],
|
|
||||||
'note left': [GAgent.make('[')],
|
'note left': [GAgent.make('[')],
|
||||||
|
'note over': [GAgent.make('['), GAgent.make(']')],
|
||||||
'note right': [GAgent.make(']')],
|
'note right': [GAgent.make(']')],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -247,25 +254,25 @@ export default class Generator {
|
||||||
this.currentNest = null;
|
this.currentNest = null;
|
||||||
|
|
||||||
this.stageHandlers = {
|
this.stageHandlers = {
|
||||||
'block begin': this.handleBlockBegin.bind(this),
|
|
||||||
'block split': this.handleBlockSplit.bind(this),
|
|
||||||
'block end': this.handleBlockEnd.bind(this),
|
|
||||||
'group begin': this.handleGroupBegin.bind(this),
|
|
||||||
'mark': this.handleMark.bind(this),
|
|
||||||
'async': this.handleAsync.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 define': this.handleAgentDefine.bind(this),
|
||||||
'agent end': this.handleAgentEnd.bind(this),
|
'agent end': this.handleAgentEnd.bind(this),
|
||||||
'divider': this.handleDivider.bind(this),
|
'agent options': this.handleAgentOptions.bind(this),
|
||||||
'label pattern': this.handleLabelPattern.bind(this),
|
'async': this.handleAsync.bind(this),
|
||||||
|
'block begin': this.handleBlockBegin.bind(this),
|
||||||
|
'block end': this.handleBlockEnd.bind(this),
|
||||||
|
'block split': this.handleBlockSplit.bind(this),
|
||||||
'connect': this.handleConnect.bind(this),
|
'connect': this.handleConnect.bind(this),
|
||||||
'connect-delay-begin': this.handleConnectDelayBegin.bind(this),
|
'connect-delay-begin': this.handleConnectDelayBegin.bind(this),
|
||||||
'connect-delay-end': this.handleConnectDelayEnd.bind(this),
|
'connect-delay-end': this.handleConnectDelayEnd.bind(this),
|
||||||
'note over': this.handleNote.bind(this),
|
'divider': this.handleDivider.bind(this),
|
||||||
'note left': this.handleNote.bind(this),
|
'group begin': this.handleGroupBegin.bind(this),
|
||||||
'note right': this.handleNote.bind(this),
|
'label pattern': this.handleLabelPattern.bind(this),
|
||||||
|
'mark': this.handleMark.bind(this),
|
||||||
'note between': this.handleNote.bind(this),
|
'note between': this.handleNote.bind(this),
|
||||||
|
'note left': this.handleNote.bind(this),
|
||||||
|
'note over': this.handleNote.bind(this),
|
||||||
|
'note right': this.handleNote.bind(this),
|
||||||
};
|
};
|
||||||
this.expandGroupedGAgent = this.expandGroupedGAgent.bind(this);
|
this.expandGroupedGAgent = this.expandGroupedGAgent.bind(this);
|
||||||
this.handleStage = this.handleStage.bind(this);
|
this.handleStage = this.handleStage.bind(this);
|
||||||
|
@ -273,6 +280,14 @@ export default class Generator {
|
||||||
this.endGroup = this.endGroup.bind(this);
|
this.endGroup = this.endGroup.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_aliasInUse(alias) {
|
||||||
|
const old = this.agentAliases.get(alias);
|
||||||
|
if(old && old !== alias) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return this.gAgents.some((gAgent) => (gAgent.id === alias));
|
||||||
|
}
|
||||||
|
|
||||||
toGAgent({name, alias, flags}) {
|
toGAgent({name, alias, flags}) {
|
||||||
if(alias) {
|
if(alias) {
|
||||||
if(this.agentAliases.has(name)) {
|
if(this.agentAliases.has(name)) {
|
||||||
|
@ -280,11 +295,7 @@ export default class Generator {
|
||||||
'Cannot alias ' + name + '; it is already an alias'
|
'Cannot alias ' + name + '; it is already an alias'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const old = this.agentAliases.get(alias);
|
if(this._aliasInUse(alias)) {
|
||||||
if(
|
|
||||||
(old && old !== alias) ||
|
|
||||||
this.gAgents.some((gAgent) => (gAgent.id === alias))
|
|
||||||
) {
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Cannot use ' + alias +
|
'Cannot use ' + alias +
|
||||||
' as an alias; it is already in use'
|
' as an alias; it is already in use'
|
||||||
|
@ -325,8 +336,8 @@ export default class Generator {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.addStage({
|
this.addStage({
|
||||||
type: 'parallel',
|
|
||||||
stages: viableStages,
|
stages: viableStages,
|
||||||
|
type: 'parallel',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,25 +372,27 @@ export default class Generator {
|
||||||
allowCovered = false,
|
allowCovered = false,
|
||||||
allowVirtual = false,
|
allowVirtual = false,
|
||||||
} = {}) {
|
} = {}) {
|
||||||
|
/* eslint-disable complexity */ // The checks are quite simple
|
||||||
gAgents.forEach((gAgent) => {
|
gAgents.forEach((gAgent) => {
|
||||||
|
/* eslint-enable complexity */
|
||||||
const state = this.getGAgentState(gAgent);
|
const state = this.getGAgentState(gAgent);
|
||||||
if(state.blocked && state.group === null) {
|
const name = gAgent.id;
|
||||||
|
|
||||||
|
if(isExpiredGroupAlias(state)) {
|
||||||
// Used to be a group alias; can never be reused
|
// Used to be a group alias; can never be reused
|
||||||
throw new Error('Duplicate agent name: ' + gAgent.id);
|
throw new Error('Duplicate agent name: ' + name);
|
||||||
}
|
}
|
||||||
if(!allowCovered && state.covered) {
|
if(!allowCovered && state.covered) {
|
||||||
throw new Error(
|
throw new Error('Agent ' + name + ' is hidden behind group');
|
||||||
'Agent ' + gAgent.id + ' is hidden behind group'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if(!allowGrouped && state.group !== null) {
|
if(!allowGrouped && state.group !== null) {
|
||||||
throw new Error('Agent ' + gAgent.id + ' is in a group');
|
throw new Error('Agent ' + name + ' is in a group');
|
||||||
}
|
}
|
||||||
if(!allowVirtual && gAgent.isVirtualSource) {
|
if(!allowVirtual && gAgent.isVirtualSource) {
|
||||||
throw new Error('cannot use message source here');
|
throw new Error('Cannot use message source here');
|
||||||
}
|
}
|
||||||
if(gAgent.id.startsWith('__')) {
|
if(isReservedAgentName(name)) {
|
||||||
throw new Error(gAgent.id + ' is a reserved name');
|
throw new Error(name + ' is a reserved name');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -410,9 +423,9 @@ export default class Generator {
|
||||||
this.defineGAgents(filteredGAgents);
|
this.defineGAgents(filteredGAgents);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: (visible ? 'agent begin' : 'agent end'),
|
|
||||||
agentIDs: filteredGAgents.map((gAgent) => gAgent.id),
|
agentIDs: filteredGAgents.map((gAgent) => gAgent.id),
|
||||||
mode,
|
mode,
|
||||||
|
type: (visible ? 'agent begin' : 'agent end'),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -436,16 +449,16 @@ export default class Generator {
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: 'agent highlight',
|
|
||||||
agentIDs: filteredGAgents.map((gAgent) => gAgent.id),
|
agentIDs: filteredGAgents.map((gAgent) => gAgent.id),
|
||||||
highlighted,
|
highlighted,
|
||||||
|
type: 'agent highlight',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
_makeSection(header, stages) {
|
_makeSection(header, stages) {
|
||||||
return {
|
return {
|
||||||
header,
|
|
||||||
delayedConnections: new Map(),
|
delayedConnections: new Map(),
|
||||||
|
header,
|
||||||
stages,
|
stages,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -467,21 +480,21 @@ export default class Generator {
|
||||||
const gAgents = [leftGAgent, rightGAgent];
|
const gAgents = [leftGAgent, rightGAgent];
|
||||||
const stages = [];
|
const stages = [];
|
||||||
this.currentSection = this._makeSection({
|
this.currentSection = this._makeSection({
|
||||||
type: 'block begin',
|
|
||||||
blockType,
|
blockType,
|
||||||
tag: this.textFormatter(tag),
|
|
||||||
label: this.textFormatter(label),
|
|
||||||
canHide: true,
|
canHide: true,
|
||||||
|
label: this.textFormatter(label),
|
||||||
left: leftGAgent.id,
|
left: leftGAgent.id,
|
||||||
right: rightGAgent.id,
|
|
||||||
ln,
|
ln,
|
||||||
|
right: rightGAgent.id,
|
||||||
|
tag: this.textFormatter(tag),
|
||||||
|
type: 'block begin',
|
||||||
}, stages);
|
}, stages);
|
||||||
this.currentNest = {
|
this.currentNest = {
|
||||||
blockType,
|
blockType,
|
||||||
gAgents,
|
gAgents,
|
||||||
|
hasContent: false,
|
||||||
leftGAgent,
|
leftGAgent,
|
||||||
rightGAgent,
|
rightGAgent,
|
||||||
hasContent: false,
|
|
||||||
sections: [this.currentSection],
|
sections: [this.currentSection],
|
||||||
};
|
};
|
||||||
this.replaceGAgentState(leftGAgent, AgentState.LOCKED);
|
this.replaceGAgentState(leftGAgent, AgentState.LOCKED);
|
||||||
|
@ -505,10 +518,10 @@ export default class Generator {
|
||||||
|
|
||||||
handleBlockBegin({ln, blockType, tag, label}) {
|
handleBlockBegin({ln, blockType, tag, label}) {
|
||||||
this.beginNested(blockType, {
|
this.beginNested(blockType, {
|
||||||
tag,
|
|
||||||
label,
|
label,
|
||||||
name: this.nextBlockName(),
|
|
||||||
ln,
|
ln,
|
||||||
|
name: this.nextBlockName(),
|
||||||
|
tag,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -521,13 +534,13 @@ export default class Generator {
|
||||||
}
|
}
|
||||||
this._checkSectionEnd();
|
this._checkSectionEnd();
|
||||||
this.currentSection = this._makeSection({
|
this.currentSection = this._makeSection({
|
||||||
type: 'block split',
|
|
||||||
blockType,
|
blockType,
|
||||||
tag: this.textFormatter(tag),
|
|
||||||
label: this.textFormatter(label),
|
label: this.textFormatter(label),
|
||||||
left: this.currentNest.leftGAgent.id,
|
left: this.currentNest.leftGAgent.id,
|
||||||
right: this.currentNest.rightGAgent.id,
|
|
||||||
ln,
|
ln,
|
||||||
|
right: this.currentNest.rightGAgent.id,
|
||||||
|
tag: this.textFormatter(tag),
|
||||||
|
type: 'block split',
|
||||||
}, []);
|
}, []);
|
||||||
this.currentNest.sections.push(this.currentSection);
|
this.currentNest.sections.push(this.currentSection);
|
||||||
}
|
}
|
||||||
|
@ -554,9 +567,9 @@ export default class Generator {
|
||||||
this.currentSection.stages.push(...section.stages);
|
this.currentSection.stages.push(...section.stages);
|
||||||
});
|
});
|
||||||
this.addStage({
|
this.addStage({
|
||||||
type: 'block end',
|
|
||||||
left: nested.leftGAgent.id,
|
left: nested.leftGAgent.id,
|
||||||
right: nested.rightGAgent.id,
|
right: nested.rightGAgent.id,
|
||||||
|
type: 'block end',
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Empty block');
|
throw new Error('Empty block');
|
||||||
|
@ -595,10 +608,10 @@ export default class Generator {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
gAgents,
|
gAgents,
|
||||||
leftGAgent,
|
|
||||||
rightGAgent,
|
|
||||||
gAgentsContained,
|
gAgentsContained,
|
||||||
gAgentsCovered,
|
gAgentsCovered,
|
||||||
|
leftGAgent,
|
||||||
|
rightGAgent,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -614,13 +627,13 @@ export default class Generator {
|
||||||
this.activeGroups.set(alias, details);
|
this.activeGroups.set(alias, details);
|
||||||
this.addStage(this.setGAgentVis(details.gAgents, true, 'box'));
|
this.addStage(this.setGAgentVis(details.gAgents, true, 'box'));
|
||||||
this.addStage({
|
this.addStage({
|
||||||
type: 'block begin',
|
|
||||||
blockType,
|
blockType,
|
||||||
tag: this.textFormatter(tag),
|
|
||||||
canHide: false,
|
canHide: false,
|
||||||
label: this.textFormatter(label),
|
label: this.textFormatter(label),
|
||||||
left: details.leftGAgent.id,
|
left: details.leftGAgent.id,
|
||||||
right: details.rightGAgent.id,
|
right: details.rightGAgent.id,
|
||||||
|
tag: this.textFormatter(tag),
|
||||||
|
type: 'block begin',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -640,23 +653,23 @@ export default class Generator {
|
||||||
this.updateGAgentState(GAgent.make(name), {group: null});
|
this.updateGAgentState(GAgent.make(name), {group: null});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: 'block end',
|
|
||||||
left: details.leftGAgent.id,
|
left: details.leftGAgent.id,
|
||||||
right: details.rightGAgent.id,
|
right: details.rightGAgent.id,
|
||||||
|
type: 'block end',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMark({name}) {
|
handleMark({name}) {
|
||||||
this.markers.add(name);
|
this.markers.add(name);
|
||||||
this.addStage({type: 'mark', name}, false);
|
this.addStage({name, type: 'mark'}, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDivider({mode, height, label}) {
|
handleDivider({mode, height, label}) {
|
||||||
this.addStage({
|
this.addStage({
|
||||||
type: 'divider',
|
|
||||||
mode,
|
|
||||||
height,
|
|
||||||
formattedLabel: this.textFormatter(label),
|
formattedLabel: this.textFormatter(label),
|
||||||
|
height,
|
||||||
|
mode,
|
||||||
|
type: 'divider',
|
||||||
}, false);
|
}, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -664,7 +677,7 @@ export default class Generator {
|
||||||
if(target !== '' && !this.markers.has(target)) {
|
if(target !== '' && !this.markers.has(target)) {
|
||||||
throw new Error('Unknown marker: ' + target);
|
throw new Error('Unknown marker: ' + target);
|
||||||
}
|
}
|
||||||
this.addStage({type: 'async', target}, false);
|
this.addStage({target, type: 'async'}, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleLabelPattern({pattern}) {
|
handleLabelPattern({pattern}) {
|
||||||
|
@ -867,15 +880,15 @@ export default class Generator {
|
||||||
const tag = {};
|
const tag = {};
|
||||||
this.handleConnectDelayBegin({
|
this.handleConnectDelayBegin({
|
||||||
agent: agents[0],
|
agent: agents[0],
|
||||||
tag,
|
|
||||||
options,
|
|
||||||
ln: 0,
|
ln: 0,
|
||||||
|
options,
|
||||||
|
tag,
|
||||||
});
|
});
|
||||||
this.handleConnectDelayEnd({
|
this.handleConnectDelayEnd({
|
||||||
agent: agents[1],
|
agent: agents[1],
|
||||||
tag,
|
|
||||||
label,
|
label,
|
||||||
options,
|
options,
|
||||||
|
tag,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -886,10 +899,10 @@ export default class Generator {
|
||||||
gAgents = this.expandVirtualSourceAgents(gAgents);
|
gAgents = this.expandVirtualSourceAgents(gAgents);
|
||||||
|
|
||||||
const connectStage = {
|
const connectStage = {
|
||||||
type: 'connect',
|
|
||||||
agentIDs: gAgents.map((gAgent) => gAgent.id),
|
agentIDs: gAgents.map((gAgent) => gAgent.id),
|
||||||
label: this.textFormatter(this.applyLabelPattern(label)),
|
label: this.textFormatter(this.applyLabelPattern(label)),
|
||||||
options,
|
options,
|
||||||
|
type: 'connect',
|
||||||
};
|
};
|
||||||
|
|
||||||
this.addParallelStages(this._makeConnectParallelStages(
|
this.addParallelStages(this._makeConnectParallelStages(
|
||||||
|
@ -908,14 +921,14 @@ export default class Generator {
|
||||||
const uniqueTag = this.nextVirtualAgentName();
|
const uniqueTag = this.nextVirtualAgentName();
|
||||||
|
|
||||||
const connectStage = {
|
const connectStage = {
|
||||||
type: 'connect-delay-begin',
|
|
||||||
tag: uniqueTag,
|
|
||||||
agentIDs: null,
|
agentIDs: null,
|
||||||
label: null,
|
label: null,
|
||||||
options,
|
options,
|
||||||
|
tag: uniqueTag,
|
||||||
|
type: 'connect-delay-begin',
|
||||||
};
|
};
|
||||||
|
|
||||||
dcs.set(tag, {tag, uniqueTag, ln, gAgents, connectStage});
|
dcs.set(tag, {connectStage, gAgents, ln, tag, uniqueTag});
|
||||||
|
|
||||||
this.addParallelStages(this._makeConnectParallelStages(
|
this.addParallelStages(this._makeConnectParallelStages(
|
||||||
flags,
|
flags,
|
||||||
|
@ -955,8 +968,8 @@ export default class Generator {
|
||||||
});
|
});
|
||||||
|
|
||||||
const connectEndStage = {
|
const connectEndStage = {
|
||||||
type: 'connect-delay-end',
|
|
||||||
tag: dcInfo.uniqueTag,
|
tag: dcInfo.uniqueTag,
|
||||||
|
type: 'connect-delay-end',
|
||||||
};
|
};
|
||||||
|
|
||||||
this.addParallelStages(this._makeConnectParallelStages(
|
this.addParallelStages(this._makeConnectParallelStages(
|
||||||
|
@ -987,18 +1000,18 @@ export default class Generator {
|
||||||
this.defineGAgents(gAgents);
|
this.defineGAgents(gAgents);
|
||||||
|
|
||||||
this.addStage({
|
this.addStage({
|
||||||
type,
|
|
||||||
agentIDs,
|
agentIDs,
|
||||||
mode,
|
|
||||||
label: this.textFormatter(label),
|
label: this.textFormatter(label),
|
||||||
|
mode,
|
||||||
|
type,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleAgentDefine({agents}) {
|
handleAgentDefine({agents}) {
|
||||||
const gAgents = agents.map(this.toGAgent);
|
const gAgents = agents.map(this.toGAgent);
|
||||||
this.validateGAgents(gAgents, {
|
this.validateGAgents(gAgents, {
|
||||||
allowGrouped: true,
|
|
||||||
allowCovered: true,
|
allowCovered: true,
|
||||||
|
allowGrouped: true,
|
||||||
});
|
});
|
||||||
mergeSets(this.gAgents, gAgents, GAgent.equals);
|
mergeSets(this.gAgents, gAgents, GAgent.equals);
|
||||||
}
|
}
|
||||||
|
@ -1007,8 +1020,8 @@ export default class Generator {
|
||||||
const gAgent = this.toGAgent(agent);
|
const gAgent = this.toGAgent(agent);
|
||||||
const gAgents = [gAgent];
|
const gAgents = [gAgent];
|
||||||
this.validateGAgents(gAgents, {
|
this.validateGAgents(gAgents, {
|
||||||
allowGrouped: true,
|
|
||||||
allowCovered: true,
|
allowCovered: true,
|
||||||
|
allowGrouped: true,
|
||||||
});
|
});
|
||||||
mergeSets(this.gAgents, gAgents, GAgent.equals);
|
mergeSets(this.gAgents, gAgents, GAgent.equals);
|
||||||
|
|
||||||
|
@ -1086,10 +1099,10 @@ export default class Generator {
|
||||||
|
|
||||||
this.textFormatter = meta.textFormatter;
|
this.textFormatter = meta.textFormatter;
|
||||||
const globals = this.beginNested('global', {
|
const globals = this.beginNested('global', {
|
||||||
tag: '',
|
|
||||||
label: '',
|
label: '',
|
||||||
name: '',
|
|
||||||
ln: 0,
|
ln: 0,
|
||||||
|
name: '',
|
||||||
|
tag: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
stages.forEach(this.handleStage);
|
stages.forEach(this.handleStage);
|
||||||
|
@ -1117,12 +1130,12 @@ export default class Generator {
|
||||||
swapFirstBegin(globals.stages, meta.headers || 'box');
|
swapFirstBegin(globals.stages, meta.headers || 'box');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
meta: {
|
|
||||||
title: this.textFormatter(meta.title),
|
|
||||||
theme: meta.theme,
|
|
||||||
code: meta.code,
|
|
||||||
},
|
|
||||||
agents: this.gAgents.slice(),
|
agents: this.gAgents.slice(),
|
||||||
|
meta: {
|
||||||
|
code: meta.code,
|
||||||
|
theme: meta.theme,
|
||||||
|
title: this.textFormatter(meta.title),
|
||||||
|
},
|
||||||
stages: globals.stages,
|
stages: globals.stages,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
/* eslint-disable sort-keys */ // Maybe later
|
|
||||||
|
|
||||||
import {dom, textSizerFactory} from '../../../spec/stubs/TestDOM.mjs';
|
import {dom, textSizerFactory} from '../../../spec/stubs/TestDOM.mjs';
|
||||||
import SVG from '../../svg/SVG.mjs';
|
import SVG from '../../svg/SVG.mjs';
|
||||||
import parser from './MarkdownParser.mjs';
|
import parser from './MarkdownParser.mjs';
|
||||||
|
@ -8,7 +6,7 @@ describe('Markdown Parser', () => {
|
||||||
it('converts simple text', () => {
|
it('converts simple text', () => {
|
||||||
const formatted = parser('hello everybody');
|
const formatted = parser('hello everybody');
|
||||||
|
|
||||||
expect(formatted).toEqual([[{text: 'hello everybody', attrs: null}]]);
|
expect(formatted).toEqual([[{attrs: null, text: 'hello everybody'}]]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('produces an empty array given an empty input', () => {
|
it('produces an empty array given an empty input', () => {
|
||||||
|
@ -21,8 +19,8 @@ describe('Markdown Parser', () => {
|
||||||
const formatted = parser('hello\neverybody');
|
const formatted = parser('hello\neverybody');
|
||||||
|
|
||||||
expect(formatted).toEqual([
|
expect(formatted).toEqual([
|
||||||
[{text: 'hello', attrs: null}],
|
[{attrs: null, text: 'hello'}],
|
||||||
[{text: 'everybody', attrs: null}],
|
[{attrs: null, text: 'everybody'}],
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -30,11 +28,11 @@ describe('Markdown Parser', () => {
|
||||||
const formatted = parser('a **b** c __d__ e');
|
const formatted = parser('a **b** c __d__ e');
|
||||||
|
|
||||||
expect(formatted).toEqual([[
|
expect(formatted).toEqual([[
|
||||||
{text: 'a ', attrs: null},
|
{attrs: null, text: 'a '},
|
||||||
{text: 'b', attrs: {'font-weight': 'bolder'}},
|
{attrs: {'font-weight': 'bolder'}, text: 'b'},
|
||||||
{text: ' c ', attrs: null},
|
{attrs: null, text: ' c '},
|
||||||
{text: 'd', attrs: {'font-weight': 'bolder'}},
|
{attrs: {'font-weight': 'bolder'}, text: 'd'},
|
||||||
{text: ' e', attrs: null},
|
{attrs: null, text: ' e'},
|
||||||
]]);
|
]]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -42,7 +40,7 @@ describe('Markdown Parser', () => {
|
||||||
const formatted = parser('a**b**c__d__e');
|
const formatted = parser('a**b**c__d__e');
|
||||||
|
|
||||||
expect(formatted).toEqual([[
|
expect(formatted).toEqual([[
|
||||||
{text: 'a**b**c__d__e', attrs: null},
|
{attrs: null, text: 'a**b**c__d__e'},
|
||||||
]]);
|
]]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -50,11 +48,11 @@ describe('Markdown Parser', () => {
|
||||||
const formatted = parser('a **b\nc** d');
|
const formatted = parser('a **b\nc** d');
|
||||||
|
|
||||||
expect(formatted).toEqual([[
|
expect(formatted).toEqual([[
|
||||||
{text: 'a ', attrs: null},
|
{attrs: null, text: 'a '},
|
||||||
{text: 'b', attrs: {'font-weight': 'bolder'}},
|
{attrs: {'font-weight': 'bolder'}, text: 'b'},
|
||||||
], [
|
], [
|
||||||
{text: 'c', attrs: {'font-weight': 'bolder'}},
|
{attrs: {'font-weight': 'bolder'}, text: 'c'},
|
||||||
{text: ' d', attrs: null},
|
{attrs: null, text: ' d'},
|
||||||
]]);
|
]]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -62,11 +60,11 @@ describe('Markdown Parser', () => {
|
||||||
const formatted = parser('a *b* c _d_ e');
|
const formatted = parser('a *b* c _d_ e');
|
||||||
|
|
||||||
expect(formatted).toEqual([[
|
expect(formatted).toEqual([[
|
||||||
{text: 'a ', attrs: null},
|
{attrs: null, text: 'a '},
|
||||||
{text: 'b', attrs: {'font-style': 'italic'}},
|
{attrs: {'font-style': 'italic'}, text: 'b'},
|
||||||
{text: ' c ', attrs: null},
|
{attrs: null, text: ' c '},
|
||||||
{text: 'd', attrs: {'font-style': 'italic'}},
|
{attrs: {'font-style': 'italic'}, text: 'd'},
|
||||||
{text: ' e', attrs: null},
|
{attrs: null, text: ' e'},
|
||||||
]]);
|
]]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -74,9 +72,9 @@ describe('Markdown Parser', () => {
|
||||||
const formatted = parser('a ~b~ c');
|
const formatted = parser('a ~b~ c');
|
||||||
|
|
||||||
expect(formatted).toEqual([[
|
expect(formatted).toEqual([[
|
||||||
{text: 'a ', attrs: null},
|
{attrs: null, text: 'a '},
|
||||||
{text: 'b', attrs: {'text-decoration': 'line-through'}},
|
{attrs: {'text-decoration': 'line-through'}, text: 'b'},
|
||||||
{text: ' c', attrs: null},
|
{attrs: null, text: ' c'},
|
||||||
]]);
|
]]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -84,9 +82,9 @@ describe('Markdown Parser', () => {
|
||||||
const formatted = parser('a `b` c');
|
const formatted = parser('a `b` c');
|
||||||
|
|
||||||
expect(formatted).toEqual([[
|
expect(formatted).toEqual([[
|
||||||
{text: 'a ', attrs: null},
|
{attrs: null, text: 'a '},
|
||||||
{text: 'b', attrs: {'font-family': 'monospace'}},
|
{attrs: {'font-family': 'monospace'}, text: 'b'},
|
||||||
{text: ' c', attrs: null},
|
{attrs: null, text: ' c'},
|
||||||
]]);
|
]]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -94,9 +92,9 @@ describe('Markdown Parser', () => {
|
||||||
const formatted = parser('a.`b`.c');
|
const formatted = parser('a.`b`.c');
|
||||||
|
|
||||||
expect(formatted).toEqual([[
|
expect(formatted).toEqual([[
|
||||||
{text: 'a.', attrs: null},
|
{attrs: null, text: 'a.'},
|
||||||
{text: 'b', attrs: {'font-family': 'monospace'}},
|
{attrs: {'font-family': 'monospace'}, text: 'b'},
|
||||||
{text: '.c', attrs: null},
|
{attrs: null, text: '.c'},
|
||||||
]]);
|
]]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -104,12 +102,12 @@ describe('Markdown Parser', () => {
|
||||||
const formatted = parser('a **_b_ c**');
|
const formatted = parser('a **_b_ c**');
|
||||||
|
|
||||||
expect(formatted).toEqual([[
|
expect(formatted).toEqual([[
|
||||||
{text: 'a ', attrs: null},
|
{attrs: null, text: 'a '},
|
||||||
{text: 'b', attrs: {
|
{attrs: {
|
||||||
'font-weight': 'bolder',
|
|
||||||
'font-style': 'italic',
|
'font-style': 'italic',
|
||||||
}},
|
'font-weight': 'bolder',
|
||||||
{text: ' c', attrs: {'font-weight': 'bolder'}},
|
}, text: 'b'},
|
||||||
|
{attrs: {'font-weight': 'bolder'}, text: ' c'},
|
||||||
]]);
|
]]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -117,16 +115,16 @@ describe('Markdown Parser', () => {
|
||||||
const formatted = parser('_a **b_ ~c~**');
|
const formatted = parser('_a **b_ ~c~**');
|
||||||
|
|
||||||
expect(formatted).toEqual([[
|
expect(formatted).toEqual([[
|
||||||
{text: 'a ', attrs: {'font-style': 'italic'}},
|
{attrs: {'font-style': 'italic'}, text: 'a '},
|
||||||
{text: 'b', attrs: {
|
{attrs: {
|
||||||
'font-weight': 'bolder',
|
|
||||||
'font-style': 'italic',
|
'font-style': 'italic',
|
||||||
}},
|
'font-weight': 'bolder',
|
||||||
{text: ' ', attrs: {'font-weight': 'bolder'}},
|
}, text: 'b'},
|
||||||
{text: 'c', attrs: {
|
{attrs: {'font-weight': 'bolder'}, text: ' '},
|
||||||
|
{attrs: {
|
||||||
'font-weight': 'bolder',
|
'font-weight': 'bolder',
|
||||||
'text-decoration': 'line-through',
|
'text-decoration': 'line-through',
|
||||||
}},
|
}, text: 'c'},
|
||||||
]]);
|
]]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
/* eslint-disable max-lines */
|
|
||||||
/* eslint-disable sort-keys */ // Maybe later
|
/* eslint-disable sort-keys */ // Maybe later
|
||||||
/* eslint-disable complexity */ // Temporary ignore while switching linter
|
|
||||||
/* eslint-disable no-param-reassign */ // Also temporary
|
|
||||||
|
|
||||||
import {combine, last} from '../../core/ArrayUtilities.mjs';
|
import {combine, last} from '../../core/ArrayUtilities.mjs';
|
||||||
import Tokeniser from './Tokeniser.mjs';
|
import Tokeniser from './Tokeniser.mjs';
|
||||||
|
@ -90,17 +87,47 @@ const NOTE_TYPES = {
|
||||||
'text': {
|
'text': {
|
||||||
mode: 'text',
|
mode: 'text',
|
||||||
types: {
|
types: {
|
||||||
'left': {type: 'note left', skip: ['of'], min: 0, max: null},
|
'left': {
|
||||||
'right': {type: 'note right', skip: ['of'], min: 0, max: null},
|
type: 'note left',
|
||||||
|
skip: ['of'],
|
||||||
|
min: 0,
|
||||||
|
max: Number.POSITIVE_INFINITY,
|
||||||
|
},
|
||||||
|
'right': {
|
||||||
|
type: 'note right',
|
||||||
|
skip: ['of'],
|
||||||
|
min: 0,
|
||||||
|
max: Number.POSITIVE_INFINITY,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'note': {
|
'note': {
|
||||||
mode: 'note',
|
mode: 'note',
|
||||||
types: {
|
types: {
|
||||||
'over': {type: 'note over', skip: [], min: 0, max: null},
|
'over': {
|
||||||
'left': {type: 'note left', skip: ['of'], min: 0, max: null},
|
type: 'note over',
|
||||||
'right': {type: 'note right', skip: ['of'], min: 0, max: null},
|
skip: [],
|
||||||
'between': {type: 'note between', skip: [], min: 2, max: null},
|
min: 0,
|
||||||
|
max: Number.POSITIVE_INFINITY,
|
||||||
|
},
|
||||||
|
'left': {
|
||||||
|
type: 'note left',
|
||||||
|
skip: ['of'],
|
||||||
|
min: 0,
|
||||||
|
max: Number.POSITIVE_INFINITY,
|
||||||
|
},
|
||||||
|
'right': {
|
||||||
|
type: 'note right',
|
||||||
|
skip: ['of'],
|
||||||
|
min: 0,
|
||||||
|
max: Number.POSITIVE_INFINITY,
|
||||||
|
},
|
||||||
|
'between': {
|
||||||
|
type: 'note between',
|
||||||
|
skip: [],
|
||||||
|
min: 2,
|
||||||
|
max: Number.POSITIVE_INFINITY,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'state': {
|
'state': {
|
||||||
|
@ -135,15 +162,20 @@ function makeError(message, token = null) {
|
||||||
return new Error(message + suffix);
|
return new Error(message + suffix);
|
||||||
}
|
}
|
||||||
|
|
||||||
function joinLabel(line, begin = 0, end = null) {
|
function endIndexInLine(line, end = null) {
|
||||||
if(end === null) {
|
if(end === null) {
|
||||||
end = line.length;
|
return line.length;
|
||||||
}
|
}
|
||||||
if(end <= begin) {
|
return end;
|
||||||
|
}
|
||||||
|
|
||||||
|
function joinLabel(line, begin = 0, end = null) {
|
||||||
|
const e = endIndexInLine(line, end);
|
||||||
|
if(e <= begin) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
let result = line[begin].v;
|
let result = line[begin].v;
|
||||||
for(let i = begin + 1; i < end; ++ i) {
|
for(let i = begin + 1; i < e; ++ i) {
|
||||||
result += line[i].s + line[i].v;
|
result += line[i].s + line[i].v;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -179,30 +211,23 @@ function skipOver(line, start, skip, error = null) {
|
||||||
return start + skip.length;
|
return start + skip.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
function findToken(line, tokens, {
|
function findTokens(line, tokens, {
|
||||||
start = 0,
|
start = 0,
|
||||||
limit = null,
|
limit = null,
|
||||||
orEnd = false,
|
orEnd = false,
|
||||||
} = {}) {
|
} = {}) {
|
||||||
if(limit === null) {
|
const e = endIndexInLine(line, limit);
|
||||||
limit = line.length;
|
for(let i = start; i <= e - tokens.length; ++ i) {
|
||||||
}
|
|
||||||
if(!Array.isArray(tokens)) {
|
|
||||||
tokens = [tokens];
|
|
||||||
}
|
|
||||||
for(let i = start; i <= limit - tokens.length; ++ i) {
|
|
||||||
if(skipOver(line, i, tokens) !== i) {
|
if(skipOver(line, i, tokens) !== i) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return orEnd ? limit : -1;
|
return orEnd ? e : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function findFirstToken(line, tokenMap, {start = 0, limit = null} = {}) {
|
function findFirstToken(line, tokenMap, {start = 0, limit = null} = {}) {
|
||||||
if(limit === null) {
|
const e = endIndexInLine(line, limit);
|
||||||
limit = line.length;
|
for(let pos = start; pos < e; ++ pos) {
|
||||||
}
|
|
||||||
for(let pos = start; pos < limit; ++ pos) {
|
|
||||||
const value = tokenMap.get(tokenKeyword(line[pos]));
|
const value = tokenMap.get(tokenKeyword(line[pos]));
|
||||||
if(value) {
|
if(value) {
|
||||||
return {pos, value};
|
return {pos, value};
|
||||||
|
@ -212,12 +237,9 @@ function findFirstToken(line, tokenMap, {start = 0, limit = null} = {}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function readAgentAlias(line, start, end, {enableAlias, allowBlankName}) {
|
function readAgentAlias(line, start, end, {enableAlias, allowBlankName}) {
|
||||||
let aliasSep = -1;
|
let aliasSep = end;
|
||||||
if(enableAlias) {
|
if(enableAlias) {
|
||||||
aliasSep = findToken(line, 'as', {start});
|
aliasSep = findTokens(line, ['as'], {limit: end, orEnd: true, start});
|
||||||
}
|
|
||||||
if(aliasSep === -1 || aliasSep >= end) {
|
|
||||||
aliasSep = end;
|
|
||||||
}
|
}
|
||||||
if(start >= aliasSep && !allowBlankName) {
|
if(start >= aliasSep && !allowBlankName) {
|
||||||
let errPosToken = line[start];
|
let errPosToken = line[start];
|
||||||
|
@ -286,29 +308,17 @@ function readAgentList(line, start, end, readAgentOpts) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const PARSERS = [
|
const PARSERS = [
|
||||||
(line, meta) => { // Title
|
{begin: ['title'], fn: (line, meta) => { // Title
|
||||||
if(tokenKeyword(line[0]) !== 'title') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
meta.title = joinLabel(line, 1);
|
meta.title = joinLabel(line, 1);
|
||||||
return true;
|
return true;
|
||||||
},
|
}},
|
||||||
|
|
||||||
(line, meta) => { // Theme
|
|
||||||
if(tokenKeyword(line[0]) !== 'theme') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
{begin: ['theme'], fn: (line, meta) => { // Theme
|
||||||
meta.theme = joinLabel(line, 1);
|
meta.theme = joinLabel(line, 1);
|
||||||
return true;
|
return true;
|
||||||
},
|
}},
|
||||||
|
|
||||||
(line, meta) => { // Terminators
|
|
||||||
if(tokenKeyword(line[0]) !== 'terminators') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
{begin: ['terminators'], fn: (line, meta) => { // Terminators
|
||||||
const type = tokenKeyword(line[1]);
|
const type = tokenKeyword(line[1]);
|
||||||
if(!type) {
|
if(!type) {
|
||||||
throw makeError('Unspecified termination', line[0]);
|
throw makeError('Unspecified termination', line[0]);
|
||||||
|
@ -318,13 +328,9 @@ const PARSERS = [
|
||||||
}
|
}
|
||||||
meta.terminators = type;
|
meta.terminators = type;
|
||||||
return true;
|
return true;
|
||||||
},
|
}},
|
||||||
|
|
||||||
(line, meta) => { // Headers
|
|
||||||
if(tokenKeyword(line[0]) !== 'headers') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
{begin: ['headers'], fn: (line, meta) => { // Headers
|
||||||
const type = tokenKeyword(line[1]);
|
const type = tokenKeyword(line[1]);
|
||||||
if(!type) {
|
if(!type) {
|
||||||
throw makeError('Unspecified header', line[0]);
|
throw makeError('Unspecified header', line[0]);
|
||||||
|
@ -334,15 +340,11 @@ const PARSERS = [
|
||||||
}
|
}
|
||||||
meta.headers = type;
|
meta.headers = type;
|
||||||
return true;
|
return true;
|
||||||
},
|
}},
|
||||||
|
|
||||||
(line) => { // Divider
|
{begin: ['divider'], fn: (line) => { // Divider
|
||||||
if(tokenKeyword(line[0]) !== 'divider') {
|
const labelSep = findTokens(line, [':'], {orEnd: true});
|
||||||
return null;
|
const heightSep = findTokens(line, ['with', 'height'], {
|
||||||
}
|
|
||||||
|
|
||||||
const labelSep = findToken(line, ':', {orEnd: true});
|
|
||||||
const heightSep = findToken(line, ['with', 'height'], {
|
|
||||||
limit: labelSep,
|
limit: labelSep,
|
||||||
orEnd: true,
|
orEnd: true,
|
||||||
});
|
});
|
||||||
|
@ -368,13 +370,9 @@ const PARSERS = [
|
||||||
height,
|
height,
|
||||||
label: joinLabel(line, labelSep + 1),
|
label: joinLabel(line, labelSep + 1),
|
||||||
};
|
};
|
||||||
},
|
}},
|
||||||
|
|
||||||
(line) => { // Autolabel
|
|
||||||
if(tokenKeyword(line[0]) !== 'autolabel') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
{begin: ['autolabel'], fn: (line) => { // Autolabel
|
||||||
let raw = null;
|
let raw = null;
|
||||||
if(tokenKeyword(line[1]) === 'off') {
|
if(tokenKeyword(line[1]) === 'off') {
|
||||||
raw = '<label>';
|
raw = '<label>';
|
||||||
|
@ -385,13 +383,16 @@ const PARSERS = [
|
||||||
type: 'label pattern',
|
type: 'label pattern',
|
||||||
pattern: labelPatternParser(raw),
|
pattern: labelPatternParser(raw),
|
||||||
};
|
};
|
||||||
},
|
}},
|
||||||
|
|
||||||
(line) => { // Block
|
{begin: ['end'], fn: (line) => { // Block End
|
||||||
if(tokenKeyword(line[0]) === 'end' && line.length === 1) {
|
if(line.length !== 1) {
|
||||||
return {type: 'block end'};
|
return null;
|
||||||
}
|
}
|
||||||
|
return {type: 'block end'};
|
||||||
|
}},
|
||||||
|
|
||||||
|
{begin: [], fn: (line) => { // Block
|
||||||
const type = BLOCK_TYPES[tokenKeyword(line[0])];
|
const type = BLOCK_TYPES[tokenKeyword(line[0])];
|
||||||
if(!type) {
|
if(!type) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -407,17 +408,11 @@ const PARSERS = [
|
||||||
tag: type.tag,
|
tag: type.tag,
|
||||||
label: joinLabel(line, skip),
|
label: joinLabel(line, skip),
|
||||||
};
|
};
|
||||||
},
|
}},
|
||||||
|
|
||||||
(line) => { // Begin reference
|
{begin: ['begin', 'reference'], fn: (line) => { // Begin reference
|
||||||
if(
|
|
||||||
tokenKeyword(line[0]) !== 'begin' ||
|
|
||||||
tokenKeyword(line[1]) !== 'reference'
|
|
||||||
) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
let agents = [];
|
let agents = [];
|
||||||
const labelSep = findToken(line, ':');
|
const labelSep = findTokens(line, [':']);
|
||||||
if(tokenKeyword(line[2]) === 'over' && labelSep > 3) {
|
if(tokenKeyword(line[2]) === 'over' && labelSep > 3) {
|
||||||
agents = readAgentList(line, 3, labelSep);
|
agents = readAgentList(line, 3, labelSep);
|
||||||
} else if(labelSep !== 2) {
|
} else if(labelSep !== 2) {
|
||||||
|
@ -440,9 +435,9 @@ const PARSERS = [
|
||||||
label: def.name,
|
label: def.name,
|
||||||
alias: def.alias,
|
alias: def.alias,
|
||||||
};
|
};
|
||||||
},
|
}},
|
||||||
|
|
||||||
(line) => { // Agent
|
{begin: [], fn: (line) => { // Agent
|
||||||
const type = AGENT_MANIPULATION_TYPES[tokenKeyword(line[0])];
|
const type = AGENT_MANIPULATION_TYPES[tokenKeyword(line[0])];
|
||||||
if(!type || line.length <= 1) {
|
if(!type || line.length <= 1) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -450,12 +445,9 @@ const PARSERS = [
|
||||||
return Object.assign({
|
return Object.assign({
|
||||||
agents: readAgentList(line, 1, line.length, {aliases: true}),
|
agents: readAgentList(line, 1, line.length, {aliases: true}),
|
||||||
}, type);
|
}, type);
|
||||||
},
|
}},
|
||||||
|
|
||||||
(line) => { // Async
|
{begin: ['simultaneously'], fn: (line) => { // Async
|
||||||
if(tokenKeyword(line[0]) !== 'simultaneously') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if(tokenKeyword(last(line)) !== ':') {
|
if(tokenKeyword(last(line)) !== ':') {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -470,11 +462,11 @@ const PARSERS = [
|
||||||
type: 'async',
|
type: 'async',
|
||||||
target,
|
target,
|
||||||
};
|
};
|
||||||
},
|
}},
|
||||||
|
|
||||||
(line) => { // Note
|
{begin: [], fn: (line) => { // Note
|
||||||
const mode = NOTE_TYPES[tokenKeyword(line[0])];
|
const mode = NOTE_TYPES[tokenKeyword(line[0])];
|
||||||
const labelSep = findToken(line, ':');
|
const labelSep = findTokens(line, [':']);
|
||||||
if(!mode || labelSep === -1) {
|
if(!mode || labelSep === -1) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -488,7 +480,7 @@ const PARSERS = [
|
||||||
if(agents.length < type.min) {
|
if(agents.length < type.min) {
|
||||||
throw makeError('Too few agents for ' + mode.mode, line[0]);
|
throw makeError('Too few agents for ' + mode.mode, line[0]);
|
||||||
}
|
}
|
||||||
if(type.max !== null && agents.length > type.max) {
|
if(agents.length > type.max) {
|
||||||
throw makeError('Too many agents for ' + mode.mode, line[0]);
|
throw makeError('Too many agents for ' + mode.mode, line[0]);
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
@ -497,10 +489,10 @@ const PARSERS = [
|
||||||
mode: mode.mode,
|
mode: mode.mode,
|
||||||
label: joinLabel(line, labelSep + 1),
|
label: joinLabel(line, labelSep + 1),
|
||||||
};
|
};
|
||||||
},
|
}},
|
||||||
|
|
||||||
(line) => { // Connect
|
{begin: [], fn: (line) => { // Connect
|
||||||
const labelSep = findToken(line, ':', {orEnd: true});
|
const labelSep = findTokens(line, [':'], {orEnd: true});
|
||||||
const connectionToken = findFirstToken(
|
const connectionToken = findFirstToken(
|
||||||
line,
|
line,
|
||||||
CONNECT.types,
|
CONNECT.types,
|
||||||
|
@ -548,9 +540,9 @@ const PARSERS = [
|
||||||
options: connectionToken.value,
|
options: connectionToken.value,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
}},
|
||||||
|
|
||||||
(line) => { // Marker
|
{begin: [], fn: (line) => { // Marker
|
||||||
if(line.length < 2 || tokenKeyword(last(line)) !== ':') {
|
if(line.length < 2 || tokenKeyword(last(line)) !== ':') {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -558,10 +550,10 @@ const PARSERS = [
|
||||||
type: 'mark',
|
type: 'mark',
|
||||||
name: joinLabel(line, 0, line.length - 1),
|
name: joinLabel(line, 0, line.length - 1),
|
||||||
};
|
};
|
||||||
},
|
}},
|
||||||
|
|
||||||
(line) => { // Options
|
{begin: [], fn: (line) => { // Options
|
||||||
const sepPos = findToken(line, 'is');
|
const sepPos = findTokens(line, ['is']);
|
||||||
if(sepPos < 1) {
|
if(sepPos < 1) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -583,13 +575,16 @@ const PARSERS = [
|
||||||
agent,
|
agent,
|
||||||
options,
|
options,
|
||||||
};
|
};
|
||||||
},
|
}},
|
||||||
];
|
];
|
||||||
|
|
||||||
function parseLine(line, {meta, stages}) {
|
function parseLine(line, {meta, stages}) {
|
||||||
let stage = null;
|
let stage = null;
|
||||||
for(let i = 0; i < PARSERS.length; ++ i) {
|
for(const {begin, fn} of PARSERS) {
|
||||||
stage = PARSERS[i](line, meta);
|
if(skipOver(line, 0, begin) !== begin.length) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
stage = fn(line, meta);
|
||||||
if(stage) {
|
if(stage) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,6 +140,16 @@ describe('Sequence Parser', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('propagates aliases', () => {
|
it('propagates aliases', () => {
|
||||||
|
const parsed = parser.parse('define Foo Bar as A');
|
||||||
|
|
||||||
|
expect(parsed.stages).toEqual([
|
||||||
|
{type: 'agent define', ln: jasmine.anything(), agents: [
|
||||||
|
{name: 'Foo Bar', alias: 'A', flags: []},
|
||||||
|
]},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('propagates long aliases', () => {
|
||||||
const parsed = parser.parse('define Foo Bar as A B');
|
const parsed = parser.parse('define Foo Bar as A B');
|
||||||
|
|
||||||
expect(parsed.stages).toEqual([
|
expect(parsed.stages).toEqual([
|
||||||
|
@ -149,6 +159,16 @@ describe('Sequence Parser', () => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('ignores missing aliases', () => {
|
||||||
|
const parsed = parser.parse('define Foo Bar as');
|
||||||
|
|
||||||
|
expect(parsed.stages).toEqual([
|
||||||
|
{type: 'agent define', ln: jasmine.anything(), agents: [
|
||||||
|
{name: 'Foo Bar', alias: '', flags: []},
|
||||||
|
]},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
it('propagates agent options', () => {
|
it('propagates agent options', () => {
|
||||||
const parsed = parser.parse('Foo bar is zig zag');
|
const parsed = parser.parse('Foo bar is zig zag');
|
||||||
|
|
||||||
|
@ -256,6 +276,12 @@ describe('Sequence Parser', () => {
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('rejects missing agent names with aliases', () => {
|
||||||
|
expect(() => parser.parse('define as A')).toThrow(new Error(
|
||||||
|
'Missing agent name at line 1, character 7'
|
||||||
|
));
|
||||||
|
});
|
||||||
|
|
||||||
it('parses source agents', () => {
|
it('parses source agents', () => {
|
||||||
const parsed = parser.parse('A -> *');
|
const parsed = parser.parse('A -> *');
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
/* eslint-disable max-lines */
|
|
||||||
|
|
||||||
import './components/AgentCap.mjs';
|
import './components/AgentCap.mjs';
|
||||||
import './components/AgentHighlight.mjs';
|
import './components/AgentHighlight.mjs';
|
||||||
import './components/Block.mjs';
|
import './components/Block.mjs';
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
/* eslint-disable sort-keys */ // Maybe later
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
VirtualDocument,
|
VirtualDocument,
|
||||||
textSizerFactory,
|
textSizerFactory,
|
||||||
|
@ -13,8 +11,8 @@ describe('Sequence Renderer', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
renderer = new Renderer({
|
renderer = new Renderer({
|
||||||
document: new VirtualDocument(),
|
document: new VirtualDocument(),
|
||||||
themes: [new BasicThemeFactory()],
|
|
||||||
textSizerFactory,
|
textSizerFactory,
|
||||||
|
themes: [new BasicThemeFactory()],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -28,14 +26,14 @@ describe('Sequence Renderer', () => {
|
||||||
|
|
||||||
const GENERATED = {
|
const GENERATED = {
|
||||||
connect: (agentIDs, label = []) => ({
|
connect: (agentIDs, label = []) => ({
|
||||||
type: 'connect',
|
|
||||||
agentIDs,
|
agentIDs,
|
||||||
label,
|
label,
|
||||||
options: {
|
options: {
|
||||||
line: 'solid',
|
|
||||||
left: 0,
|
left: 0,
|
||||||
|
line: 'solid',
|
||||||
right: 1,
|
right: 1,
|
||||||
},
|
},
|
||||||
|
type: 'connect',
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -49,30 +47,30 @@ describe('Sequence Renderer', () => {
|
||||||
describe('.render', () => {
|
describe('.render', () => {
|
||||||
it('populates the SVG with content', () => {
|
it('populates the SVG with content', () => {
|
||||||
renderer.render({
|
renderer.render({
|
||||||
meta: {title: format('Title')},
|
|
||||||
agents: [
|
agents: [
|
||||||
{
|
{
|
||||||
id: '[',
|
|
||||||
formattedLabel: null,
|
|
||||||
anchorRight: true,
|
anchorRight: true,
|
||||||
options: [],
|
|
||||||
}, {
|
|
||||||
id: 'Col 1',
|
|
||||||
formattedLabel: format('Col 1!'),
|
|
||||||
anchorRight: false,
|
|
||||||
options: [],
|
|
||||||
}, {
|
|
||||||
id: 'Col 2',
|
|
||||||
formattedLabel: format('Col 2!'),
|
|
||||||
anchorRight: false,
|
|
||||||
options: [],
|
|
||||||
}, {
|
|
||||||
id: ']',
|
|
||||||
formattedLabel: null,
|
formattedLabel: null,
|
||||||
|
id: '[',
|
||||||
|
options: [],
|
||||||
|
}, {
|
||||||
anchorRight: false,
|
anchorRight: false,
|
||||||
|
formattedLabel: format('Col 1!'),
|
||||||
|
id: 'Col 1',
|
||||||
|
options: [],
|
||||||
|
}, {
|
||||||
|
anchorRight: false,
|
||||||
|
formattedLabel: format('Col 2!'),
|
||||||
|
id: 'Col 2',
|
||||||
|
options: [],
|
||||||
|
}, {
|
||||||
|
anchorRight: false,
|
||||||
|
formattedLabel: null,
|
||||||
|
id: ']',
|
||||||
options: [],
|
options: [],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
meta: {title: format('Title')},
|
||||||
stages: [],
|
stages: [],
|
||||||
});
|
});
|
||||||
const element = renderer.dom();
|
const element = renderer.dom();
|
||||||
|
@ -83,20 +81,20 @@ describe('Sequence Renderer', () => {
|
||||||
|
|
||||||
it('adds the code as metadata', () => {
|
it('adds the code as metadata', () => {
|
||||||
renderer.render({
|
renderer.render({
|
||||||
meta: {title: [], code: 'hello'},
|
|
||||||
agents: [
|
agents: [
|
||||||
{
|
{
|
||||||
id: '[',
|
|
||||||
formattedLabel: null,
|
|
||||||
anchorRight: true,
|
anchorRight: true,
|
||||||
|
formattedLabel: null,
|
||||||
|
id: '[',
|
||||||
options: [],
|
options: [],
|
||||||
}, {
|
}, {
|
||||||
id: ']',
|
|
||||||
formattedLabel: null,
|
|
||||||
anchorRight: false,
|
anchorRight: false,
|
||||||
|
formattedLabel: null,
|
||||||
|
id: ']',
|
||||||
options: [],
|
options: [],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
meta: {code: 'hello', title: []},
|
||||||
stages: [],
|
stages: [],
|
||||||
});
|
});
|
||||||
const element = renderer.dom();
|
const element = renderer.dom();
|
||||||
|
@ -111,34 +109,34 @@ describe('Sequence Renderer', () => {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
renderer.render({
|
renderer.render({
|
||||||
meta: {title: []},
|
|
||||||
agents: [
|
agents: [
|
||||||
{
|
{
|
||||||
id: '[',
|
|
||||||
formattedLabel: null,
|
|
||||||
anchorRight: true,
|
anchorRight: true,
|
||||||
options: [],
|
|
||||||
}, {
|
|
||||||
id: 'A',
|
|
||||||
formattedLabel: format('A!'),
|
|
||||||
anchorRight: false,
|
|
||||||
options: [],
|
|
||||||
}, {
|
|
||||||
id: 'B',
|
|
||||||
formattedLabel: format('B!'),
|
|
||||||
anchorRight: false,
|
|
||||||
options: [],
|
|
||||||
}, {
|
|
||||||
id: ']',
|
|
||||||
formattedLabel: null,
|
formattedLabel: null,
|
||||||
|
id: '[',
|
||||||
|
options: [],
|
||||||
|
}, {
|
||||||
anchorRight: false,
|
anchorRight: false,
|
||||||
|
formattedLabel: format('A!'),
|
||||||
|
id: 'A',
|
||||||
|
options: [],
|
||||||
|
}, {
|
||||||
|
anchorRight: false,
|
||||||
|
formattedLabel: format('B!'),
|
||||||
|
id: 'B',
|
||||||
|
options: [],
|
||||||
|
}, {
|
||||||
|
anchorRight: false,
|
||||||
|
formattedLabel: null,
|
||||||
|
id: ']',
|
||||||
options: [],
|
options: [],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
meta: {title: []},
|
||||||
stages: [
|
stages: [
|
||||||
{type: 'agent begin', agentIDs: ['A', 'B'], mode: 'box'},
|
{agentIDs: ['A', 'B'], mode: 'box', type: 'agent begin'},
|
||||||
GENERATED.connect(['A', 'B']),
|
GENERATED.connect(['A', 'B']),
|
||||||
{type: 'agent end', agentIDs: ['A', 'B'], mode: 'none'},
|
{agentIDs: ['A', 'B'], mode: 'none', type: 'agent end'},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -158,49 +156,49 @@ describe('Sequence Renderer', () => {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
renderer.render({
|
renderer.render({
|
||||||
meta: {title: []},
|
|
||||||
agents: [
|
agents: [
|
||||||
{
|
{
|
||||||
id: '[',
|
|
||||||
formattedLabel: null,
|
|
||||||
anchorRight: true,
|
anchorRight: true,
|
||||||
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,
|
formattedLabel: null,
|
||||||
|
id: '[',
|
||||||
|
options: [],
|
||||||
|
}, {
|
||||||
anchorRight: false,
|
anchorRight: false,
|
||||||
|
formattedLabel: format('A!'),
|
||||||
|
id: 'A',
|
||||||
|
options: [],
|
||||||
|
}, {
|
||||||
|
anchorRight: false,
|
||||||
|
formattedLabel: format('B!'),
|
||||||
|
id: 'B',
|
||||||
|
options: [],
|
||||||
|
}, {
|
||||||
|
anchorRight: false,
|
||||||
|
formattedLabel: format('C!'),
|
||||||
|
id: 'C',
|
||||||
|
options: [],
|
||||||
|
}, {
|
||||||
|
anchorRight: false,
|
||||||
|
formattedLabel: null,
|
||||||
|
id: ']',
|
||||||
options: [],
|
options: [],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
meta: {title: []},
|
||||||
stages: [
|
stages: [
|
||||||
{
|
{
|
||||||
type: 'agent begin',
|
|
||||||
agentIDs: ['A', 'B', 'C'],
|
agentIDs: ['A', 'B', 'C'],
|
||||||
mode: 'box',
|
mode: 'box',
|
||||||
|
type: 'agent begin',
|
||||||
},
|
},
|
||||||
GENERATED.connect(['[', 'A']),
|
GENERATED.connect(['[', 'A']),
|
||||||
GENERATED.connect(['A', 'B']),
|
GENERATED.connect(['A', 'B']),
|
||||||
GENERATED.connect(['B', 'C']),
|
GENERATED.connect(['B', 'C']),
|
||||||
GENERATED.connect(['C', ']']),
|
GENERATED.connect(['C', ']']),
|
||||||
{
|
{
|
||||||
type: 'agent end',
|
|
||||||
agentIDs: ['A', 'B', 'C'],
|
agentIDs: ['A', 'B', 'C'],
|
||||||
mode: 'none',
|
mode: 'none',
|
||||||
|
type: 'agent end',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
@ -228,50 +226,50 @@ describe('Sequence Renderer', () => {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
renderer.render({
|
renderer.render({
|
||||||
meta: {title: []},
|
|
||||||
agents: [
|
agents: [
|
||||||
{
|
{
|
||||||
id: '[',
|
|
||||||
formattedLabel: null,
|
|
||||||
anchorRight: true,
|
anchorRight: true,
|
||||||
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: 'D',
|
|
||||||
formattedLabel: format('D!'),
|
|
||||||
anchorRight: false,
|
|
||||||
options: [],
|
|
||||||
}, {
|
|
||||||
id: ']',
|
|
||||||
formattedLabel: null,
|
formattedLabel: null,
|
||||||
|
id: '[',
|
||||||
|
options: [],
|
||||||
|
}, {
|
||||||
anchorRight: false,
|
anchorRight: false,
|
||||||
|
formattedLabel: format('A!'),
|
||||||
|
id: 'A',
|
||||||
|
options: [],
|
||||||
|
}, {
|
||||||
|
anchorRight: false,
|
||||||
|
formattedLabel: format('B!'),
|
||||||
|
id: 'B',
|
||||||
|
options: [],
|
||||||
|
}, {
|
||||||
|
anchorRight: false,
|
||||||
|
formattedLabel: format('C!'),
|
||||||
|
id: 'C',
|
||||||
|
options: [],
|
||||||
|
}, {
|
||||||
|
anchorRight: false,
|
||||||
|
formattedLabel: format('D!'),
|
||||||
|
id: 'D',
|
||||||
|
options: [],
|
||||||
|
}, {
|
||||||
|
anchorRight: false,
|
||||||
|
formattedLabel: null,
|
||||||
|
id: ']',
|
||||||
options: [],
|
options: [],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
meta: {title: []},
|
||||||
stages: [
|
stages: [
|
||||||
{type: 'agent begin', agentIDs: ['A', 'B'], mode: 'box'},
|
{agentIDs: ['A', 'B'], mode: 'box', type: 'agent begin'},
|
||||||
GENERATED.connect(['A', 'B'], format('short')),
|
GENERATED.connect(['A', 'B'], format('short')),
|
||||||
{type: 'agent end', agentIDs: ['B'], mode: 'cross'},
|
{agentIDs: ['B'], mode: 'cross', type: 'agent end'},
|
||||||
{type: 'agent begin', agentIDs: ['C'], mode: 'box'},
|
{agentIDs: ['C'], mode: 'box', type: 'agent begin'},
|
||||||
GENERATED.connect(['A', 'C'], format('long description')),
|
GENERATED.connect(['A', 'C'], format('long description')),
|
||||||
{type: 'agent end', agentIDs: ['C'], mode: 'cross'},
|
{agentIDs: ['C'], mode: 'cross', type: 'agent end'},
|
||||||
{type: 'agent begin', agentIDs: ['D'], mode: 'box'},
|
{agentIDs: ['D'], mode: 'box', type: 'agent begin'},
|
||||||
GENERATED.connect(['A', 'D'], format('short again')),
|
GENERATED.connect(['A', 'D'], format('short again')),
|
||||||
{type: 'agent end', agentIDs: ['A', 'D'], mode: 'cross'},
|
{agentIDs: ['A', 'D'], mode: 'cross', type: 'agent end'},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
/* eslint-disable sort-keys */ // Maybe later
|
|
||||||
|
|
||||||
import BaseComponent, {register} from './BaseComponent.mjs';
|
import BaseComponent, {register} from './BaseComponent.mjs';
|
||||||
import {mergeSets} from '../../../core/ArrayUtilities.mjs';
|
import {mergeSets} from '../../../core/ArrayUtilities.mjs';
|
||||||
|
|
||||||
|
@ -36,11 +34,11 @@ class Arrowhead {
|
||||||
const config = this.getConfig(theme);
|
const config = this.getConfig(theme);
|
||||||
const short = this.short(theme);
|
const short = this.short(theme);
|
||||||
layer.add(config.render(config.attrs, {
|
layer.add(config.render(config.attrs, {
|
||||||
|
dir,
|
||||||
|
height: config.height,
|
||||||
|
width: config.width,
|
||||||
x: pt.x + short * dir.dx,
|
x: pt.x + short * dir.dx,
|
||||||
y: pt.y + short * dir.dy,
|
y: pt.y + short * dir.dy,
|
||||||
width: config.width,
|
|
||||||
height: config.height,
|
|
||||||
dir,
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,9 +72,9 @@ class Arrowcross {
|
||||||
render(layer, theme, pt, dir) {
|
render(layer, theme, pt, dir) {
|
||||||
const config = this.getConfig(theme);
|
const config = this.getConfig(theme);
|
||||||
layer.add(config.render({
|
layer.add(config.render({
|
||||||
|
radius: config.radius,
|
||||||
x: pt.x + config.short * dir.dx,
|
x: pt.x + config.short * dir.dx,
|
||||||
y: pt.y + config.short * dir.dy,
|
y: pt.y + config.short * dir.dy,
|
||||||
radius: config.radius,
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,10 +94,10 @@ class Arrowcross {
|
||||||
|
|
||||||
const ARROWHEADS = [
|
const ARROWHEADS = [
|
||||||
{
|
{
|
||||||
render: () => null,
|
|
||||||
width: () => 0,
|
|
||||||
height: () => 0,
|
height: () => 0,
|
||||||
lineGap: () => 0,
|
lineGap: () => 0,
|
||||||
|
render: () => null,
|
||||||
|
width: () => 0,
|
||||||
},
|
},
|
||||||
new Arrowhead('single'),
|
new Arrowhead('single'),
|
||||||
new Arrowhead('double'),
|
new Arrowhead('double'),
|
||||||
|
@ -184,12 +182,12 @@ export class Connect extends BaseComponent {
|
||||||
const dx1 = lArrow.lineGap(env.theme, line.attrs);
|
const dx1 = lArrow.lineGap(env.theme, line.attrs);
|
||||||
const dx2 = rArrow.lineGap(env.theme, line.attrs);
|
const dx2 = rArrow.lineGap(env.theme, line.attrs);
|
||||||
const rendered = line.renderRev(line.attrs, {
|
const rendered = line.renderRev(line.attrs, {
|
||||||
x1: x1 + dx1,
|
|
||||||
y1,
|
|
||||||
x2: x2 + dx2,
|
|
||||||
y2,
|
|
||||||
xR,
|
|
||||||
rad: config.loopbackRadius,
|
rad: config.loopbackRadius,
|
||||||
|
x1: x1 + dx1,
|
||||||
|
x2: x2 + dx2,
|
||||||
|
xR,
|
||||||
|
y1,
|
||||||
|
y2,
|
||||||
});
|
});
|
||||||
clickable.add(rendered.shape);
|
clickable.add(rendered.shape);
|
||||||
|
|
||||||
|
@ -225,9 +223,9 @@ export class Connect extends BaseComponent {
|
||||||
);
|
);
|
||||||
|
|
||||||
const renderedText = env.svg.boxedText({
|
const renderedText = env.svg.boxedText({
|
||||||
padding: config.mask.padding,
|
|
||||||
boxAttrs: {'fill': '#000000'},
|
boxAttrs: {'fill': '#000000'},
|
||||||
labelAttrs: config.label.loopbackAttrs,
|
labelAttrs: config.label.loopbackAttrs,
|
||||||
|
padding: config.mask.padding,
|
||||||
}, label, {
|
}, label, {
|
||||||
x: xL - config.mask.padding.left,
|
x: xL - config.mask.padding.left,
|
||||||
y: yBegin - height + config.label.margin.top,
|
y: yBegin - height + config.label.margin.top,
|
||||||
|
@ -251,20 +249,20 @@ export class Connect extends BaseComponent {
|
||||||
env.lineMaskLayer.add(renderedText.box);
|
env.lineMaskLayer.add(renderedText.box);
|
||||||
const clickable = env.makeRegion().add(
|
const clickable = env.makeRegion().add(
|
||||||
env.svg.box(OUTLINE_ATTRS, {
|
env.svg.box(OUTLINE_ATTRS, {
|
||||||
|
'height': raise + env.primaryY - yBegin + arrowDip,
|
||||||
|
'width': xR + config.loopbackRadius - from.x,
|
||||||
'x': from.x,
|
'x': from.x,
|
||||||
'y': yBegin - raise,
|
'y': yBegin - raise,
|
||||||
'width': xR + config.loopbackRadius - from.x,
|
|
||||||
'height': raise + env.primaryY - yBegin + arrowDip,
|
|
||||||
}),
|
}),
|
||||||
renderedText.label
|
renderedText.label
|
||||||
);
|
);
|
||||||
|
|
||||||
this.renderRevArrowLine({
|
this.renderRevArrowLine({
|
||||||
x1: from.x + from.currentMaxRad,
|
x1: from.x + from.currentMaxRad,
|
||||||
y1: yBegin,
|
|
||||||
x2: to.x + to.currentMaxRad,
|
x2: to.x + to.currentMaxRad,
|
||||||
y2: env.primaryY,
|
|
||||||
xR,
|
xR,
|
||||||
|
y1: yBegin,
|
||||||
|
y2: env.primaryY,
|
||||||
}, options, env, clickable);
|
}, options, env, clickable);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -291,8 +289,8 @@ export class Connect extends BaseComponent {
|
||||||
|
|
||||||
const rendered = line.renderFlat(line.attrs, {
|
const rendered = line.renderFlat(line.attrs, {
|
||||||
x1: x1 + d1 * dx,
|
x1: x1 + d1 * dx,
|
||||||
y1: y1 + d1 * dy,
|
|
||||||
x2: x2 - d2 * dx,
|
x2: x2 - d2 * dx,
|
||||||
|
y1: y1 + d1 * dy,
|
||||||
y2: y2 - d2 * dy,
|
y2: y2 - d2 * dy,
|
||||||
});
|
});
|
||||||
clickable.add(rendered.shape);
|
clickable.add(rendered.shape);
|
||||||
|
@ -304,9 +302,9 @@ export class Connect extends BaseComponent {
|
||||||
rArrow.render(clickable, env.theme, p2, {dx: -dx, dy: -dy});
|
rArrow.render(clickable, env.theme, p2, {dx: -dx, dy: -dy});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
lArrow,
|
||||||
p1,
|
p1,
|
||||||
p2,
|
p2,
|
||||||
lArrow,
|
|
||||||
rArrow,
|
rArrow,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -316,16 +314,16 @@ export class Connect extends BaseComponent {
|
||||||
|
|
||||||
if(from.isVirtualSource) {
|
if(from.isVirtualSource) {
|
||||||
clickable.add(config.render({
|
clickable.add(config.render({
|
||||||
|
radius: config.radius,
|
||||||
x: rendered.p1.x - config.radius,
|
x: rendered.p1.x - config.radius,
|
||||||
y: rendered.p1.y,
|
y: rendered.p1.y,
|
||||||
radius: config.radius,
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
if(to.isVirtualSource) {
|
if(to.isVirtualSource) {
|
||||||
clickable.add(config.render({
|
clickable.add(config.render({
|
||||||
|
radius: config.radius,
|
||||||
x: rendered.p2.x + config.radius,
|
x: rendered.p2.x + config.radius,
|
||||||
y: rendered.p2.y,
|
y: rendered.p2.y,
|
||||||
radius: config.radius,
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -352,9 +350,9 @@ export class Connect extends BaseComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
const text = env.svg.boxedText({
|
const text = env.svg.boxedText({
|
||||||
padding: config.mask.padding,
|
|
||||||
boxAttrs,
|
boxAttrs,
|
||||||
labelAttrs: config.label.attrs,
|
labelAttrs: config.label.attrs,
|
||||||
|
padding: config.mask.padding,
|
||||||
}, label, {
|
}, label, {
|
||||||
x: midX,
|
x: midX,
|
||||||
y: midY + config.label.margin.top - height,
|
y: midY + config.label.margin.top - height,
|
||||||
|
@ -382,8 +380,8 @@ export class Connect extends BaseComponent {
|
||||||
|
|
||||||
const rendered = this.renderArrowLine({
|
const rendered = this.renderArrowLine({
|
||||||
x1,
|
x1,
|
||||||
y1: yBegin,
|
|
||||||
x2,
|
x2,
|
||||||
|
y1: yBegin,
|
||||||
y2: env.primaryY,
|
y2: env.primaryY,
|
||||||
}, options, env, clickable);
|
}, options, env, clickable);
|
||||||
|
|
||||||
|
@ -394,7 +392,7 @@ export class Connect extends BaseComponent {
|
||||||
|
|
||||||
const lift = Math.max(height, arrowSpread);
|
const lift = Math.max(height, arrowSpread);
|
||||||
|
|
||||||
this.renderVirtualSources({from, to, rendered}, env, clickable);
|
this.renderVirtualSources({from, rendered, to}, env, clickable);
|
||||||
|
|
||||||
clickable.add(env.svg.el('path')
|
clickable.add(env.svg.el('path')
|
||||||
.attrs(OUTLINE_ATTRS)
|
.attrs(OUTLINE_ATTRS)
|
||||||
|
@ -407,12 +405,12 @@ export class Connect extends BaseComponent {
|
||||||
)));
|
)));
|
||||||
|
|
||||||
this.renderSimpleLabel(label, {
|
this.renderSimpleLabel(label, {
|
||||||
|
height,
|
||||||
layer: clickable,
|
layer: clickable,
|
||||||
x1,
|
x1,
|
||||||
y1: yBegin,
|
|
||||||
x2,
|
x2,
|
||||||
|
y1: yBegin,
|
||||||
y2: env.primaryY,
|
y2: env.primaryY,
|
||||||
height,
|
|
||||||
}, env);
|
}, env);
|
||||||
|
|
||||||
return env.primaryY + Math.max(
|
return env.primaryY + Math.max(
|
||||||
|
@ -482,8 +480,8 @@ export class ConnectDelayBegin extends Connect {
|
||||||
render(stage, env) {
|
render(stage, env) {
|
||||||
const dc = env.state.delayedConnections;
|
const dc = env.state.delayedConnections;
|
||||||
dc.set(stage.tag, {
|
dc.set(stage.tag, {
|
||||||
stage,
|
|
||||||
from: Object.assign({}, env.agentInfos.get(stage.agentIDs[0])),
|
from: Object.assign({}, env.agentInfos.get(stage.agentIDs[0])),
|
||||||
|
stage,
|
||||||
y: env.primaryY,
|
y: env.primaryY,
|
||||||
});
|
});
|
||||||
return env.primaryY + env.theme.actionMargin;
|
return env.primaryY + env.theme.actionMargin;
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
/* eslint-disable complexity */ // Temporary ignore while switching linter
|
|
||||||
/* eslint-disable no-param-reassign */ // Also temporary
|
|
||||||
|
|
||||||
import BaseComponent, {register} from './BaseComponent.mjs';
|
import BaseComponent, {register} from './BaseComponent.mjs';
|
||||||
|
|
||||||
const OUTLINE_ATTRS = {
|
const OUTLINE_ATTRS = {
|
||||||
|
@ -26,6 +23,35 @@ function findExtremes(agentInfos, agentIDs) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function findEdges(fullW, {
|
||||||
|
x0 = null,
|
||||||
|
x1 = null,
|
||||||
|
xMid = null,
|
||||||
|
}) {
|
||||||
|
let xL = x0;
|
||||||
|
let xR = x1;
|
||||||
|
if(xL === null && xMid !== null) {
|
||||||
|
xL = xMid - fullW / 2;
|
||||||
|
}
|
||||||
|
if(xR === null && xL !== null) {
|
||||||
|
xR = xL + fullW;
|
||||||
|
} else if(xL === null) {
|
||||||
|
xL = xR - fullW;
|
||||||
|
}
|
||||||
|
return {xL, xR};
|
||||||
|
}
|
||||||
|
|
||||||
|
function textAnchorX(anchor, {xL, xR}, padding) {
|
||||||
|
switch(anchor) {
|
||||||
|
case 'middle':
|
||||||
|
return (xL + padding.left + xR - padding.right) / 2;
|
||||||
|
case 'end':
|
||||||
|
return xR - padding.right;
|
||||||
|
default:
|
||||||
|
return xL + padding.left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class NoteComponent extends BaseComponent {
|
class NoteComponent extends BaseComponent {
|
||||||
prepareMeasurements({mode, label}, env) {
|
prepareMeasurements({mode, label}, env) {
|
||||||
const config = env.theme.getNote(mode);
|
const config = env.theme.getNote(mode);
|
||||||
|
@ -37,67 +63,36 @@ class NoteComponent extends BaseComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
renderNote({
|
renderNote({
|
||||||
xMid = null,
|
|
||||||
x0 = null,
|
|
||||||
x1 = null,
|
|
||||||
mode,
|
|
||||||
label,
|
label,
|
||||||
|
mode,
|
||||||
|
position,
|
||||||
}, env) {
|
}, env) {
|
||||||
const config = env.theme.getNote(mode);
|
const config = env.theme.getNote(mode);
|
||||||
|
const {padding} = config;
|
||||||
|
|
||||||
const y = env.topY + config.margin.top + config.padding.top;
|
const y = env.topY + config.margin.top + padding.top;
|
||||||
const labelNode = env.svg.formattedText(config.labelAttrs, label);
|
const labelNode = env.svg.formattedText(config.labelAttrs, label);
|
||||||
const size = env.textSizer.measure(labelNode);
|
const size = env.textSizer.measure(labelNode);
|
||||||
|
|
||||||
const fullW = (
|
const fullW = (size.width + padding.left + padding.right);
|
||||||
size.width +
|
const fullH = (size.height + padding.top + padding.bottom);
|
||||||
config.padding.left +
|
const edges = findEdges(fullW, position);
|
||||||
config.padding.right
|
|
||||||
);
|
|
||||||
const fullH = (
|
|
||||||
config.padding.top +
|
|
||||||
size.height +
|
|
||||||
config.padding.bottom
|
|
||||||
);
|
|
||||||
if(x0 === null && xMid !== null) {
|
|
||||||
x0 = xMid - fullW / 2;
|
|
||||||
}
|
|
||||||
if(x1 === null && x0 !== null) {
|
|
||||||
x1 = x0 + fullW;
|
|
||||||
} else if(x0 === null) {
|
|
||||||
x0 = x1 - fullW;
|
|
||||||
}
|
|
||||||
switch(config.labelAttrs['text-anchor']) {
|
|
||||||
case 'middle':
|
|
||||||
labelNode.set({
|
labelNode.set({
|
||||||
x: (
|
x: textAnchorX(config.labelAttrs['text-anchor'], edges, padding),
|
||||||
x0 + config.padding.left +
|
|
||||||
x1 - config.padding.right
|
|
||||||
) / 2,
|
|
||||||
y,
|
y,
|
||||||
});
|
});
|
||||||
break;
|
|
||||||
case 'end':
|
const boundingBox = {
|
||||||
labelNode.set({x: x1 - config.padding.right, y});
|
height: fullH,
|
||||||
break;
|
width: edges.xR - edges.xL,
|
||||||
default:
|
x: edges.xL,
|
||||||
labelNode.set({x: x0 + config.padding.left, y});
|
y: env.topY + config.margin.top,
|
||||||
break;
|
};
|
||||||
}
|
|
||||||
|
|
||||||
env.makeRegion().add(
|
env.makeRegion().add(
|
||||||
config.boxRenderer({
|
config.boxRenderer(boundingBox),
|
||||||
height: fullH,
|
env.svg.box(OUTLINE_ATTRS, boundingBox),
|
||||||
width: x1 - x0,
|
|
||||||
x: x0,
|
|
||||||
y: env.topY + config.margin.top,
|
|
||||||
}),
|
|
||||||
env.svg.box(OUTLINE_ATTRS, {
|
|
||||||
height: fullH,
|
|
||||||
width: x1 - x0,
|
|
||||||
x: x0,
|
|
||||||
y: env.topY + config.margin.top,
|
|
||||||
}),
|
|
||||||
labelNode
|
labelNode
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -150,14 +145,16 @@ export class NoteOver extends NoteComponent {
|
||||||
return this.renderNote({
|
return this.renderNote({
|
||||||
label,
|
label,
|
||||||
mode,
|
mode,
|
||||||
xMid,
|
position: {xMid},
|
||||||
}, env);
|
}, env);
|
||||||
} else {
|
} else {
|
||||||
return this.renderNote({
|
return this.renderNote({
|
||||||
label,
|
label,
|
||||||
mode,
|
mode,
|
||||||
|
position: {
|
||||||
x0: infoL.x - infoL.currentMaxRad - config.overlap.left,
|
x0: infoL.x - infoL.currentMaxRad - config.overlap.left,
|
||||||
x1: infoR.x + infoR.currentMaxRad + config.overlap.right,
|
x1: infoR.x + infoR.currentMaxRad + config.overlap.right,
|
||||||
|
},
|
||||||
}, env);
|
}, env);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -204,7 +201,7 @@ export class NoteSide extends NoteComponent {
|
||||||
return this.renderNote({
|
return this.renderNote({
|
||||||
label,
|
label,
|
||||||
mode,
|
mode,
|
||||||
x0,
|
position: {x0},
|
||||||
}, env);
|
}, env);
|
||||||
} else {
|
} else {
|
||||||
const info = env.agentInfos.get(left);
|
const info = env.agentInfos.get(left);
|
||||||
|
@ -212,7 +209,7 @@ export class NoteSide extends NoteComponent {
|
||||||
return this.renderNote({
|
return this.renderNote({
|
||||||
label,
|
label,
|
||||||
mode,
|
mode,
|
||||||
x1,
|
position: {x1},
|
||||||
}, env);
|
}, env);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -251,7 +248,7 @@ export class NoteBetween extends NoteComponent {
|
||||||
return this.renderNote({
|
return this.renderNote({
|
||||||
label,
|
label,
|
||||||
mode,
|
mode,
|
||||||
xMid,
|
position: {xMid},
|
||||||
}, env);
|
}, env);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
/* eslint-disable sort-keys */ // Maybe later
|
|
||||||
|
|
||||||
function optionsAttributes(attributes, options) {
|
function optionsAttributes(attributes, options) {
|
||||||
const attrs = Object.assign({}, attributes['']);
|
const attrs = Object.assign({}, attributes['']);
|
||||||
options.forEach((opt) => {
|
options.forEach((opt) => {
|
||||||
|
@ -63,14 +61,14 @@ export default class BaseTheme {
|
||||||
return optionsAttributes(attributes, options);
|
return optionsAttributes(attributes, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderAgentLine({x, y0, y1, width, className, options}) {
|
renderAgentLine({className, options, width, x, y0, y1}) {
|
||||||
const attrs = this.optionsAttributes(this.agentLineAttrs, options);
|
const attrs = this.optionsAttributes(this.agentLineAttrs, options);
|
||||||
if(width > 0) {
|
if(width > 0) {
|
||||||
return this.svg.box(attrs, {
|
return this.svg.box(attrs, {
|
||||||
|
height: y1 - y0,
|
||||||
|
width,
|
||||||
x: x - width / 2,
|
x: x - width / 2,
|
||||||
y: y0,
|
y: y0,
|
||||||
width,
|
|
||||||
height: y1 - y0,
|
|
||||||
}).addClass(className);
|
}).addClass(className);
|
||||||
} else {
|
} else {
|
||||||
return this.svg.line(attrs, {
|
return this.svg.line(attrs, {
|
||||||
|
@ -84,7 +82,7 @@ export default class BaseTheme {
|
||||||
|
|
||||||
// INTERNAL HELPERS
|
// INTERNAL HELPERS
|
||||||
|
|
||||||
renderArrowHead(attrs, {x, y, width, height, dir}) {
|
renderArrowHead(attrs, {dir, height, width, x, y}) {
|
||||||
const wx = width * dir.dx;
|
const wx = width * dir.dx;
|
||||||
const wy = width * dir.dy;
|
const wy = width * dir.dy;
|
||||||
const hy = height * 0.5 * dir.dx;
|
const hy = height * 0.5 * dir.dx;
|
||||||
|
@ -98,7 +96,7 @@ export default class BaseTheme {
|
||||||
.attrs(attrs);
|
.attrs(attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderTag(attrs, {x, y, width, height}) {
|
renderTag(attrs, {height, width, x, y}) {
|
||||||
const {rx, ry} = attrs;
|
const {rx, ry} = attrs;
|
||||||
const x2 = x + width;
|
const x2 = x + width;
|
||||||
const y2 = y + height;
|
const y2 = y + height;
|
||||||
|
@ -148,12 +146,12 @@ export default class BaseTheme {
|
||||||
|
|
||||||
renderRef(options, position) {
|
renderRef(options, position) {
|
||||||
return {
|
return {
|
||||||
shape: this.svg.box(options, position).attrs({'fill': 'none'}),
|
fill: this.svg.box(options, position).attrs({'stroke': 'none'}),
|
||||||
mask: this.svg.box(options, position).attrs({
|
mask: this.svg.box(options, position).attrs({
|
||||||
'fill': '#000000',
|
'fill': '#000000',
|
||||||
'stroke': 'none',
|
'stroke': 'none',
|
||||||
}),
|
}),
|
||||||
fill: this.svg.box(options, position).attrs({'stroke': 'none'}),
|
shape: this.svg.box(options, position).attrs({'fill': 'none'}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,6 +161,8 @@ export default class BaseTheme {
|
||||||
{x1, y1, x2, y2}
|
{x1, y1, x2, y2}
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
|
p1: {x: x1, y: y1},
|
||||||
|
p2: {x: x2, y: y2},
|
||||||
shape: this.svg.el('path')
|
shape: this.svg.el('path')
|
||||||
.attr('d', this.svg.patternedLine(pattern)
|
.attr('d', this.svg.patternedLine(pattern)
|
||||||
.move(x1, y1)
|
.move(x1, y1)
|
||||||
|
@ -170,15 +170,13 @@ export default class BaseTheme {
|
||||||
.cap()
|
.cap()
|
||||||
.asPath())
|
.asPath())
|
||||||
.attrs(attrs),
|
.attrs(attrs),
|
||||||
p1: {x: x1, y: y1},
|
|
||||||
p2: {x: x2, y: y2},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
renderRevConnect(
|
renderRevConnect(
|
||||||
pattern,
|
pattern,
|
||||||
attrs,
|
attrs,
|
||||||
{x1, y1, x2, y2, xR, rad}
|
{rad, x1, x2, xR, y1, y2}
|
||||||
) {
|
) {
|
||||||
const maxRad = (y2 - y1) / 2;
|
const maxRad = (y2 - y1) / 2;
|
||||||
const line = this.svg.patternedLine(pattern)
|
const line = this.svg.patternedLine(pattern)
|
||||||
|
@ -193,20 +191,20 @@ export default class BaseTheme {
|
||||||
line.arc(xR, (y1 + y2) / 2, Math.PI);
|
line.arc(xR, (y1 + y2) / 2, Math.PI);
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
p1: {x: x1, y: y1},
|
||||||
|
p2: {x: x2, y: y2},
|
||||||
shape: this.svg.el('path')
|
shape: this.svg.el('path')
|
||||||
.attr('d', line
|
.attr('d', line
|
||||||
.line(x2, y2)
|
.line(x2, y2)
|
||||||
.cap()
|
.cap()
|
||||||
.asPath())
|
.asPath())
|
||||||
.attrs(attrs),
|
.attrs(attrs),
|
||||||
p1: {x: x1, y: y1},
|
|
||||||
p2: {x: x2, y: y2},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
renderLineDivider(
|
renderLineDivider(
|
||||||
{lineAttrs},
|
{lineAttrs},
|
||||||
{x, y, labelWidth, width, height}
|
{height, labelWidth, width, x, y}
|
||||||
) {
|
) {
|
||||||
let shape = null;
|
let shape = null;
|
||||||
const yPos = y + height / 2;
|
const yPos = y + height / 2;
|
||||||
|
@ -238,25 +236,25 @@ export default class BaseTheme {
|
||||||
|
|
||||||
renderDelayDivider(
|
renderDelayDivider(
|
||||||
{dotSize, gapSize},
|
{dotSize, gapSize},
|
||||||
{x, y, width, height}
|
{height, width, x, y}
|
||||||
) {
|
) {
|
||||||
const mask = this.svg.el('g');
|
const mask = this.svg.el('g');
|
||||||
for(let i = 0; i + gapSize <= height; i += dotSize + gapSize) {
|
for(let i = 0; i + gapSize <= height; i += dotSize + gapSize) {
|
||||||
mask.add(this.svg.box({
|
mask.add(this.svg.box({
|
||||||
'fill': '#000000',
|
'fill': '#000000',
|
||||||
}, {
|
}, {
|
||||||
|
height: gapSize,
|
||||||
|
width,
|
||||||
x,
|
x,
|
||||||
y: y + i,
|
y: y + i,
|
||||||
width,
|
|
||||||
height: gapSize,
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
return {mask};
|
return {mask};
|
||||||
}
|
}
|
||||||
|
|
||||||
renderTearDivider(
|
renderTearDivider(
|
||||||
{fadeBegin, fadeSize, pattern, zigWidth, zigHeight, lineAttrs},
|
{fadeBegin, fadeSize, lineAttrs, pattern, zigHeight, zigWidth},
|
||||||
{x, y, labelWidth, labelHeight, width, height, env}
|
{env, height, labelHeight, labelWidth, width, x, y}
|
||||||
) {
|
) {
|
||||||
const maskGradID = env.addDef('tear-grad', () => {
|
const maskGradID = env.addDef('tear-grad', () => {
|
||||||
const px = 100 / width;
|
const px = 100 / width;
|
||||||
|
@ -285,24 +283,24 @@ export default class BaseTheme {
|
||||||
this.svg.box({
|
this.svg.box({
|
||||||
'fill': 'url(#' + maskGradID + ')',
|
'fill': 'url(#' + maskGradID + ')',
|
||||||
}, {
|
}, {
|
||||||
|
height: height + 10,
|
||||||
|
width,
|
||||||
x,
|
x,
|
||||||
y: y - 5,
|
y: y - 5,
|
||||||
width,
|
|
||||||
height: height + 10,
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
const shapeMaskID = env.addDef(shapeMask);
|
const shapeMaskID = env.addDef(shapeMask);
|
||||||
|
|
||||||
if(labelWidth > 0) {
|
if(labelWidth > 0) {
|
||||||
shapeMask.add(this.svg.box({
|
shapeMask.add(this.svg.box({
|
||||||
|
'fill': '#000000',
|
||||||
'rx': 2,
|
'rx': 2,
|
||||||
'ry': 2,
|
'ry': 2,
|
||||||
'fill': '#000000',
|
|
||||||
}, {
|
}, {
|
||||||
|
'height': labelHeight + 2,
|
||||||
|
'width': labelWidth,
|
||||||
'x': x + (width - labelWidth) / 2,
|
'x': x + (width - labelWidth) / 2,
|
||||||
'y': y + (height - labelHeight) / 2 - 1,
|
'y': y + (height - labelHeight) / 2 - 1,
|
||||||
'width': labelWidth,
|
|
||||||
'height': labelHeight + 2,
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -345,6 +343,6 @@ export default class BaseTheme {
|
||||||
'fill': '#000000',
|
'fill': '#000000',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return {shape, mask};
|
return {mask, shape};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
/* eslint-disable complexity */ // Temporary ignore while switching linter
|
|
||||||
|
|
||||||
function makeCanvas(width, height) {
|
function makeCanvas(width, height) {
|
||||||
window.devicePixelRatio = 1;
|
window.devicePixelRatio = 1;
|
||||||
const canvas = document.createElement('canvas');
|
const canvas = document.createElement('canvas');
|
||||||
|
@ -36,6 +34,20 @@ function proportionalSize(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resize_ranges(l, h) {
|
||||||
|
/* eslint-disable no-bitwise */ // Faster than Math.floor
|
||||||
|
const li = (l | 0);
|
||||||
|
const hi = (h | 0);
|
||||||
|
/* eslint-enable no-bitwise */
|
||||||
|
const lm = (hi === li) ? (h - l) : (li + 1 - l);
|
||||||
|
const hm = h - hi;
|
||||||
|
if(hm < 0.001) {
|
||||||
|
return {hi: hi - 1, hm: 1, li, lm};
|
||||||
|
} else {
|
||||||
|
return {hi, hm, li, lm};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default class ImageRegion {
|
export default class ImageRegion {
|
||||||
constructor(width, height, values, {
|
constructor(width, height, values, {
|
||||||
origin = 0,
|
origin = 0,
|
||||||
|
@ -296,40 +308,20 @@ export default class ImageRegion {
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
resize(size) {
|
_resize(width, height) {
|
||||||
const {width, height} = this.getProportionalSize(size);
|
|
||||||
if(width === this.width && height === this.height) {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
const {dim} = this;
|
const {dim} = this;
|
||||||
const values = new Float32Array(width * height * dim);
|
|
||||||
|
|
||||||
const mx = this.width / width;
|
const mx = this.width / width;
|
||||||
const my = this.height / height;
|
const my = this.height / height;
|
||||||
|
const values = new Float32Array(width * height * dim);
|
||||||
const norm = 1 / (mx * my);
|
const norm = 1 / (mx * my);
|
||||||
|
|
||||||
function ranges(l, h) {
|
|
||||||
/* eslint-disable no-bitwise */ // Faster than Math.floor
|
|
||||||
const li = (l | 0);
|
|
||||||
const hi = (h | 0);
|
|
||||||
/* eslint-enable no-bitwise */
|
|
||||||
const lm = (hi === li) ? (h - l) : (li + 1 - l);
|
|
||||||
const hm = h - hi;
|
|
||||||
if(hm < 0.001) {
|
|
||||||
return {hi: hi - 1, hm: 1, li, lm};
|
|
||||||
} else {
|
|
||||||
return {hi, hm, li, lm};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const xrs = [];
|
const xrs = [];
|
||||||
for(let x = 0; x < width; ++ x) {
|
for(let x = 0; x < width; ++ x) {
|
||||||
xrs[x] = ranges(x * mx, (x + 1) * mx);
|
xrs[x] = resize_ranges(x * mx, (x + 1) * mx);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(let y = 0; y < height; ++ y) {
|
for(let y = 0; y < height; ++ y) {
|
||||||
const yr = ranges(y * my, (y + 1) * my);
|
const yr = resize_ranges(y * my, (y + 1) * my);
|
||||||
for(let x = 0; x < width; ++ x) {
|
for(let x = 0; x < width; ++ x) {
|
||||||
const xr = xrs[x];
|
const xr = xrs[x];
|
||||||
const p = (y * width + x) * dim;
|
const p = (y * width + x) * dim;
|
||||||
|
@ -342,6 +334,15 @@ export default class ImageRegion {
|
||||||
return new ImageRegion(width, height, values, {dim});
|
return new ImageRegion(width, height, values, {dim});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resize(size) {
|
||||||
|
const {width, height} = this.getProportionalSize(size);
|
||||||
|
if(width === this.width && height === this.height) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._resize(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
getSuggestedChannels({blue = null, green = null, red = null} = {}) {
|
getSuggestedChannels({blue = null, green = null, red = null} = {}) {
|
||||||
return {
|
return {
|
||||||
blue: (blue === null) ? (this.dim - 1) : blue,
|
blue: (blue === null) ? (this.dim - 1) : blue,
|
||||||
|
|
|
@ -83,7 +83,7 @@ module.exports = {
|
||||||
'lines-between-class-members': ['error'],
|
'lines-between-class-members': ['error'],
|
||||||
'max-depth': ['error', 4],
|
'max-depth': ['error', 4],
|
||||||
'max-len': ['error', {'ignoreUrls': true}],
|
'max-len': ['error', {'ignoreUrls': true}],
|
||||||
'max-lines': ['error', 600],
|
'max-lines': ['error', 800],
|
||||||
'max-nested-callbacks': ['error', 4], // Includes jasmine blocks
|
'max-nested-callbacks': ['error', 4], // Includes jasmine blocks
|
||||||
'max-params': ['error', 4],
|
'max-params': ['error', 4],
|
||||||
'max-statements': ['error', 20],
|
'max-statements': ['error', 20],
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
/* eslint-disable max-lines */
|
|
||||||
|
|
||||||
import DOMWrapper from '../../scripts/core/DOMWrapper.mjs';
|
import DOMWrapper from '../../scripts/core/DOMWrapper.mjs';
|
||||||
|
|
||||||
const DELAY_AGENTCHANGE = 500;
|
const DELAY_AGENTCHANGE = 500;
|
||||||
|
|
|
@ -504,8 +504,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* eslint-disable max-lines */
|
|
||||||
|
|
||||||
const DELAY_AGENTCHANGE = 500;
|
const DELAY_AGENTCHANGE = 500;
|
||||||
const DELAY_STAGECHANGE = 250;
|
const DELAY_STAGECHANGE = 250;
|
||||||
const PNG_RESOLUTION = 4;
|
const PNG_RESOLUTION = 4;
|
||||||
|
|
Loading…
Reference in New Issue