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