mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-11 19:39:43 +02:00
convert sequenceDb to class.
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
||||||
|
import type { DiagramDB } from '../../diagram-api/types.js';
|
||||||
import { log } from '../../logger.js';
|
import { log } from '../../logger.js';
|
||||||
import { ImperativeState } from '../../utils/imperativeState.js';
|
import { ImperativeState } from '../../utils/imperativeState.js';
|
||||||
import { sanitizeText } from '../common/common.js';
|
import { sanitizeText } from '../common/common.js';
|
||||||
@@ -28,7 +29,8 @@ interface SequenceState {
|
|||||||
lastDestroyed?: Actor;
|
lastDestroyed?: Actor;
|
||||||
}
|
}
|
||||||
|
|
||||||
const state = new ImperativeState<SequenceState>(() => ({
|
export class SequenceDB implements DiagramDB {
|
||||||
|
private readonly state = new ImperativeState<SequenceState>(() => ({
|
||||||
prevActor: undefined,
|
prevActor: undefined,
|
||||||
actors: new Map(),
|
actors: new Map(),
|
||||||
createdActors: new Map(),
|
createdActors: new Map(),
|
||||||
@@ -43,34 +45,34 @@ const state = new ImperativeState<SequenceState>(() => ({
|
|||||||
lastDestroyed: undefined,
|
lastDestroyed: undefined,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const addBox = function (data: { text: string; color: string; wrap: boolean }) {
|
public addBox = (data: { text: string; color: string; wrap: boolean }) => {
|
||||||
state.records.boxes.push({
|
this.state.records.boxes.push({
|
||||||
name: data.text,
|
name: data.text,
|
||||||
wrap: data.wrap ?? autoWrap(),
|
wrap: data.wrap ?? this.autoWrap(),
|
||||||
fill: data.color,
|
fill: data.color,
|
||||||
actorKeys: [],
|
actorKeys: [],
|
||||||
});
|
});
|
||||||
state.records.currentBox = state.records.boxes.slice(-1)[0];
|
this.state.records.currentBox = this.state.records.boxes.slice(-1)[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const addActor = function (
|
public addActor = (
|
||||||
id: string,
|
id: string,
|
||||||
name: string,
|
name: string,
|
||||||
description: { text: string; wrap?: boolean | null; type: string },
|
description: { text: string; wrap?: boolean | null; type: string },
|
||||||
type: string
|
type: string
|
||||||
) {
|
) => {
|
||||||
let assignedBox = state.records.currentBox;
|
let assignedBox = this.state.records.currentBox;
|
||||||
const old = state.records.actors.get(id);
|
const old = this.state.records.actors.get(id);
|
||||||
if (old) {
|
if (old) {
|
||||||
// If already set and trying to set to a new one throw error
|
// If already set and trying to set to a new one throw error
|
||||||
if (state.records.currentBox && old.box && state.records.currentBox !== old.box) {
|
if (this.state.records.currentBox && old.box && this.state.records.currentBox !== old.box) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`A same participant should only be defined in one Box: ${old.name} can't be in '${old.box.name}' and in '${state.records.currentBox.name}' at the same time.`
|
`A same participant should only be defined in one Box: ${old.name} can't be in '${old.box.name}' and in '${this.state.records.currentBox.name}' at the same time.`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't change the box if already
|
// Don't change the box if already
|
||||||
assignedBox = old.box ? old.box : state.records.currentBox;
|
assignedBox = old.box ? old.box : this.state.records.currentBox;
|
||||||
old.box = assignedBox;
|
old.box = assignedBox;
|
||||||
|
|
||||||
// Don't allow description nulling
|
// Don't allow description nulling
|
||||||
@@ -87,47 +89,47 @@ export const addActor = function (
|
|||||||
description = { text: name, type };
|
description = { text: name, type };
|
||||||
}
|
}
|
||||||
|
|
||||||
state.records.actors.set(id, {
|
this.state.records.actors.set(id, {
|
||||||
box: assignedBox,
|
box: assignedBox,
|
||||||
name: name,
|
name: name,
|
||||||
description: description.text,
|
description: description.text,
|
||||||
wrap: description.wrap ?? autoWrap(),
|
wrap: description.wrap ?? this.autoWrap(),
|
||||||
prevActor: state.records.prevActor,
|
prevActor: this.state.records.prevActor,
|
||||||
links: {},
|
links: {},
|
||||||
properties: {},
|
properties: {},
|
||||||
actorCnt: null,
|
actorCnt: null,
|
||||||
rectData: null,
|
rectData: null,
|
||||||
type: type ?? 'participant',
|
type: type ?? 'participant',
|
||||||
});
|
});
|
||||||
if (state.records.prevActor) {
|
if (this.state.records.prevActor) {
|
||||||
const prevActorInRecords = state.records.actors.get(state.records.prevActor);
|
const prevActorInRecords = this.state.records.actors.get(this.state.records.prevActor);
|
||||||
if (prevActorInRecords) {
|
if (prevActorInRecords) {
|
||||||
prevActorInRecords.nextActor = id;
|
prevActorInRecords.nextActor = id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.records.currentBox) {
|
if (this.state.records.currentBox) {
|
||||||
state.records.currentBox.actorKeys.push(id);
|
this.state.records.currentBox.actorKeys.push(id);
|
||||||
}
|
}
|
||||||
state.records.prevActor = id;
|
this.state.records.prevActor = id;
|
||||||
};
|
};
|
||||||
|
|
||||||
const activationCount = (part: string) => {
|
private readonly activationCount = (part: string) => {
|
||||||
let i;
|
let i;
|
||||||
let count = 0;
|
let count = 0;
|
||||||
if (!part) {
|
if (!part) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
for (i = 0; i < state.records.messages.length; i++) {
|
for (i = 0; i < this.state.records.messages.length; i++) {
|
||||||
if (
|
if (
|
||||||
state.records.messages[i].type === LINETYPE.ACTIVE_START &&
|
this.state.records.messages[i].type === this.LINETYPE.ACTIVE_START &&
|
||||||
state.records.messages[i].from === part
|
this.state.records.messages[i].from === part
|
||||||
) {
|
) {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
state.records.messages[i].type === LINETYPE.ACTIVE_END &&
|
this.state.records.messages[i].type === this.LINETYPE.ACTIVE_END &&
|
||||||
state.records.messages[i].from === part
|
this.state.records.messages[i].from === part
|
||||||
) {
|
) {
|
||||||
count--;
|
count--;
|
||||||
}
|
}
|
||||||
@@ -135,30 +137,30 @@ const activationCount = (part: string) => {
|
|||||||
return count;
|
return count;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const addMessage = function (
|
public addMessage = (
|
||||||
idFrom: Message['from'],
|
idFrom: Message['from'],
|
||||||
idTo: Message['to'],
|
idTo: Message['to'],
|
||||||
message: { text: string; wrap?: boolean },
|
message: { text: string; wrap?: boolean },
|
||||||
answer: Message['answer']
|
answer: Message['answer']
|
||||||
) {
|
) => {
|
||||||
state.records.messages.push({
|
this.state.records.messages.push({
|
||||||
from: idFrom,
|
from: idFrom,
|
||||||
to: idTo,
|
to: idTo,
|
||||||
message: message.text,
|
message: message.text,
|
||||||
wrap: message.wrap ?? autoWrap(),
|
wrap: message.wrap ?? this.autoWrap(),
|
||||||
answer: answer,
|
answer: answer,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const addSignal = function (
|
public addSignal = (
|
||||||
idFrom?: Message['from'],
|
idFrom?: Message['from'],
|
||||||
idTo?: Message['to'],
|
idTo?: Message['to'],
|
||||||
message?: { text: string; wrap: boolean },
|
message?: { text: string; wrap: boolean },
|
||||||
messageType?: number,
|
messageType?: number,
|
||||||
activate = false
|
activate = false
|
||||||
) {
|
) => {
|
||||||
if (messageType === LINETYPE.ACTIVE_END) {
|
if (messageType === this.LINETYPE.ACTIVE_END) {
|
||||||
const cnt = activationCount(idFrom ?? '');
|
const cnt = this.activationCount(idFrom ?? '');
|
||||||
if (cnt < 1) {
|
if (cnt < 1) {
|
||||||
// Bail out as there is an activation signal from an inactive participant
|
// Bail out as there is an activation signal from an inactive participant
|
||||||
const error = new Error('Trying to inactivate an inactive participant (' + idFrom + ')');
|
const error = new Error('Trying to inactivate an inactive participant (' + idFrom + ')');
|
||||||
@@ -174,61 +176,61 @@ export const addSignal = function (
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
state.records.messages.push({
|
this.state.records.messages.push({
|
||||||
from: idFrom,
|
from: idFrom,
|
||||||
to: idTo,
|
to: idTo,
|
||||||
message: message?.text ?? '',
|
message: message?.text ?? '',
|
||||||
wrap: message?.wrap ?? autoWrap(),
|
wrap: message?.wrap ?? this.autoWrap(),
|
||||||
type: messageType,
|
type: messageType,
|
||||||
activate,
|
activate,
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const hasAtLeastOneBox = function () {
|
public hasAtLeastOneBox = () => {
|
||||||
return state.records.boxes.length > 0;
|
return this.state.records.boxes.length > 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const hasAtLeastOneBoxWithTitle = function () {
|
public hasAtLeastOneBoxWithTitle = () => {
|
||||||
return state.records.boxes.some((b) => b.name);
|
return this.state.records.boxes.some((b) => b.name);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getMessages = function () {
|
public getMessages = () => {
|
||||||
return state.records.messages;
|
return this.state.records.messages;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getBoxes = function () {
|
public getBoxes = () => {
|
||||||
return state.records.boxes;
|
return this.state.records.boxes;
|
||||||
};
|
};
|
||||||
export const getActors = function () {
|
public getActors = () => {
|
||||||
return state.records.actors;
|
return this.state.records.actors;
|
||||||
};
|
};
|
||||||
export const getCreatedActors = function () {
|
public getCreatedActors = () => {
|
||||||
return state.records.createdActors;
|
return this.state.records.createdActors;
|
||||||
};
|
};
|
||||||
export const getDestroyedActors = function () {
|
public getDestroyedActors = () => {
|
||||||
return state.records.destroyedActors;
|
return this.state.records.destroyedActors;
|
||||||
};
|
};
|
||||||
export const getActor = function (id: string) {
|
public getActor = (id: string) => {
|
||||||
// TODO: do we ever use this function in a way that it might return undefined?
|
// TODO: do we ever use this function in a way that it might return undefined?
|
||||||
return state.records.actors.get(id)!;
|
return this.state.records.actors.get(id)!;
|
||||||
};
|
};
|
||||||
export const getActorKeys = function () {
|
public getActorKeys = () => {
|
||||||
return [...state.records.actors.keys()];
|
return [...this.state.records.actors.keys()];
|
||||||
};
|
};
|
||||||
export const enableSequenceNumbers = function () {
|
public enableSequenceNumbers = () => {
|
||||||
state.records.sequenceNumbersEnabled = true;
|
this.state.records.sequenceNumbersEnabled = true;
|
||||||
};
|
};
|
||||||
export const disableSequenceNumbers = function () {
|
public disableSequenceNumbers = () => {
|
||||||
state.records.sequenceNumbersEnabled = false;
|
this.state.records.sequenceNumbersEnabled = false;
|
||||||
};
|
};
|
||||||
export const showSequenceNumbers = () => state.records.sequenceNumbersEnabled;
|
public showSequenceNumbers = () => this.state.records.sequenceNumbersEnabled;
|
||||||
|
|
||||||
export const setWrap = function (wrapSetting?: boolean) {
|
public setWrap = (wrapSetting?: boolean) => {
|
||||||
state.records.wrapEnabled = wrapSetting;
|
this.state.records.wrapEnabled = wrapSetting;
|
||||||
};
|
};
|
||||||
|
|
||||||
const extractWrap = (text?: string): { cleanedText?: string; wrap?: boolean } => {
|
private readonly extractWrap = (text?: string): { cleanedText?: string; wrap?: boolean } => {
|
||||||
if (text === undefined) {
|
if (text === undefined) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -239,23 +241,23 @@ const extractWrap = (text?: string): { cleanedText?: string; wrap?: boolean } =>
|
|||||||
return { cleanedText, wrap };
|
return { cleanedText, wrap };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const autoWrap = () => {
|
public autoWrap = () => {
|
||||||
// if setWrap has been called, use that value, otherwise use the value from the config
|
// if setWrap has been called, use that value, otherwise use the value from the config
|
||||||
// TODO: refactor, always use the config value let setWrap update the config value
|
// TODO: refactor, always use the config value let setWrap update the config value
|
||||||
if (state.records.wrapEnabled !== undefined) {
|
if (this.state.records.wrapEnabled !== undefined) {
|
||||||
return state.records.wrapEnabled;
|
return this.state.records.wrapEnabled;
|
||||||
}
|
}
|
||||||
return getConfig().sequence?.wrap ?? false;
|
return getConfig().sequence?.wrap ?? false;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const clear = function () {
|
public clear = () => {
|
||||||
state.reset();
|
this.state.reset();
|
||||||
commonClear();
|
commonClear();
|
||||||
};
|
};
|
||||||
|
|
||||||
export const parseMessage = function (str: string) {
|
public parseMessage = (str: string) => {
|
||||||
const trimmedStr = str.trim();
|
const trimmedStr = str.trim();
|
||||||
const { wrap, cleanedText } = extractWrap(trimmedStr);
|
const { wrap, cleanedText } = this.extractWrap(trimmedStr);
|
||||||
const message = {
|
const message = {
|
||||||
text: cleanedText,
|
text: cleanedText,
|
||||||
wrap,
|
wrap,
|
||||||
@@ -267,7 +269,7 @@ export const parseMessage = function (str: string) {
|
|||||||
// We expect the box statement to be color first then description
|
// We expect the box statement to be color first then description
|
||||||
// The color can be rgb,rgba,hsl,hsla, or css code names #hex codes are not supported for now because of the way the char # is handled
|
// The color can be rgb,rgba,hsl,hsla, or css code names #hex codes are not supported for now because of the way the char # is handled
|
||||||
// We extract first segment as color, the rest of the line is considered as text
|
// We extract first segment as color, the rest of the line is considered as text
|
||||||
export const parseBoxData = function (str: string) {
|
public parseBoxData = (str: string) => {
|
||||||
const match = /^((?:rgba?|hsla?)\s*\(.*\)|\w*)(.*)$/.exec(str);
|
const match = /^((?:rgba?|hsla?)\s*\(.*\)|\w*)(.*)$/.exec(str);
|
||||||
let color = match?.[1] ? match[1].trim() : 'transparent';
|
let color = match?.[1] ? match[1].trim() : 'transparent';
|
||||||
let title = match?.[2] ? match[2].trim() : undefined;
|
let title = match?.[2] ? match[2].trim() : undefined;
|
||||||
@@ -286,7 +288,7 @@ export const parseBoxData = function (str: string) {
|
|||||||
title = str.trim();
|
title = str.trim();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const { wrap, cleanedText } = extractWrap(title);
|
const { wrap, cleanedText } = this.extractWrap(title);
|
||||||
return {
|
return {
|
||||||
text: cleanedText ? sanitizeText(cleanedText, getConfig()) : undefined,
|
text: cleanedText ? sanitizeText(cleanedText, getConfig()) : undefined,
|
||||||
color,
|
color,
|
||||||
@@ -294,7 +296,7 @@ export const parseBoxData = function (str: string) {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const LINETYPE = {
|
public LINETYPE = {
|
||||||
SOLID: 0,
|
SOLID: 0,
|
||||||
DOTTED: 1,
|
DOTTED: 1,
|
||||||
NOTE: 2,
|
NOTE: 2,
|
||||||
@@ -329,46 +331,46 @@ export const LINETYPE = {
|
|||||||
BIDIRECTIONAL_DOTTED: 34,
|
BIDIRECTIONAL_DOTTED: 34,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ARROWTYPE = {
|
public ARROWTYPE = {
|
||||||
FILLED: 0,
|
FILLED: 0,
|
||||||
OPEN: 1,
|
OPEN: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PLACEMENT = {
|
public PLACEMENT = {
|
||||||
LEFTOF: 0,
|
LEFTOF: 0,
|
||||||
RIGHTOF: 1,
|
RIGHTOF: 1,
|
||||||
OVER: 2,
|
OVER: 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const addNote = function (
|
public addNote = (
|
||||||
actor: { actor: string },
|
actor: { actor: string },
|
||||||
placement: Message['placement'],
|
placement: Message['placement'],
|
||||||
message: { text: string; wrap?: boolean }
|
message: { text: string; wrap?: boolean }
|
||||||
) {
|
) => {
|
||||||
const note: Note = {
|
const note: Note = {
|
||||||
actor: actor,
|
actor: actor,
|
||||||
placement: placement,
|
placement: placement,
|
||||||
message: message.text,
|
message: message.text,
|
||||||
wrap: message.wrap ?? autoWrap(),
|
wrap: message.wrap ?? this.autoWrap(),
|
||||||
};
|
};
|
||||||
|
|
||||||
//@ts-ignore: Coerce actor into a [to, from, ...] array
|
//@ts-ignore: Coerce actor into a [to, from, ...] array
|
||||||
// eslint-disable-next-line unicorn/prefer-spread
|
// eslint-disable-next-line unicorn/prefer-spread
|
||||||
const actors = [].concat(actor, actor);
|
const actors = [].concat(actor, actor);
|
||||||
state.records.notes.push(note);
|
this.state.records.notes.push(note);
|
||||||
state.records.messages.push({
|
this.state.records.messages.push({
|
||||||
from: actors[0],
|
from: actors[0],
|
||||||
to: actors[1],
|
to: actors[1],
|
||||||
message: message.text,
|
message: message.text,
|
||||||
wrap: message.wrap ?? autoWrap(),
|
wrap: message.wrap ?? this.autoWrap(),
|
||||||
type: LINETYPE.NOTE,
|
type: this.LINETYPE.NOTE,
|
||||||
placement: placement,
|
placement: placement,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const addLinks = function (actorId: string, text: { text: string }) {
|
public addLinks = (actorId: string, text: { text: string }) => {
|
||||||
// find the actor
|
// find the actor
|
||||||
const actor = getActor(actorId);
|
const actor = this.getActor(actorId);
|
||||||
// JSON.parse the text
|
// JSON.parse the text
|
||||||
try {
|
try {
|
||||||
let sanitizedText = sanitizeText(text.text, getConfig());
|
let sanitizedText = sanitizeText(text.text, getConfig());
|
||||||
@@ -376,15 +378,15 @@ export const addLinks = function (actorId: string, text: { text: string }) {
|
|||||||
sanitizedText = sanitizedText.replace(/=/g, '=');
|
sanitizedText = sanitizedText.replace(/=/g, '=');
|
||||||
const links = JSON.parse(sanitizedText);
|
const links = JSON.parse(sanitizedText);
|
||||||
// add the deserialized text to the actor's links field.
|
// add the deserialized text to the actor's links field.
|
||||||
insertLinks(actor, links);
|
this.insertLinks(actor, links);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.error('error while parsing actor link text', e);
|
log.error('error while parsing actor link text', e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const addALink = function (actorId: string, text: { text: string }) {
|
public addALink = (actorId: string, text: { text: string }) => {
|
||||||
// find the actor
|
// find the actor
|
||||||
const actor = getActor(actorId);
|
const actor = this.getActor(actorId);
|
||||||
try {
|
try {
|
||||||
const links: Record<string, string> = {};
|
const links: Record<string, string> = {};
|
||||||
let sanitizedText = sanitizeText(text.text, getConfig());
|
let sanitizedText = sanitizeText(text.text, getConfig());
|
||||||
@@ -396,7 +398,7 @@ export const addALink = function (actorId: string, text: { text: string }) {
|
|||||||
|
|
||||||
links[label] = link;
|
links[label] = link;
|
||||||
// add the deserialized text to the actor's links field.
|
// add the deserialized text to the actor's links field.
|
||||||
insertLinks(actor, links);
|
this.insertLinks(actor, links);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.error('error while parsing actor link text', e);
|
log.error('error while parsing actor link text', e);
|
||||||
}
|
}
|
||||||
@@ -406,7 +408,7 @@ export const addALink = function (actorId: string, text: { text: string }) {
|
|||||||
* @param actor - the actor to add the links to
|
* @param actor - the actor to add the links to
|
||||||
* @param links - the links to add to the actor
|
* @param links - the links to add to the actor
|
||||||
*/
|
*/
|
||||||
function insertLinks(actor: Actor, links: Record<string, string>) {
|
private readonly insertLinks = (actor: Actor, links: Record<string, string>) => {
|
||||||
if (actor.links == null) {
|
if (actor.links == null) {
|
||||||
actor.links = links;
|
actor.links = links;
|
||||||
} else {
|
} else {
|
||||||
@@ -414,17 +416,17 @@ function insertLinks(actor: Actor, links: Record<string, string>) {
|
|||||||
actor.links[key] = links[key];
|
actor.links[key] = links[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
export const addProperties = function (actorId: string, text: { text: string }) {
|
public addProperties = (actorId: string, text: { text: string }) => {
|
||||||
// find the actor
|
// find the actor
|
||||||
const actor = getActor(actorId);
|
const actor = this.getActor(actorId);
|
||||||
// JSON.parse the text
|
// JSON.parse the text
|
||||||
try {
|
try {
|
||||||
const sanitizedText = sanitizeText(text.text, getConfig());
|
const sanitizedText = sanitizeText(text.text, getConfig());
|
||||||
const properties: Record<string, unknown> = JSON.parse(sanitizedText);
|
const properties: Record<string, unknown> = JSON.parse(sanitizedText);
|
||||||
// add the deserialized text to the actor's property field.
|
// add the deserialized text to the actor's property field.
|
||||||
insertProperties(actor, properties);
|
this.insertProperties(actor, properties);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.error('error while parsing actor properties text', e);
|
log.error('error while parsing actor properties text', e);
|
||||||
}
|
}
|
||||||
@@ -434,7 +436,7 @@ export const addProperties = function (actorId: string, text: { text: string })
|
|||||||
* @param actor - the actor to add the properties to
|
* @param actor - the actor to add the properties to
|
||||||
* @param properties - the properties to add to the actor's properties
|
* @param properties - the properties to add to the actor's properties
|
||||||
*/
|
*/
|
||||||
function insertProperties(actor: Actor, properties: Record<string, unknown>) {
|
private readonly insertProperties = (actor: Actor, properties: Record<string, unknown>) => {
|
||||||
if (actor.properties == null) {
|
if (actor.properties == null) {
|
||||||
actor.properties = properties;
|
actor.properties = properties;
|
||||||
} else {
|
} else {
|
||||||
@@ -442,15 +444,15 @@ function insertProperties(actor: Actor, properties: Record<string, unknown>) {
|
|||||||
actor.properties[key] = properties[key];
|
actor.properties[key] = properties[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
function boxEnd() {
|
private readonly boxEnd = () => {
|
||||||
state.records.currentBox = undefined;
|
this.state.records.currentBox = undefined;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const addDetails = function (actorId: string, text: { text: string }) {
|
public addDetails = (actorId: string, text: { text: string }) => {
|
||||||
// find the actor
|
// find the actor
|
||||||
const actor = getActor(actorId);
|
const actor = this.getActor(actorId);
|
||||||
const elem = document.getElementById(text.text)!;
|
const elem = document.getElementById(text.text)!;
|
||||||
|
|
||||||
// JSON.parse the text
|
// JSON.parse the text
|
||||||
@@ -459,18 +461,18 @@ export const addDetails = function (actorId: string, text: { text: string }) {
|
|||||||
const details = JSON.parse(text);
|
const details = JSON.parse(text);
|
||||||
// add the deserialized text to the actor's property field.
|
// add the deserialized text to the actor's property field.
|
||||||
if (details.properties) {
|
if (details.properties) {
|
||||||
insertProperties(actor, details.properties);
|
this.insertProperties(actor, details.properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (details.links) {
|
if (details.links) {
|
||||||
insertLinks(actor, details.links);
|
this.insertLinks(actor, details.links);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.error('error while parsing actor details text', e);
|
log.error('error while parsing actor details text', e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getActorProperty = function (actor: Actor, key: string) {
|
public getActorProperty = (actor: Actor, key: string) => {
|
||||||
if (actor?.properties !== undefined) {
|
if (actor?.properties !== undefined) {
|
||||||
return actor.properties[key];
|
return actor.properties[key];
|
||||||
}
|
}
|
||||||
@@ -479,15 +481,15 @@ export const getActorProperty = function (actor: Actor, key: string) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-redundant-type-constituents
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-redundant-type-constituents
|
||||||
export const apply = function (param: any | AddMessageParams | AddMessageParams[]) {
|
public apply = (param: any | AddMessageParams | AddMessageParams[]) => {
|
||||||
if (Array.isArray(param)) {
|
if (Array.isArray(param)) {
|
||||||
param.forEach(function (item) {
|
param.forEach((item) => {
|
||||||
apply(item);
|
this.apply(item);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
switch (param.type) {
|
switch (param.type) {
|
||||||
case 'sequenceIndex':
|
case 'sequenceIndex':
|
||||||
state.records.messages.push({
|
this.state.records.messages.push({
|
||||||
from: undefined,
|
from: undefined,
|
||||||
to: undefined,
|
to: undefined,
|
||||||
message: {
|
message: {
|
||||||
@@ -500,169 +502,139 @@ export const apply = function (param: any | AddMessageParams | AddMessageParams[
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case 'addParticipant':
|
case 'addParticipant':
|
||||||
addActor(param.actor, param.actor, param.description, param.draw);
|
this.addActor(param.actor, param.actor, param.description, param.draw);
|
||||||
break;
|
break;
|
||||||
case 'createParticipant':
|
case 'createParticipant':
|
||||||
if (state.records.actors.has(param.actor)) {
|
if (this.state.records.actors.has(param.actor)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"It is not possible to have actors with the same id, even if one is destroyed before the next is created. Use 'AS' aliases to simulate the behavior"
|
"It is not possible to have actors with the same id, even if one is destroyed before the next is created. Use 'AS' aliases to simulate the behavior"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
state.records.lastCreated = param.actor;
|
this.state.records.lastCreated = param.actor;
|
||||||
addActor(param.actor, param.actor, param.description, param.draw);
|
this.addActor(param.actor, param.actor, param.description, param.draw);
|
||||||
state.records.createdActors.set(param.actor, state.records.messages.length);
|
this.state.records.createdActors.set(param.actor, this.state.records.messages.length);
|
||||||
break;
|
break;
|
||||||
case 'destroyParticipant':
|
case 'destroyParticipant':
|
||||||
state.records.lastDestroyed = param.actor;
|
this.state.records.lastDestroyed = param.actor;
|
||||||
state.records.destroyedActors.set(param.actor, state.records.messages.length);
|
this.state.records.destroyedActors.set(param.actor, this.state.records.messages.length);
|
||||||
break;
|
break;
|
||||||
case 'activeStart':
|
case 'activeStart':
|
||||||
addSignal(param.actor, undefined, undefined, param.signalType);
|
this.addSignal(param.actor, undefined, undefined, param.signalType);
|
||||||
break;
|
break;
|
||||||
case 'activeEnd':
|
case 'activeEnd':
|
||||||
addSignal(param.actor, undefined, undefined, param.signalType);
|
this.addSignal(param.actor, undefined, undefined, param.signalType);
|
||||||
break;
|
break;
|
||||||
case 'addNote':
|
case 'addNote':
|
||||||
addNote(param.actor, param.placement, param.text);
|
this.addNote(param.actor, param.placement, param.text);
|
||||||
break;
|
break;
|
||||||
case 'addLinks':
|
case 'addLinks':
|
||||||
addLinks(param.actor, param.text);
|
this.addLinks(param.actor, param.text);
|
||||||
break;
|
break;
|
||||||
case 'addALink':
|
case 'addALink':
|
||||||
addALink(param.actor, param.text);
|
this.addALink(param.actor, param.text);
|
||||||
break;
|
break;
|
||||||
case 'addProperties':
|
case 'addProperties':
|
||||||
addProperties(param.actor, param.text);
|
this.addProperties(param.actor, param.text);
|
||||||
break;
|
break;
|
||||||
case 'addDetails':
|
case 'addDetails':
|
||||||
addDetails(param.actor, param.text);
|
this.addDetails(param.actor, param.text);
|
||||||
break;
|
break;
|
||||||
case 'addMessage':
|
case 'addMessage':
|
||||||
if (state.records.lastCreated) {
|
if (this.state.records.lastCreated) {
|
||||||
if (param.to !== state.records.lastCreated) {
|
if (param.to !== this.state.records.lastCreated) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'The created participant ' +
|
'The created participant ' +
|
||||||
state.records.lastCreated.name +
|
this.state.records.lastCreated.name +
|
||||||
' does not have an associated creating message after its declaration. Please check the sequence diagram.'
|
' does not have an associated creating message after its declaration. Please check the sequence diagram.'
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
state.records.lastCreated = undefined;
|
this.state.records.lastCreated = undefined;
|
||||||
}
|
}
|
||||||
} else if (state.records.lastDestroyed) {
|
} else if (this.state.records.lastDestroyed) {
|
||||||
if (
|
if (
|
||||||
param.to !== state.records.lastDestroyed &&
|
param.to !== this.state.records.lastDestroyed &&
|
||||||
param.from !== state.records.lastDestroyed
|
param.from !== this.state.records.lastDestroyed
|
||||||
) {
|
) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'The destroyed participant ' +
|
'The destroyed participant ' +
|
||||||
state.records.lastDestroyed.name +
|
this.state.records.lastDestroyed.name +
|
||||||
' does not have an associated destroying message after its declaration. Please check the sequence diagram.'
|
' does not have an associated destroying message after its declaration. Please check the sequence diagram.'
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
state.records.lastDestroyed = undefined;
|
this.state.records.lastDestroyed = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addSignal(param.from, param.to, param.msg, param.signalType, param.activate);
|
this.addSignal(param.from, param.to, param.msg, param.signalType, param.activate);
|
||||||
break;
|
break;
|
||||||
case 'boxStart':
|
case 'boxStart':
|
||||||
addBox(param.boxData);
|
this.addBox(param.boxData);
|
||||||
break;
|
break;
|
||||||
case 'boxEnd':
|
case 'boxEnd':
|
||||||
boxEnd();
|
this.boxEnd();
|
||||||
break;
|
break;
|
||||||
case 'loopStart':
|
case 'loopStart':
|
||||||
addSignal(undefined, undefined, param.loopText, param.signalType);
|
this.addSignal(undefined, undefined, param.loopText, param.signalType);
|
||||||
break;
|
break;
|
||||||
case 'loopEnd':
|
case 'loopEnd':
|
||||||
addSignal(undefined, undefined, undefined, param.signalType);
|
this.addSignal(undefined, undefined, undefined, param.signalType);
|
||||||
break;
|
break;
|
||||||
case 'rectStart':
|
case 'rectStart':
|
||||||
addSignal(undefined, undefined, param.color, param.signalType);
|
this.addSignal(undefined, undefined, param.color, param.signalType);
|
||||||
break;
|
break;
|
||||||
case 'rectEnd':
|
case 'rectEnd':
|
||||||
addSignal(undefined, undefined, undefined, param.signalType);
|
this.addSignal(undefined, undefined, undefined, param.signalType);
|
||||||
break;
|
break;
|
||||||
case 'optStart':
|
case 'optStart':
|
||||||
addSignal(undefined, undefined, param.optText, param.signalType);
|
this.addSignal(undefined, undefined, param.optText, param.signalType);
|
||||||
break;
|
break;
|
||||||
case 'optEnd':
|
case 'optEnd':
|
||||||
addSignal(undefined, undefined, undefined, param.signalType);
|
this.addSignal(undefined, undefined, undefined, param.signalType);
|
||||||
break;
|
break;
|
||||||
case 'altStart':
|
case 'altStart':
|
||||||
addSignal(undefined, undefined, param.altText, param.signalType);
|
this.addSignal(undefined, undefined, param.altText, param.signalType);
|
||||||
break;
|
break;
|
||||||
case 'else':
|
case 'else':
|
||||||
addSignal(undefined, undefined, param.altText, param.signalType);
|
this.addSignal(undefined, undefined, param.altText, param.signalType);
|
||||||
break;
|
break;
|
||||||
case 'altEnd':
|
case 'altEnd':
|
||||||
addSignal(undefined, undefined, undefined, param.signalType);
|
this.addSignal(undefined, undefined, undefined, param.signalType);
|
||||||
break;
|
break;
|
||||||
case 'setAccTitle':
|
case 'setAccTitle':
|
||||||
setAccTitle(param.text);
|
setAccTitle(param.text);
|
||||||
break;
|
break;
|
||||||
case 'parStart':
|
case 'parStart':
|
||||||
addSignal(undefined, undefined, param.parText, param.signalType);
|
this.addSignal(undefined, undefined, param.parText, param.signalType);
|
||||||
break;
|
break;
|
||||||
case 'and':
|
case 'and':
|
||||||
addSignal(undefined, undefined, param.parText, param.signalType);
|
this.addSignal(undefined, undefined, param.parText, param.signalType);
|
||||||
break;
|
break;
|
||||||
case 'parEnd':
|
case 'parEnd':
|
||||||
addSignal(undefined, undefined, undefined, param.signalType);
|
this.addSignal(undefined, undefined, undefined, param.signalType);
|
||||||
break;
|
break;
|
||||||
case 'criticalStart':
|
case 'criticalStart':
|
||||||
addSignal(undefined, undefined, param.criticalText, param.signalType);
|
this.addSignal(undefined, undefined, param.criticalText, param.signalType);
|
||||||
break;
|
break;
|
||||||
case 'option':
|
case 'option':
|
||||||
addSignal(undefined, undefined, param.optionText, param.signalType);
|
this.addSignal(undefined, undefined, param.optionText, param.signalType);
|
||||||
break;
|
break;
|
||||||
case 'criticalEnd':
|
case 'criticalEnd':
|
||||||
addSignal(undefined, undefined, undefined, param.signalType);
|
this.addSignal(undefined, undefined, undefined, param.signalType);
|
||||||
break;
|
break;
|
||||||
case 'breakStart':
|
case 'breakStart':
|
||||||
addSignal(undefined, undefined, param.breakText, param.signalType);
|
this.addSignal(undefined, undefined, param.breakText, param.signalType);
|
||||||
break;
|
break;
|
||||||
case 'breakEnd':
|
case 'breakEnd':
|
||||||
addSignal(undefined, undefined, undefined, param.signalType);
|
this.addSignal(undefined, undefined, undefined, param.signalType);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
public getAccTitle = getAccTitle;
|
||||||
addActor,
|
public getDiagramTitle = getDiagramTitle;
|
||||||
addMessage,
|
public setDiagramTitle = setDiagramTitle;
|
||||||
addSignal,
|
public getConfig = () => getConfig().sequence;
|
||||||
addLinks,
|
public setAccTitle = setAccTitle;
|
||||||
addDetails,
|
public setAccDescription = setAccDescription;
|
||||||
addProperties,
|
public getAccDescription = getAccDescription;
|
||||||
autoWrap,
|
}
|
||||||
setWrap,
|
|
||||||
enableSequenceNumbers,
|
|
||||||
disableSequenceNumbers,
|
|
||||||
showSequenceNumbers,
|
|
||||||
getMessages,
|
|
||||||
getActors,
|
|
||||||
getCreatedActors,
|
|
||||||
getDestroyedActors,
|
|
||||||
getActor,
|
|
||||||
getActorKeys,
|
|
||||||
getActorProperty,
|
|
||||||
getAccTitle,
|
|
||||||
getBoxes,
|
|
||||||
getDiagramTitle,
|
|
||||||
setDiagramTitle,
|
|
||||||
getConfig: () => getConfig().sequence,
|
|
||||||
clear,
|
|
||||||
parseMessage,
|
|
||||||
parseBoxData,
|
|
||||||
LINETYPE,
|
|
||||||
ARROWTYPE,
|
|
||||||
PLACEMENT,
|
|
||||||
addNote,
|
|
||||||
setAccTitle,
|
|
||||||
apply,
|
|
||||||
setAccDescription,
|
|
||||||
getAccDescription,
|
|
||||||
hasAtLeastOneBox,
|
|
||||||
hasAtLeastOneBoxWithTitle,
|
|
||||||
};
|
|
||||||
|
@@ -3,6 +3,7 @@ import { setSiteConfig } from '../../diagram-api/diagramAPI.js';
|
|||||||
import mermaidAPI from '../../mermaidAPI.js';
|
import mermaidAPI from '../../mermaidAPI.js';
|
||||||
import { Diagram } from '../../Diagram.js';
|
import { Diagram } from '../../Diagram.js';
|
||||||
import { addDiagrams } from '../../diagram-api/diagram-orchestration.js';
|
import { addDiagrams } from '../../diagram-api/diagram-orchestration.js';
|
||||||
|
import { SequenceDB } from './sequenceDb.js';
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
// Is required to load the sequence diagram
|
// Is required to load the sequence diagram
|
||||||
@@ -2071,3 +2072,27 @@ ${prop}-->>A: Hello, how are you?`)
|
|||||||
).resolves.toBeDefined();
|
).resolves.toBeDefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('sequence db class', () => {
|
||||||
|
let sequenceDb;
|
||||||
|
beforeEach(() => {
|
||||||
|
sequenceDb = new SequenceDB();
|
||||||
|
});
|
||||||
|
// This is to ensure that functions used in sequence JISON are exposed as function from SequenceDB
|
||||||
|
it('should have functions used in sequence JISON as own property', () => {
|
||||||
|
const functionsUsedInParser = [
|
||||||
|
'apply',
|
||||||
|
'parseBoxData',
|
||||||
|
'LINETYPE',
|
||||||
|
'setDiagramTitle',
|
||||||
|
'setAccTitle',
|
||||||
|
'setAccDescription',
|
||||||
|
'parseMessage',
|
||||||
|
'PLACEMENT',
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const fun of functionsUsedInParser) {
|
||||||
|
expect(Object.hasOwn(sequenceDb, fun)).toBe(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
@@ -1,13 +1,20 @@
|
|||||||
import type { DiagramDefinition } from '../../diagram-api/types.js';
|
import type { DiagramDefinition } from '../../diagram-api/types.js';
|
||||||
// @ts-ignore: JISON doesn't support types
|
// @ts-ignore: JISON doesn't support types
|
||||||
import parser from './parser/sequenceDiagram.jison';
|
import parser from './parser/sequenceDiagram.jison';
|
||||||
import db from './sequenceDb.js';
|
import { SequenceDB } from './sequenceDb.js';
|
||||||
import styles from './styles.js';
|
import styles from './styles.js';
|
||||||
import renderer from './sequenceRenderer.js';
|
import renderer from './sequenceRenderer.js';
|
||||||
|
|
||||||
|
let db: SequenceDB;
|
||||||
|
|
||||||
export const diagram: DiagramDefinition = {
|
export const diagram: DiagramDefinition = {
|
||||||
parser,
|
parser,
|
||||||
db,
|
get db() {
|
||||||
|
if (!db) {
|
||||||
|
db = new SequenceDB();
|
||||||
|
}
|
||||||
|
return db;
|
||||||
|
},
|
||||||
renderer,
|
renderer,
|
||||||
styles,
|
styles,
|
||||||
init: ({ wrap }) => {
|
init: ({ wrap }) => {
|
||||||
|
Reference in New Issue
Block a user