convert sequenceDb to class.

This commit is contained in:
saurabhg772244
2025-01-15 15:37:33 +05:30
parent bc2cc61240
commit 5d3d1047a4
3 changed files with 643 additions and 639 deletions

View File

@@ -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(/&equals;/g, '='); sanitizedText = sanitizedText.replace(/&equals;/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,
};

View File

@@ -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);
}
});
});

View File

@@ -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 }) => {