diff --git a/packages/mermaid/src/diagrams/state/stateDb.js b/packages/mermaid/src/diagrams/state/stateDb.js index d0877847cf..5e82eaf78b 100644 --- a/packages/mermaid/src/diagrams/state/stateDb.js +++ b/packages/mermaid/src/diagrams/state/stateDb.js @@ -31,9 +31,20 @@ const FILL_KEYWORD = 'fill'; const BG_FILL = 'bgFill'; const STYLECLASS_SEP = ','; +/** + * Returns a new list of classes. + * In the future, this can be replaced with a class common to all diagrams. + * ClassDef information = { id: id, styles: [], textStyles: [] } + * + * @returns {{}} + */ +function newClassesList() { + return {}; +} + let direction = DEFAULT_DIAGRAM_DIRECTION; let rootDoc = []; -let classes = []; // style classes defined by a classDef +let classes = newClassesList(); // style classes defined by a classDef const newDoc = () => { return { @@ -270,11 +281,9 @@ export const clear = function (saveCommon) { }; currentDocument = documents.root; - currentDocument = documents.root; - // number of start and end nodes; used to construct ids startEndCount = 0; - classes = []; + classes = newClassesList(); if (!saveCommon) { commonClear(); } @@ -300,7 +309,7 @@ export const getRelations = function () { * else return the given id * * @param {string} id - * @returns {{id: string, type: string}} - the id and type that should be used + * @returns {string} - the id (original or constructed) */ function startIdIfNeeded(id = '') { let fixedId = id; @@ -329,7 +338,7 @@ function startTypeIfNeeded(id = '', type = DEFAULT_STATE_TYPE) { * else return the given id * * @param {string} id - * @returns {{id: string, type: string}} - the id and type that should be used + * @returns {string} - the id (original or constructed) */ function endIdIfNeeded(id = '') { let fixedId = id; @@ -442,12 +451,12 @@ const getDividerId = () => { * @example classDef my-style fill:#f96; * * @param {string} id - the id of this (style) class - * @param {string} styleAttributes - the string with 1 or more style attributes (each separated by a comma) + * @param {string | null} styleAttributes - the string with 1 or more style attributes (each separated by a comma) */ export const addStyleClass = function (id, styleAttributes = '') { // create a new style class object with this id if (typeof classes[id] === 'undefined') { - classes[id] = { id: id, styles: [], textStyles: [] }; + classes[id] = { id: id, styles: [], textStyles: [] }; // This is a classDef } const foundClass = classes[id]; if (typeof styleAttributes !== 'undefined') { diff --git a/packages/mermaid/src/diagrams/state/stateDiagram-v2.spec.js b/packages/mermaid/src/diagrams/state/stateDiagram-v2.spec.js index 39ec0f0d2c..7ed5555dba 100644 --- a/packages/mermaid/src/diagrams/state/stateDiagram-v2.spec.js +++ b/packages/mermaid/src/diagrams/state/stateDiagram-v2.spec.js @@ -3,6 +3,7 @@ import stateDb from './stateDb'; import stateDiagram from './parser/stateDiagram.jison'; describe('state diagram V2, ', function () { + // TODO - these examples should be put into ./parser/stateDiagram.spec.js describe('when parsing an info graph it', function () { beforeEach(function () { parser.yy = stateDb; diff --git a/packages/mermaid/src/diagrams/state/stateRenderer-v2.js b/packages/mermaid/src/diagrams/state/stateRenderer-v2.js index 1011fb6b13..752b70e445 100644 --- a/packages/mermaid/src/diagrams/state/stateRenderer-v2.js +++ b/packages/mermaid/src/diagrams/state/stateRenderer-v2.js @@ -58,11 +58,6 @@ const G_EDGE_LABELTYPE = 'text'; const G_EDGE_THICKNESS = 'normal'; // -------------------------------------- -// When information is parsed and processed (extracted) by stateDb.extract() -// These are globals so the information can be accessed as needed (e.g. in setUpNode, etc.) -let diagramStates = []; -let diagramClasses = []; - // List of nodes created from the parsed diagram statement items let nodeDb = {}; @@ -81,25 +76,20 @@ export const setConf = function (cnf) { }; /** - * Returns the all the styles from classDef statements in the graph definition. + * Returns the all the classdef styles (a.k.a. classes) from classDef statements in the graph definition. * * @param {string} text - the diagram text to be parsed - * @param {Diagram} diagramObj - * @returns {object} ClassDef styles + * @param diagramObj + * @returns {object} ClassDef styles (a Map with keys = strings, values = ) */ export const getClasses = function (text, diagramObj) { log.trace('Extracting classes'); - if (diagramClasses.length > 0) { - return diagramClasses; // we have already extracted the classes - } - diagramObj.db.clear(); try { // Parse the graph definition diagramObj.parser.parse(text); // must run extract() to turn the parsed statements into states, relationships, classes, etc. diagramObj.db.extract(diagramObj.db.getRootDocV2()); - return diagramObj.db.getClasses(); } catch (e) { return e; @@ -107,7 +97,7 @@ export const getClasses = function (text, diagramObj) { }; /** - * Get classes from the db info item. + * Get classes from the db for the info item. * If there aren't any or if dbInfoItem isn't defined, return an empty string. * Else create 1 string from the list of classes found * @@ -132,7 +122,7 @@ function getClassesFromDbInfo(dbInfoItem) { * * @param itemId * @param counter - * @param type + * @param {string | null} type * @param typeSpacer * @returns {string} */ @@ -147,10 +137,11 @@ export function stateDomId(itemId = '', counter = 0, type = '', typeSpacer = DOM * @param g - graph * @param {object} parent * @param {object} parsedItem - parsed statement item + * @param {object[]} diagramStates - the list of all known states for the diagram * @param {object} diagramDb * @param {boolean} altFlag - for clusters, add the "statediagram-cluster-alt" CSS class */ -const setupNode = (g, parent, parsedItem, diagramDb, altFlag) => { +const setupNode = (g, parent, parsedItem, diagramStates, diagramDb, altFlag) => { const itemId = parsedItem.id; const classStr = getClassesFromDbInfo(diagramStates[itemId]); @@ -307,7 +298,7 @@ const setupNode = (g, parent, parsedItem, diagramDb, altFlag) => { } if (parsedItem.doc) { log.trace('Adding nodes children '); - setupDoc(g, parsedItem, parsedItem.doc, diagramDb, !altFlag); + setupDoc(g, parsedItem, parsedItem.doc, diagramStates, diagramDb, !altFlag); } }; @@ -318,25 +309,26 @@ const setupNode = (g, parent, parsedItem, diagramDb, altFlag) => { * @param g * @param parentParsedItem - parsed Item that is the parent of this document (doc) * @param doc - the document to set up + * @param {object} diagramStates - the list of all known states for the diagram * @param diagramDb - * @param altFlag + * @param {boolean} altFlag * @todo This duplicates some of what is done in stateDb.js extract method */ -const setupDoc = (g, parentParsedItem, doc, diagramDb, altFlag) => { +const setupDoc = (g, parentParsedItem, doc, diagramStates, diagramDb, altFlag) => { // graphItemCount = 0; log.trace('items', doc); doc.forEach((item) => { switch (item.stmt) { case STMT_STATE: - setupNode(g, parentParsedItem, item, diagramDb, altFlag); + setupNode(g, parentParsedItem, item, diagramStates, diagramDb, altFlag); break; case DEFAULT_STATE_TYPE: - setupNode(g, parentParsedItem, item, diagramDb, altFlag); + setupNode(g, parentParsedItem, item, diagramStates, diagramDb, altFlag); break; case STMT_RELATION: { - setupNode(g, parentParsedItem, item.state1, diagramDb, altFlag); - setupNode(g, parentParsedItem, item.state2, diagramDb, altFlag); + setupNode(g, parentParsedItem, item.state1, diagramStates, diagramDb, altFlag); + setupNode(g, parentParsedItem, item.state2, diagramStates, diagramDb, altFlag); const edgeData = { id: 'edge' + graphItemCount, arrowhead: 'normal', @@ -407,8 +399,7 @@ export const draw = function (text, id, _version, diag) { diag.db.extract(diag.db.getRootDocV2()); log.info(diag.db.getRootDocV2()); - diagramStates = diag.db.getStates(); - diagramClasses = diag.db.getClasses(); + const diagramStates = diag.db.getStates(); // Create the input mermaid.graph const g = new graphlib.Graph({ @@ -426,7 +417,7 @@ export const draw = function (text, id, _version, diag) { return {}; }); - setupNode(g, undefined, diag.db.getRootDocV2(), diag.db, true); + setupNode(g, undefined, diag.db.getRootDocV2(), diagramStates, diag.db, true); // Set up an SVG group so that we can translate the final graph. let sandboxElement; diff --git a/packages/mermaid/src/diagrams/state/stateRenderer-v2.spec.js b/packages/mermaid/src/diagrams/state/stateRenderer-v2.spec.js new file mode 100644 index 0000000000..3a118e607d --- /dev/null +++ b/packages/mermaid/src/diagrams/state/stateRenderer-v2.spec.js @@ -0,0 +1,31 @@ +import { expectTypeOf } from 'vitest'; + +import { parser } from './parser/stateDiagram'; +import stateDb from './stateDb'; +import stateRendererV2 from './stateRenderer-v2'; + +// Can use this instead of having to register diagrams and load/orchestrate them, etc. +class FauxDiagramObj { + db = stateDb; + parser = parser; + renderer = stateRendererV2; + + constructor(options = { db: stateDb, parser: parser, renderer: stateRendererV2 }) { + this.db = options.db; + this.parser = options.parser; + this.renderer = options.renderer; + this.parser.yy = this.db; + } +} + +describe('stateRenderer-v2', () => { + describe('getClasses', () => { + const diagramText = 'statediagram-v2\n'; + const fauxStateDiagram = new FauxDiagramObj(); + + it('returns a {}', () => { + const result = stateRendererV2.getClasses(diagramText, fauxStateDiagram); + expectTypeOf(result).toBeObject(); + }); + }); +}); diff --git a/packages/mermaid/src/mermaidAPI.ts b/packages/mermaid/src/mermaidAPI.ts index b921655ab3..7a67c708ea 100644 --- a/packages/mermaid/src/mermaidAPI.ts +++ b/packages/mermaid/src/mermaidAPI.ts @@ -32,7 +32,7 @@ import { evaluate } from './diagrams/common/common'; import { isEmpty } from 'lodash'; // diagram names that support classDef statements -const CLASSDEF_DIAGRAMS = ['graph', 'flowchart', 'flowchart-v2', 'stateDiagram']; +const CLASSDEF_DIAGRAMS = ['graph', 'flowchart', 'flowchart-v2', 'stateDiagram', 'stateDiagram-v2']; const MAX_TEXTLENGTH_EXCEEDED_MSG = 'graph TB;a[Maximum text size in diagram exceeded];style a fill:#faa';