1 | import { D as DEFAULT_STATE_TYPE, a as DIVIDER_TYPE, S as STMT_RELATION, b as STMT_STATE, c as DEFAULT_NESTED_DOC_DIR, p as parser, d as db, s as styles } from "./styles-6e15b198.js";
|
2 | import { G as Graph } from "./layout-e57aec3f.js";
|
3 | import { l as log, c as getConfig, j as select, x as utils, k as configureSvgSize, f as common } from "./mermaid-4b4b971d.js";
|
4 | import { r as render } from "./index-f7dc402e.js";
|
5 | import "./edges-a0c69811.js";
|
6 | import "./createText-b06b2794.js";
|
7 | import "./svgDraw-1b15aedc.js";
|
8 | import "./line-53c588d2.js";
|
9 | import "./array-b7dcf730.js";
|
10 | import "./constant-b644328d.js";
|
11 | const SHAPE_STATE = "rect";
|
12 | const SHAPE_STATE_WITH_DESC = "rectWithTitle";
|
13 | const SHAPE_START = "start";
|
14 | const SHAPE_END = "end";
|
15 | const SHAPE_DIVIDER = "divider";
|
16 | const SHAPE_GROUP = "roundedWithTitle";
|
17 | const SHAPE_NOTE = "note";
|
18 | const SHAPE_NOTEGROUP = "noteGroup";
|
19 | const CSS_DIAGRAM = "statediagram";
|
20 | const CSS_STATE = "state";
|
21 | const CSS_DIAGRAM_STATE = `${CSS_DIAGRAM}-${CSS_STATE}`;
|
22 | const CSS_EDGE = "transition";
|
23 | const CSS_NOTE = "note";
|
24 | const CSS_NOTE_EDGE = "note-edge";
|
25 | const CSS_EDGE_NOTE_EDGE = `${CSS_EDGE} ${CSS_NOTE_EDGE}`;
|
26 | const CSS_DIAGRAM_NOTE = `${CSS_DIAGRAM}-${CSS_NOTE}`;
|
27 | const CSS_CLUSTER = "cluster";
|
28 | const CSS_DIAGRAM_CLUSTER = `${CSS_DIAGRAM}-${CSS_CLUSTER}`;
|
29 | const CSS_CLUSTER_ALT = "cluster-alt";
|
30 | const CSS_DIAGRAM_CLUSTER_ALT = `${CSS_DIAGRAM}-${CSS_CLUSTER_ALT}`;
|
31 | const PARENT = "parent";
|
32 | const NOTE = "note";
|
33 | const DOMID_STATE = "state";
|
34 | const DOMID_TYPE_SPACER = "----";
|
35 | const NOTE_ID = `${DOMID_TYPE_SPACER}${NOTE}`;
|
36 | const PARENT_ID = `${DOMID_TYPE_SPACER}${PARENT}`;
|
37 | const G_EDGE_STYLE = "fill:none";
|
38 | const G_EDGE_ARROWHEADSTYLE = "fill: #333";
|
39 | const G_EDGE_LABELPOS = "c";
|
40 | const G_EDGE_LABELTYPE = "text";
|
41 | const G_EDGE_THICKNESS = "normal";
|
42 | let nodeDb = {};
|
43 | let graphItemCount = 0;
|
44 | const setConf = function(cnf) {
|
45 | const keys = Object.keys(cnf);
|
46 | for (const key of keys) {
|
47 | cnf[key];
|
48 | }
|
49 | };
|
50 | const getClasses = function(text, diagramObj) {
|
51 | log.trace("Extracting classes");
|
52 | diagramObj.db.clear();
|
53 | try {
|
54 | diagramObj.parser.parse(text);
|
55 | diagramObj.db.extract(diagramObj.db.getRootDocV2());
|
56 | return diagramObj.db.getClasses();
|
57 | } catch (e) {
|
58 | return e;
|
59 | }
|
60 | };
|
61 | function getClassesFromDbInfo(dbInfoItem) {
|
62 | if (dbInfoItem === void 0 || dbInfoItem === null) {
|
63 | return "";
|
64 | } else {
|
65 | if (dbInfoItem.classes) {
|
66 | return dbInfoItem.classes.join(" ");
|
67 | } else {
|
68 | return "";
|
69 | }
|
70 | }
|
71 | }
|
72 | function stateDomId(itemId = "", counter = 0, type = "", typeSpacer = DOMID_TYPE_SPACER) {
|
73 | const typeStr = type !== null && type.length > 0 ? `${typeSpacer}${type}` : "";
|
74 | return `${DOMID_STATE}-${itemId}${typeStr}-${counter}`;
|
75 | }
|
76 | const setupNode = (g, parent, parsedItem, diagramStates, diagramDb, altFlag) => {
|
77 | const itemId = parsedItem.id;
|
78 | const classStr = getClassesFromDbInfo(diagramStates[itemId]);
|
79 | if (itemId !== "root") {
|
80 | let shape = SHAPE_STATE;
|
81 | if (parsedItem.start === true) {
|
82 | shape = SHAPE_START;
|
83 | }
|
84 | if (parsedItem.start === false) {
|
85 | shape = SHAPE_END;
|
86 | }
|
87 | if (parsedItem.type !== DEFAULT_STATE_TYPE) {
|
88 | shape = parsedItem.type;
|
89 | }
|
90 | if (!nodeDb[itemId]) {
|
91 | nodeDb[itemId] = {
|
92 | id: itemId,
|
93 | shape,
|
94 | description: common.sanitizeText(itemId, getConfig()),
|
95 | classes: `${classStr} ${CSS_DIAGRAM_STATE}`
|
96 | };
|
97 | }
|
98 | const newNode = nodeDb[itemId];
|
99 | if (parsedItem.description) {
|
100 | if (Array.isArray(newNode.description)) {
|
101 | newNode.shape = SHAPE_STATE_WITH_DESC;
|
102 | newNode.description.push(parsedItem.description);
|
103 | } else {
|
104 | if (newNode.description.length > 0) {
|
105 | newNode.shape = SHAPE_STATE_WITH_DESC;
|
106 | if (newNode.description === itemId) {
|
107 | newNode.description = [parsedItem.description];
|
108 | } else {
|
109 | newNode.description = [newNode.description, parsedItem.description];
|
110 | }
|
111 | } else {
|
112 | newNode.shape = SHAPE_STATE;
|
113 | newNode.description = parsedItem.description;
|
114 | }
|
115 | }
|
116 | newNode.description = common.sanitizeTextOrArray(newNode.description, getConfig());
|
117 | }
|
118 | if (newNode.description.length === 1 && newNode.shape === SHAPE_STATE_WITH_DESC) {
|
119 | newNode.shape = SHAPE_STATE;
|
120 | }
|
121 | if (!newNode.type && parsedItem.doc) {
|
122 | log.info("Setting cluster for ", itemId, getDir(parsedItem));
|
123 | newNode.type = "group";
|
124 | newNode.dir = getDir(parsedItem);
|
125 | newNode.shape = parsedItem.type === DIVIDER_TYPE ? SHAPE_DIVIDER : SHAPE_GROUP;
|
126 | newNode.classes = newNode.classes + " " + CSS_DIAGRAM_CLUSTER + " " + (altFlag ? CSS_DIAGRAM_CLUSTER_ALT : "");
|
127 | }
|
128 | const nodeData = {
|
129 | labelStyle: "",
|
130 | shape: newNode.shape,
|
131 | labelText: newNode.description,
|
132 |
|
133 |
|
134 |
|
135 | classes: newNode.classes,
|
136 | style: "",
|
137 |
|
138 | id: itemId,
|
139 | dir: newNode.dir,
|
140 | domId: stateDomId(itemId, graphItemCount),
|
141 | type: newNode.type,
|
142 | padding: 15
|
143 |
|
144 | };
|
145 | nodeData.centerLabel = true;
|
146 | if (parsedItem.note) {
|
147 | const noteData = {
|
148 | labelStyle: "",
|
149 | shape: SHAPE_NOTE,
|
150 | labelText: parsedItem.note.text,
|
151 | classes: CSS_DIAGRAM_NOTE,
|
152 |
|
153 | style: "",
|
154 |
|
155 | id: itemId + NOTE_ID + "-" + graphItemCount,
|
156 | domId: stateDomId(itemId, graphItemCount, NOTE),
|
157 | type: newNode.type,
|
158 | padding: 15
|
159 |
|
160 | };
|
161 | const groupData = {
|
162 | labelStyle: "",
|
163 | shape: SHAPE_NOTEGROUP,
|
164 | labelText: parsedItem.note.text,
|
165 | classes: newNode.classes,
|
166 | style: "",
|
167 |
|
168 | id: itemId + PARENT_ID,
|
169 | domId: stateDomId(itemId, graphItemCount, PARENT),
|
170 | type: "group",
|
171 | padding: 0
|
172 |
|
173 | };
|
174 | graphItemCount++;
|
175 | const parentNodeId = itemId + PARENT_ID;
|
176 | g.setNode(parentNodeId, groupData);
|
177 | g.setNode(noteData.id, noteData);
|
178 | g.setNode(itemId, nodeData);
|
179 | g.setParent(itemId, parentNodeId);
|
180 | g.setParent(noteData.id, parentNodeId);
|
181 | let from = itemId;
|
182 | let to = noteData.id;
|
183 | if (parsedItem.note.position === "left of") {
|
184 | from = noteData.id;
|
185 | to = itemId;
|
186 | }
|
187 | g.setEdge(from, to, {
|
188 | arrowhead: "none",
|
189 | arrowType: "",
|
190 | style: G_EDGE_STYLE,
|
191 | labelStyle: "",
|
192 | classes: CSS_EDGE_NOTE_EDGE,
|
193 | arrowheadStyle: G_EDGE_ARROWHEADSTYLE,
|
194 | labelpos: G_EDGE_LABELPOS,
|
195 | labelType: G_EDGE_LABELTYPE,
|
196 | thickness: G_EDGE_THICKNESS
|
197 | });
|
198 | } else {
|
199 | g.setNode(itemId, nodeData);
|
200 | }
|
201 | }
|
202 | if (parent && parent.id !== "root") {
|
203 | log.trace("Setting node ", itemId, " to be child of its parent ", parent.id);
|
204 | g.setParent(itemId, parent.id);
|
205 | }
|
206 | if (parsedItem.doc) {
|
207 | log.trace("Adding nodes children ");
|
208 | setupDoc(g, parsedItem, parsedItem.doc, diagramStates, diagramDb, !altFlag);
|
209 | }
|
210 | };
|
211 | const setupDoc = (g, parentParsedItem, doc, diagramStates, diagramDb, altFlag) => {
|
212 | log.trace("items", doc);
|
213 | doc.forEach((item) => {
|
214 | switch (item.stmt) {
|
215 | case STMT_STATE:
|
216 | setupNode(g, parentParsedItem, item, diagramStates, diagramDb, altFlag);
|
217 | break;
|
218 | case DEFAULT_STATE_TYPE:
|
219 | setupNode(g, parentParsedItem, item, diagramStates, diagramDb, altFlag);
|
220 | break;
|
221 | case STMT_RELATION:
|
222 | {
|
223 | setupNode(g, parentParsedItem, item.state1, diagramStates, diagramDb, altFlag);
|
224 | setupNode(g, parentParsedItem, item.state2, diagramStates, diagramDb, altFlag);
|
225 | const edgeData = {
|
226 | id: "edge" + graphItemCount,
|
227 | arrowhead: "normal",
|
228 | arrowTypeEnd: "arrow_barb",
|
229 | style: G_EDGE_STYLE,
|
230 | labelStyle: "",
|
231 | label: common.sanitizeText(item.description, getConfig()),
|
232 | arrowheadStyle: G_EDGE_ARROWHEADSTYLE,
|
233 | labelpos: G_EDGE_LABELPOS,
|
234 | labelType: G_EDGE_LABELTYPE,
|
235 | thickness: G_EDGE_THICKNESS,
|
236 | classes: CSS_EDGE
|
237 | };
|
238 | g.setEdge(item.state1.id, item.state2.id, edgeData, graphItemCount);
|
239 | graphItemCount++;
|
240 | }
|
241 | break;
|
242 | }
|
243 | });
|
244 | };
|
245 | const getDir = (parsedItem, defaultDir = DEFAULT_NESTED_DOC_DIR) => {
|
246 | let dir = defaultDir;
|
247 | if (parsedItem.doc) {
|
248 | for (let i = 0; i < parsedItem.doc.length; i++) {
|
249 | const parsedItemDoc = parsedItem.doc[i];
|
250 | if (parsedItemDoc.stmt === "dir") {
|
251 | dir = parsedItemDoc.value;
|
252 | }
|
253 | }
|
254 | }
|
255 | return dir;
|
256 | };
|
257 | const draw = async function(text, id, _version, diag) {
|
258 | log.info("Drawing state diagram (v2)", id);
|
259 | nodeDb = {};
|
260 | diag.db.getDirection();
|
261 | const { securityLevel, state: conf } = getConfig();
|
262 | const nodeSpacing = conf.nodeSpacing || 50;
|
263 | const rankSpacing = conf.rankSpacing || 50;
|
264 | log.info(diag.db.getRootDocV2());
|
265 | diag.db.extract(diag.db.getRootDocV2());
|
266 | log.info(diag.db.getRootDocV2());
|
267 | const diagramStates = diag.db.getStates();
|
268 | const g = new Graph({
|
269 | multigraph: true,
|
270 | compound: true
|
271 | }).setGraph({
|
272 | rankdir: getDir(diag.db.getRootDocV2()),
|
273 | nodesep: nodeSpacing,
|
274 | ranksep: rankSpacing,
|
275 | marginx: 8,
|
276 | marginy: 8
|
277 | }).setDefaultEdgeLabel(function() {
|
278 | return {};
|
279 | });
|
280 | setupNode(g, void 0, diag.db.getRootDocV2(), diagramStates, diag.db, true);
|
281 | let sandboxElement;
|
282 | if (securityLevel === "sandbox") {
|
283 | sandboxElement = select("#i" + id);
|
284 | }
|
285 | const root = securityLevel === "sandbox" ? select(sandboxElement.nodes()[0].contentDocument.body) : select("body");
|
286 | const svg = root.select(`[id="${id}"]`);
|
287 | const element = root.select("#" + id + " g");
|
288 | await render(element, g, ["barb"], CSS_DIAGRAM, id);
|
289 | const padding = 8;
|
290 | utils.insertTitle(svg, "statediagramTitleText", conf.titleTopMargin, diag.db.getDiagramTitle());
|
291 | const bounds = svg.node().getBBox();
|
292 | const width = bounds.width + padding * 2;
|
293 | const height = bounds.height + padding * 2;
|
294 | svg.attr("class", CSS_DIAGRAM);
|
295 | const svgBounds = svg.node().getBBox();
|
296 | configureSvgSize(svg, height, width, conf.useMaxWidth);
|
297 | const vBox = `${svgBounds.x - padding} ${svgBounds.y - padding} ${width} ${height}`;
|
298 | log.debug(`viewBox ${vBox}`);
|
299 | svg.attr("viewBox", vBox);
|
300 | const labels = document.querySelectorAll('[id="' + id + '"] .edgeLabel .label');
|
301 | for (const label of labels) {
|
302 | const dim = label.getBBox();
|
303 | const rect = document.createElementNS("http://www.w3.org/2000/svg", SHAPE_STATE);
|
304 | rect.setAttribute("rx", 0);
|
305 | rect.setAttribute("ry", 0);
|
306 | rect.setAttribute("width", dim.width);
|
307 | rect.setAttribute("height", dim.height);
|
308 | label.insertBefore(rect, label.firstChild);
|
309 | }
|
310 | };
|
311 | const renderer = {
|
312 | setConf,
|
313 | getClasses,
|
314 | draw
|
315 | };
|
316 | const diagram = {
|
317 | parser,
|
318 | db,
|
319 | renderer,
|
320 | styles,
|
321 | init: (cnf) => {
|
322 | if (!cnf.state) {
|
323 | cnf.state = {};
|
324 | }
|
325 | cnf.state.arrowMarkerAbsolute = cnf.arrowMarkerAbsolute;
|
326 | db.clear();
|
327 | }
|
328 | };
|
329 | export {
|
330 | diagram
|
331 | };
|