From 3567308a221953b7ef0395a646cc3c3a2df21990 Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Fri, 29 Mar 2024 13:29:31 +0530 Subject: [PATCH 01/10] fix: make sequenceDB typesafe --- .../sequence/{sequenceDb.js => sequenceDb.ts} | 241 ++++++++++++------ 1 file changed, 169 insertions(+), 72 deletions(-) rename packages/mermaid/src/diagrams/sequence/{sequenceDb.js => sequenceDb.ts} (74%) diff --git a/packages/mermaid/src/diagrams/sequence/sequenceDb.js b/packages/mermaid/src/diagrams/sequence/sequenceDb.ts similarity index 74% rename from packages/mermaid/src/diagrams/sequence/sequenceDb.js rename to packages/mermaid/src/diagrams/sequence/sequenceDb.ts index 4ff1982275..7a2c3f730f 100644 --- a/packages/mermaid/src/diagrams/sequence/sequenceDb.js +++ b/packages/mermaid/src/diagrams/sequence/sequenceDb.ts @@ -12,7 +12,60 @@ import { } from '../common/commonDb.js'; import { ImperativeState } from '../../utils/imperativeState.js'; -const state = new ImperativeState(() => ({ +type Box = { + name: string; + wrap: boolean; + fill: string; + actorKeys: string[]; +}; + +type Actor = { + box?: Box; + name: string; + description: string; + wrap: boolean; + prevActor?: string; + nextActor?: string; + links: Record; + properties: Record; + actorCnt: number | null; + rectData: unknown; + type: string; +}; + +type Message = { + from?: { actor: string }; + to?: { actor: string }; + message?: + | string + | { + start: number; + step: number; + visible: boolean; + }; + wrap: boolean; + answer?: unknown; + type?: number; + activate?: boolean; + placement?: string; +}; + +type State = { + prevActor?: string; + actors: Record; + createdActors: Record; + destroyedActors: Record; + boxes: Box[]; + messages: Message[]; + notes: unknown[]; + sequenceNumbersEnabled: boolean; + wrapEnabled?: boolean; + currentBox?: Box; + lastCreated?: Actor; + lastDestroyed?: Actor; +}; + +const state = new ImperativeState(() => ({ prevActor: undefined, actors: {}, createdActors: {}, @@ -27,7 +80,7 @@ const state = new ImperativeState(() => ({ lastDestroyed: undefined, })); -export const addBox = function (data) { +export const addBox = function (data: { text: string; color: string; wrap: boolean }) { state.records.boxes.push({ name: data.text, wrap: (data.wrap === undefined && autoWrap()) || !!data.wrap, @@ -37,20 +90,19 @@ export const addBox = function (data) { state.records.currentBox = state.records.boxes.slice(-1)[0]; }; -export const addActor = function (id, name, description, type) { +export const addActor = function ( + id: string, + name: string, + description: { text: string; wrap?: boolean | null; type: string }, + type: string +) { let assignedBox = state.records.currentBox; const old = state.records.actors[id]; if (old) { // If already set and trying to set to a new one throw error if (state.records.currentBox && old.box && state.records.currentBox !== old.box) { 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 '${state.records.currentBox.name}' at the same time.` ); } @@ -94,19 +146,19 @@ export const addActor = function (id, name, description, type) { state.records.prevActor = id; }; -const activationCount = (part) => { +const activationCount = (part?: string) => { let i; let count = 0; for (i = 0; i < state.records.messages.length; i++) { if ( state.records.messages[i].type === LINETYPE.ACTIVE_START && - state.records.messages[i].from.actor === part + state.records.messages[i].from?.actor === part ) { count++; } if ( state.records.messages[i].type === LINETYPE.ACTIVE_END && - state.records.messages[i].from.actor === part + state.records.messages[i].from?.actor === part ) { count--; } @@ -114,7 +166,12 @@ const activationCount = (part) => { return count; }; -export const addMessage = function (idFrom, idTo, message, answer) { +export const addMessage = function ( + idFrom: Message['from'], + idTo: Message['to'], + message: { text: string; wrap?: boolean }, + answer: Message['answer'] +) { state.records.messages.push({ from: idFrom, to: idTo, @@ -125,17 +182,21 @@ export const addMessage = function (idFrom, idTo, message, answer) { }; export const addSignal = function ( - idFrom, - idTo, - message = { text: undefined, wrap: undefined }, - messageType, - activate = false + idFrom?: Message['from'], + idTo?: Message['to'], + message?: { text: string; wrap?: boolean }, + messageType?: number, + activate: boolean = false ) { if (messageType === LINETYPE.ACTIVE_END) { - const cnt = activationCount(idFrom.actor); + const cnt = activationCount(idFrom?.actor); if (cnt < 1) { // Bail out as there is an activation signal from an inactive participant - let error = new Error('Trying to inactivate an inactive participant (' + idFrom.actor + ')'); + const error = new Error( + 'Trying to inactivate an inactive participant (' + idFrom?.actor + ')' + ); + + // @ts-ignore: we are passing hash param to the error object, however we should define our own custom error class to make it type safe error.hash = { text: '->>-', token: '->>-', @@ -149,8 +210,8 @@ export const addSignal = function ( state.records.messages.push({ from: idFrom, to: idTo, - message: message.text, - wrap: (message.wrap === undefined && autoWrap()) || !!message.wrap, + message: message?.text, + wrap: (message?.wrap === undefined && autoWrap()) || !!message?.wrap, type: messageType, activate, }); @@ -181,7 +242,7 @@ export const getCreatedActors = function () { export const getDestroyedActors = function () { return state.records.destroyedActors; }; -export const getActor = function (id) { +export const getActor = function (id: string) { return state.records.actors[id]; }; export const getActorKeys = function () { @@ -195,7 +256,7 @@ export const disableSequenceNumbers = function () { }; export const showSequenceNumbers = () => state.records.sequenceNumbersEnabled; -export const setWrap = function (wrapSetting) { +export const setWrap = function (wrapSetting: boolean) { state.records.wrapEnabled = wrapSetting; }; @@ -205,7 +266,7 @@ export const autoWrap = () => { if (state.records.wrapEnabled !== undefined) { return state.records.wrapEnabled; } - return getConfig().sequence.wrap; + return getConfig()?.sequence?.wrap; }; export const clear = function () { @@ -213,25 +274,25 @@ export const clear = function () { commonClear(); }; -export const parseMessage = function (str) { - const _str = str.trim(); +export const parseMessage = function (str: string) { + const trimmedStr = str.trim(); const message = { - text: _str.replace(/^:?(?:no)?wrap:/, '').trim(), + text: trimmedStr.replace(/^:?(?:no)?wrap:/, '').trim(), wrap: - _str.match(/^:?wrap:/) !== null + trimmedStr.match(/^:?wrap:/) !== null ? true - : _str.match(/^:?nowrap:/) !== null + : trimmedStr.match(/^:?nowrap:/) !== null ? false : undefined, }; - log.debug('parseMessage:', message); + log.debug(`parseMessage: ${message}`); return message; }; // 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 // We extract first segment as color, the rest of the line is considered as text -export const parseBoxData = function (str) { +export const parseBoxData = function (str: string) { const match = str.match(/^((?:rgba?|hsla?)\s*\(.*\)|\w*)(.*)$/); let color = match != null && match[1] ? match[1].trim() : 'transparent'; let title = match != null && match[2] ? match[2].trim() : undefined; @@ -312,7 +373,11 @@ export const PLACEMENT = { OVER: 2, }; -export const addNote = function (actor, placement, message) { +export const addNote = function ( + actor: { actor: string }, + placement: Message['placement'], + message: { text: string; wrap?: boolean } +) { const note = { actor: actor, placement: placement, @@ -322,7 +387,7 @@ export const addNote = function (actor, placement, message) { // Coerce actor into a [to, from, ...] array // eslint-disable-next-line unicorn/prefer-spread - const actors = [].concat(actor, actor); + const actors = [actor, actor]; state.records.notes.push(note); state.records.messages.push({ @@ -335,7 +400,7 @@ export const addNote = function (actor, placement, message) { }); }; -export const addLinks = function (actorId, text) { +export const addLinks = function (actorId: string, text: { text: string }) { // find the actor const actor = getActor(actorId); // JSON.parse the text @@ -351,17 +416,17 @@ export const addLinks = function (actorId, text) { } }; -export const addALink = function (actorId, text) { +export const addALink = function (actorId: string, text: { text: string }) { // find the actor const actor = getActor(actorId); try { - const links = {}; + const links: { [key: string]: string } = {}; let sanitizedText = sanitizeText(text.text, getConfig()); - var sep = sanitizedText.indexOf('@'); + const sep = sanitizedText.indexOf('@'); sanitizedText = sanitizedText.replace(/&/g, '&'); sanitizedText = sanitizedText.replace(/=/g, '='); - var label = sanitizedText.slice(0, sep - 1).trim(); - var link = sanitizedText.slice(sep + 1).trim(); + const label = sanitizedText.slice(0, sep - 1).trim(); + const link = sanitizedText.slice(sep + 1).trim(); links[label] = link; // add the deserialized text to the actor's links field. @@ -372,26 +437,26 @@ export const addALink = function (actorId, text) { }; /** - * @param {any} actor - * @param {any} links + * @param actor - the actor to add the links to + * @param links - the links to add to the actor */ -function insertLinks(actor, links) { +function insertLinks(actor: Actor, links: Record) { if (actor.links == null) { actor.links = links; } else { - for (let key in links) { + for (const key in links) { actor.links[key] = links[key]; } } } -export const addProperties = function (actorId, text) { +export const addProperties = function (actorId: string, text: { text: string }) { // find the actor const actor = getActor(actorId); // JSON.parse the text try { - let sanitizedText = sanitizeText(text.text, getConfig()); - const properties = JSON.parse(sanitizedText); + const sanitizedText = sanitizeText(text.text, getConfig()); + const properties: Record = JSON.parse(sanitizedText); // add the deserialized text to the actor's property field. insertProperties(actor, properties); } catch (e) { @@ -400,30 +465,27 @@ export const addProperties = function (actorId, text) { }; /** - * @param {any} actor - * @param {any} properties + * @param actor - the actor to add the properties to + * @param properties - the properties to add to the actor's properties */ -function insertProperties(actor, properties) { +function insertProperties(actor: Actor, properties: Record) { if (actor.properties == null) { actor.properties = properties; } else { - for (let key in properties) { + for (const key in properties) { actor.properties[key] = properties[key]; } } } -/** - * - */ function boxEnd() { state.records.currentBox = undefined; } -export const addDetails = function (actorId, text) { +export const addDetails = function (actorId: string, text: { text: string }) { // find the actor const actor = getActor(actorId); - const elem = document.getElementById(text.text); + const elem = document.getElementById(text.text)!; // JSON.parse the text try { @@ -442,7 +504,7 @@ export const addDetails = function (actorId, text) { } }; -export const getActorProperty = function (actor, key) { +export const getActorProperty = function (actor: Actor, key: string) { if (actor !== undefined && actor.properties !== undefined) { return actor.properties[key]; } @@ -450,20 +512,55 @@ export const getActorProperty = function (actor, key) { return undefined; }; -/** - * @typedef {object} AddMessageParams A message from one actor to another. - * @property {string} from - The id of the actor sending the message. - * @property {string} to - The id of the actor receiving the message. - * @property {string} msg - The message text. - * @property {number} signalType - The type of signal. - * @property {"addMessage"} type - Set to `"addMessage"` if this is an `AddMessageParams`. - * @property {boolean} [activate] - If `true`, this signal starts an activation. - */ - -/** - * @param {object | object[] | AddMessageParams} param - Object of parameters. - */ -export const apply = function (param) { +type AddMessageParams = { + from: string; + to: string; + msg: string; + signalType: number; + type: + | 'addMessage' + | 'sequenceIndex' + | 'addParticipant' + | 'createParticipant' + | 'destroyParticipant' + | 'activeStart' + | 'activeEnd' + | 'addNote' + | 'addLinks' + | 'addALink' + | 'addProperties' + | 'addDetails' + | 'boxStart' + | 'boxEnd' + | 'loopStart' + | 'loopEnd' + | 'rectStart' + | 'rectEnd' + | 'optStart' + | 'optEnd' + | 'altStart' + | 'else' + | 'altEnd' + | 'setAccTitle' + | 'parStart' + | 'parAnd' + | 'parEnd' + | 'and' + | 'criticalStart' + | 'criticalOption' + | 'option' + | 'criticalEnd' + | 'breakStart' + | 'breakEnd' + | 'parOverStart' + | 'parOverEnd' + | 'parOverAnd' + | 'parOverEnd'; + + activate: boolean; +}; + +export const apply = function (param: any | AddMessageParams | AddMessageParams[]) { if (Array.isArray(param)) { param.forEach(function (item) { apply(item); From b8e0bcee5b768c8f292a632f445bf1f68073599f Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Fri, 29 Mar 2024 14:27:51 +0530 Subject: [PATCH 02/10] fix type --- packages/mermaid/src/diagrams/sequence/sequenceDb.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mermaid/src/diagrams/sequence/sequenceDb.ts b/packages/mermaid/src/diagrams/sequence/sequenceDb.ts index 7a2c3f730f..1520daf4ab 100644 --- a/packages/mermaid/src/diagrams/sequence/sequenceDb.ts +++ b/packages/mermaid/src/diagrams/sequence/sequenceDb.ts @@ -256,7 +256,7 @@ export const disableSequenceNumbers = function () { }; export const showSequenceNumbers = () => state.records.sequenceNumbersEnabled; -export const setWrap = function (wrapSetting: boolean) { +export const setWrap = function (wrapSetting?: boolean) { state.records.wrapEnabled = wrapSetting; }; From 799af4e550e05f7d2474b11539b9ae759987c660 Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Fri, 29 Mar 2024 15:05:03 +0530 Subject: [PATCH 03/10] fix test --- packages/mermaid/src/diagrams/sequence/sequenceDb.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/mermaid/src/diagrams/sequence/sequenceDb.ts b/packages/mermaid/src/diagrams/sequence/sequenceDb.ts index 1520daf4ab..8635bbb282 100644 --- a/packages/mermaid/src/diagrams/sequence/sequenceDb.ts +++ b/packages/mermaid/src/diagrams/sequence/sequenceDb.ts @@ -184,7 +184,7 @@ export const addMessage = function ( export const addSignal = function ( idFrom?: Message['from'], idTo?: Message['to'], - message?: { text: string; wrap?: boolean }, + message: { text?: string; wrap?: boolean } = { text: undefined, wrap: undefined }, messageType?: number, activate: boolean = false ) { @@ -385,10 +385,9 @@ export const addNote = function ( wrap: (message.wrap === undefined && autoWrap()) || !!message.wrap, }; - // Coerce actor into a [to, from, ...] array + //@ts-ignore: Coerce actor into a [to, from, ...] array // eslint-disable-next-line unicorn/prefer-spread - const actors = [actor, actor]; - + const actors = [].concat(actor, actor); state.records.notes.push(note); state.records.messages.push({ from: actors[0], From 2fd6de0af5cd0c04f5072d72ced4849483bf1de3 Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Fri, 29 Mar 2024 15:27:13 +0530 Subject: [PATCH 04/10] more type fixes --- .../mermaid/src/diagrams/sequence/sequenceDb.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/mermaid/src/diagrams/sequence/sequenceDb.ts b/packages/mermaid/src/diagrams/sequence/sequenceDb.ts index 8635bbb282..11a3250167 100644 --- a/packages/mermaid/src/diagrams/sequence/sequenceDb.ts +++ b/packages/mermaid/src/diagrams/sequence/sequenceDb.ts @@ -36,7 +36,7 @@ type Actor = { type Message = { from?: { actor: string }; to?: { actor: string }; - message?: + message: | string | { start: number; @@ -146,19 +146,23 @@ export const addActor = function ( state.records.prevActor = id; }; -const activationCount = (part?: string) => { +const activationCount = (part: string) => { let i; let count = 0; + if (!part) { + return 0; + } + for (i = 0; i < state.records.messages.length; i++) { if ( state.records.messages[i].type === LINETYPE.ACTIVE_START && - state.records.messages[i].from?.actor === part + state.records.messages[i].from!.actor === part ) { count++; } if ( state.records.messages[i].type === LINETYPE.ACTIVE_END && - state.records.messages[i].from?.actor === part + state.records.messages[i].from!.actor === part ) { count--; } @@ -189,7 +193,7 @@ export const addSignal = function ( activate: boolean = false ) { if (messageType === LINETYPE.ACTIVE_END) { - const cnt = activationCount(idFrom?.actor); + const cnt = activationCount(idFrom?.actor || ''); if (cnt < 1) { // Bail out as there is an activation signal from an inactive participant const error = new Error( @@ -210,7 +214,7 @@ export const addSignal = function ( state.records.messages.push({ from: idFrom, to: idTo, - message: message?.text, + message: message?.text ?? '', wrap: (message?.wrap === undefined && autoWrap()) || !!message?.wrap, type: messageType, activate, From e27e56f7bfa9e229de17d486cdc2697455069a80 Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Tue, 2 Apr 2024 10:38:04 +0530 Subject: [PATCH 05/10] use interfaces instead of types --- .../src/diagrams/sequence/sequenceDb.ts | 114 +++++++++--------- 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/packages/mermaid/src/diagrams/sequence/sequenceDb.ts b/packages/mermaid/src/diagrams/sequence/sequenceDb.ts index 11a3250167..b40add8412 100644 --- a/packages/mermaid/src/diagrams/sequence/sequenceDb.ts +++ b/packages/mermaid/src/diagrams/sequence/sequenceDb.ts @@ -12,14 +12,14 @@ import { } from '../common/commonDb.js'; import { ImperativeState } from '../../utils/imperativeState.js'; -type Box = { +interface Box { name: string; wrap: boolean; fill: string; actorKeys: string[]; -}; +} -type Actor = { +interface Actor { box?: Box; name: string; description: string; @@ -31,9 +31,9 @@ type Actor = { actorCnt: number | null; rectData: unknown; type: string; -}; +} -type Message = { +interface Message { from?: { actor: string }; to?: { actor: string }; message: @@ -48,7 +48,55 @@ type Message = { type?: number; activate?: boolean; placement?: string; -}; +} + +interface AddMessageParams { + from: string; + to: string; + msg: string; + signalType: number; + type: + | 'addMessage' + | 'sequenceIndex' + | 'addParticipant' + | 'createParticipant' + | 'destroyParticipant' + | 'activeStart' + | 'activeEnd' + | 'addNote' + | 'addLinks' + | 'addALink' + | 'addProperties' + | 'addDetails' + | 'boxStart' + | 'boxEnd' + | 'loopStart' + | 'loopEnd' + | 'rectStart' + | 'rectEnd' + | 'optStart' + | 'optEnd' + | 'altStart' + | 'else' + | 'altEnd' + | 'setAccTitle' + | 'parStart' + | 'parAnd' + | 'parEnd' + | 'and' + | 'criticalStart' + | 'criticalOption' + | 'option' + | 'criticalEnd' + | 'breakStart' + | 'breakEnd' + | 'parOverStart' + | 'parOverEnd' + | 'parOverAnd' + | 'parOverEnd'; + + activate: boolean; +} type State = { prevActor?: string; @@ -134,7 +182,7 @@ export const addActor = function ( properties: {}, actorCnt: null, rectData: null, - type: type || 'participant', + type: type ?? 'participant', }; if (state.records.prevActor && state.records.actors[state.records.prevActor]) { state.records.actors[state.records.prevActor].nextActor = id; @@ -188,7 +236,7 @@ export const addMessage = function ( export const addSignal = function ( idFrom?: Message['from'], idTo?: Message['to'], - message: { text?: string; wrap?: boolean } = { text: undefined, wrap: undefined }, + message?: { text: string; wrap: boolean }, messageType?: number, activate: boolean = false ) { @@ -423,7 +471,7 @@ export const addALink = function (actorId: string, text: { text: string }) { // find the actor const actor = getActor(actorId); try { - const links: { [key: string]: string } = {}; + const links: Record = {}; let sanitizedText = sanitizeText(text.text, getConfig()); const sep = sanitizedText.indexOf('@'); sanitizedText = sanitizedText.replace(/&/g, '&'); @@ -515,54 +563,6 @@ export const getActorProperty = function (actor: Actor, key: string) { return undefined; }; -type AddMessageParams = { - from: string; - to: string; - msg: string; - signalType: number; - type: - | 'addMessage' - | 'sequenceIndex' - | 'addParticipant' - | 'createParticipant' - | 'destroyParticipant' - | 'activeStart' - | 'activeEnd' - | 'addNote' - | 'addLinks' - | 'addALink' - | 'addProperties' - | 'addDetails' - | 'boxStart' - | 'boxEnd' - | 'loopStart' - | 'loopEnd' - | 'rectStart' - | 'rectEnd' - | 'optStart' - | 'optEnd' - | 'altStart' - | 'else' - | 'altEnd' - | 'setAccTitle' - | 'parStart' - | 'parAnd' - | 'parEnd' - | 'and' - | 'criticalStart' - | 'criticalOption' - | 'option' - | 'criticalEnd' - | 'breakStart' - | 'breakEnd' - | 'parOverStart' - | 'parOverEnd' - | 'parOverAnd' - | 'parOverEnd'; - - activate: boolean; -}; - export const apply = function (param: any | AddMessageParams | AddMessageParams[]) { if (Array.isArray(param)) { param.forEach(function (item) { From 8792e0a97871d69c0e1e68723cae5fef1508424f Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Tue, 2 Apr 2024 10:40:34 +0530 Subject: [PATCH 06/10] move types to separate file --- .../mermaid/src/diagrams/sequence/types.ts | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 packages/mermaid/src/diagrams/sequence/types.ts diff --git a/packages/mermaid/src/diagrams/sequence/types.ts b/packages/mermaid/src/diagrams/sequence/types.ts new file mode 100644 index 0000000000..83ef0fc67a --- /dev/null +++ b/packages/mermaid/src/diagrams/sequence/types.ts @@ -0,0 +1,85 @@ +export interface Box { + name: string; + wrap: boolean; + fill: string; + actorKeys: string[]; +} + +export interface Actor { + box?: Box; + name: string; + description: string; + wrap: boolean; + prevActor?: string; + nextActor?: string; + links: Record; + properties: Record; + actorCnt: number | null; + rectData: unknown; + type: string; +} + +export interface Message { + from?: { actor: string }; + to?: { actor: string }; + message: + | string + | { + start: number; + step: number; + visible: boolean; + }; + wrap: boolean; + answer?: unknown; + type?: number; + activate?: boolean; + placement?: string; +} + +export interface AddMessageParams { + from: string; + to: string; + msg: string; + signalType: number; + type: + | 'addMessage' + | 'sequenceIndex' + | 'addParticipant' + | 'createParticipant' + | 'destroyParticipant' + | 'activeStart' + | 'activeEnd' + | 'addNote' + | 'addLinks' + | 'addALink' + | 'addProperties' + | 'addDetails' + | 'boxStart' + | 'boxEnd' + | 'loopStart' + | 'loopEnd' + | 'rectStart' + | 'rectEnd' + | 'optStart' + | 'optEnd' + | 'altStart' + | 'else' + | 'altEnd' + | 'setAccTitle' + | 'parStart' + | 'parAnd' + | 'parEnd' + | 'and' + | 'criticalStart' + | 'criticalOption' + | 'option' + | 'criticalEnd' + | 'breakStart' + | 'breakEnd' + | 'parOverStart' + | 'parOverEnd' + | 'parOverAnd' + | 'parOverEnd'; + + activate: boolean; +} From 0d00e885806d0c26024b27f3a7368306f24c65e5 Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Tue, 2 Apr 2024 11:40:11 +0530 Subject: [PATCH 07/10] simplify message type from and to --- .../src/diagrams/sequence/sequenceDb.ts | 97 +------------------ .../mermaid/src/diagrams/sequence/types.ts | 4 +- 2 files changed, 7 insertions(+), 94 deletions(-) diff --git a/packages/mermaid/src/diagrams/sequence/sequenceDb.ts b/packages/mermaid/src/diagrams/sequence/sequenceDb.ts index b40add8412..80638e1807 100644 --- a/packages/mermaid/src/diagrams/sequence/sequenceDb.ts +++ b/packages/mermaid/src/diagrams/sequence/sequenceDb.ts @@ -11,92 +11,7 @@ import { setDiagramTitle, } from '../common/commonDb.js'; import { ImperativeState } from '../../utils/imperativeState.js'; - -interface Box { - name: string; - wrap: boolean; - fill: string; - actorKeys: string[]; -} - -interface Actor { - box?: Box; - name: string; - description: string; - wrap: boolean; - prevActor?: string; - nextActor?: string; - links: Record; - properties: Record; - actorCnt: number | null; - rectData: unknown; - type: string; -} - -interface Message { - from?: { actor: string }; - to?: { actor: string }; - message: - | string - | { - start: number; - step: number; - visible: boolean; - }; - wrap: boolean; - answer?: unknown; - type?: number; - activate?: boolean; - placement?: string; -} - -interface AddMessageParams { - from: string; - to: string; - msg: string; - signalType: number; - type: - | 'addMessage' - | 'sequenceIndex' - | 'addParticipant' - | 'createParticipant' - | 'destroyParticipant' - | 'activeStart' - | 'activeEnd' - | 'addNote' - | 'addLinks' - | 'addALink' - | 'addProperties' - | 'addDetails' - | 'boxStart' - | 'boxEnd' - | 'loopStart' - | 'loopEnd' - | 'rectStart' - | 'rectEnd' - | 'optStart' - | 'optEnd' - | 'altStart' - | 'else' - | 'altEnd' - | 'setAccTitle' - | 'parStart' - | 'parAnd' - | 'parEnd' - | 'and' - | 'criticalStart' - | 'criticalOption' - | 'option' - | 'criticalEnd' - | 'breakStart' - | 'breakEnd' - | 'parOverStart' - | 'parOverEnd' - | 'parOverAnd' - | 'parOverEnd'; - - activate: boolean; -} +import type { Actor, AddMessageParams, Box, Message } from './types.js'; type State = { prevActor?: string; @@ -204,13 +119,13 @@ const activationCount = (part: string) => { for (i = 0; i < state.records.messages.length; i++) { if ( state.records.messages[i].type === LINETYPE.ACTIVE_START && - state.records.messages[i].from!.actor === part + state.records.messages[i].from === part ) { count++; } if ( state.records.messages[i].type === LINETYPE.ACTIVE_END && - state.records.messages[i].from!.actor === part + state.records.messages[i].from === part ) { count--; } @@ -241,12 +156,10 @@ export const addSignal = function ( activate: boolean = false ) { if (messageType === LINETYPE.ACTIVE_END) { - const cnt = activationCount(idFrom?.actor || ''); + const cnt = activationCount(idFrom || ''); if (cnt < 1) { // Bail out as there is an activation signal from an inactive participant - const error = new Error( - 'Trying to inactivate an inactive participant (' + idFrom?.actor + ')' - ); + const error = new Error('Trying to inactivate an inactive participant (' + idFrom + ')'); // @ts-ignore: we are passing hash param to the error object, however we should define our own custom error class to make it type safe error.hash = { diff --git a/packages/mermaid/src/diagrams/sequence/types.ts b/packages/mermaid/src/diagrams/sequence/types.ts index 83ef0fc67a..b307751601 100644 --- a/packages/mermaid/src/diagrams/sequence/types.ts +++ b/packages/mermaid/src/diagrams/sequence/types.ts @@ -20,8 +20,8 @@ export interface Actor { } export interface Message { - from?: { actor: string }; - to?: { actor: string }; + from?: string; + to?: string; message: | string | { From 5d1ac22fd10f5179c1b20e7fbf1f3269c020e61a Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Fri, 5 Apr 2024 17:17:01 +0530 Subject: [PATCH 08/10] add eslint rule consistent-type-definations --- .eslintrc.cjs | 1 + packages/mermaid/src/diagrams/sequence/sequenceDb.ts | 7 ++++--- packages/mermaid/src/diagrams/sequence/types.ts | 7 +++++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index dceb314c8e..d0bb27bc9e 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -53,6 +53,7 @@ module.exports = { '@typescript-eslint/no-floating-promises': 'error', '@typescript-eslint/no-misused-promises': 'error', '@typescript-eslint/no-unused-vars': 'warn', + '@typescript-eslint/consistent-type-definitions': 'warn', '@typescript-eslint/ban-ts-comment': [ 'error', { diff --git a/packages/mermaid/src/diagrams/sequence/sequenceDb.ts b/packages/mermaid/src/diagrams/sequence/sequenceDb.ts index 80638e1807..03f095fb6e 100644 --- a/packages/mermaid/src/diagrams/sequence/sequenceDb.ts +++ b/packages/mermaid/src/diagrams/sequence/sequenceDb.ts @@ -11,8 +11,9 @@ import { setDiagramTitle, } from '../common/commonDb.js'; import { ImperativeState } from '../../utils/imperativeState.js'; -import type { Actor, AddMessageParams, Box, Message } from './types.js'; +import type { Actor, AddMessageParams, Box, Message, Note } from './types.js'; +// eslint-disable-next-line @typescript-eslint/consistent-type-definitions type State = { prevActor?: string; actors: Record; @@ -20,7 +21,7 @@ type State = { destroyedActors: Record; boxes: Box[]; messages: Message[]; - notes: unknown[]; + notes: Note[]; sequenceNumbersEnabled: boolean; wrapEnabled?: boolean; currentBox?: Box; @@ -343,7 +344,7 @@ export const addNote = function ( placement: Message['placement'], message: { text: string; wrap?: boolean } ) { - const note = { + const note: Note = { actor: actor, placement: placement, message: message.text, diff --git a/packages/mermaid/src/diagrams/sequence/types.ts b/packages/mermaid/src/diagrams/sequence/types.ts index b307751601..5cc6ae249c 100644 --- a/packages/mermaid/src/diagrams/sequence/types.ts +++ b/packages/mermaid/src/diagrams/sequence/types.ts @@ -83,3 +83,10 @@ export interface AddMessageParams { activate: boolean; } + +export interface Note { + actor: { actor: string }; + placement: Message['placement']; + message: string; + wrap: boolean; +} From 12bd301401d99cbe3036062af1095f3fec5ce4a2 Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Fri, 5 Apr 2024 17:56:56 +0530 Subject: [PATCH 09/10] revert from and to type to object --- packages/mermaid/src/diagrams/sequence/sequenceDb.ts | 10 ++++++---- packages/mermaid/src/diagrams/sequence/types.ts | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/mermaid/src/diagrams/sequence/sequenceDb.ts b/packages/mermaid/src/diagrams/sequence/sequenceDb.ts index 03f095fb6e..5d844904bc 100644 --- a/packages/mermaid/src/diagrams/sequence/sequenceDb.ts +++ b/packages/mermaid/src/diagrams/sequence/sequenceDb.ts @@ -120,13 +120,13 @@ const activationCount = (part: string) => { for (i = 0; i < state.records.messages.length; i++) { if ( state.records.messages[i].type === LINETYPE.ACTIVE_START && - state.records.messages[i].from === part + state.records.messages[i].from?.actor === part ) { count++; } if ( state.records.messages[i].type === LINETYPE.ACTIVE_END && - state.records.messages[i].from === part + state.records.messages[i].from?.actor === part ) { count--; } @@ -157,10 +157,12 @@ export const addSignal = function ( activate: boolean = false ) { if (messageType === LINETYPE.ACTIVE_END) { - const cnt = activationCount(idFrom || ''); + const cnt = activationCount(idFrom?.actor || ''); if (cnt < 1) { // 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?.actor + ')' + ); // @ts-ignore: we are passing hash param to the error object, however we should define our own custom error class to make it type safe error.hash = { diff --git a/packages/mermaid/src/diagrams/sequence/types.ts b/packages/mermaid/src/diagrams/sequence/types.ts index 5cc6ae249c..754df95e3f 100644 --- a/packages/mermaid/src/diagrams/sequence/types.ts +++ b/packages/mermaid/src/diagrams/sequence/types.ts @@ -20,8 +20,8 @@ export interface Actor { } export interface Message { - from?: string; - to?: string; + from?: { actor: string }; + to?: { actor: string }; message: | string | { From 866d9416b449376fe0e53be4c976ea9f745fb39f Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Sat, 13 Apr 2024 11:50:19 +0530 Subject: [PATCH 10/10] fix: Remove `ImperativeState` type restriction. --- packages/mermaid/src/diagrams/sequence/sequenceDb.ts | 9 ++++----- packages/mermaid/src/utils/imperativeState.ts | 6 +++--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/mermaid/src/diagrams/sequence/sequenceDb.ts b/packages/mermaid/src/diagrams/sequence/sequenceDb.ts index 5d844904bc..03d3210aa9 100644 --- a/packages/mermaid/src/diagrams/sequence/sequenceDb.ts +++ b/packages/mermaid/src/diagrams/sequence/sequenceDb.ts @@ -1,5 +1,6 @@ import { getConfig } from '../../diagram-api/diagramAPI.js'; import { log } from '../../logger.js'; +import { ImperativeState } from '../../utils/imperativeState.js'; import { sanitizeText } from '../common/common.js'; import { clear as commonClear, @@ -10,11 +11,9 @@ import { setAccTitle, setDiagramTitle, } from '../common/commonDb.js'; -import { ImperativeState } from '../../utils/imperativeState.js'; import type { Actor, AddMessageParams, Box, Message, Note } from './types.js'; -// eslint-disable-next-line @typescript-eslint/consistent-type-definitions -type State = { +interface SequenceState { prevActor?: string; actors: Record; createdActors: Record; @@ -27,9 +26,9 @@ type State = { currentBox?: Box; lastCreated?: Actor; lastDestroyed?: Actor; -}; +} -const state = new ImperativeState(() => ({ +const state = new ImperativeState(() => ({ prevActor: undefined, actors: {}, createdActors: {}, diff --git a/packages/mermaid/src/utils/imperativeState.ts b/packages/mermaid/src/utils/imperativeState.ts index dcadeee1fd..1661e356c4 100644 --- a/packages/mermaid/src/utils/imperativeState.ts +++ b/packages/mermaid/src/utils/imperativeState.ts @@ -2,11 +2,11 @@ * Resettable state storage. * @example * ``` - * const state = new ImperativeState(() => { + * const state = new ImperativeState(() => ({ * foo: undefined as string | undefined, * bar: [] as number[], * baz: 1 as number | undefined, - * }); + * })); * * state.records.foo = "hi"; * console.log(state.records.foo); // prints "hi"; @@ -21,7 +21,7 @@ * // } * ``` */ -export class ImperativeState> { +export class ImperativeState { public records: S; /**