@eventcatalog/visualiser 5.0.1 → 5.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-R3QHQ7LF.mjs → chunk-JB2NMDKX.mjs} +2 -2
- package/dist/chunk-JB2NMDKX.mjs.map +1 -0
- package/dist/chunk-P2DH6CFV.mjs +1196 -0
- package/dist/chunk-P2DH6CFV.mjs.map +1 -0
- package/dist/chunk-STJQWGKW.mjs +1 -0
- package/dist/{chunk-KVTGV7VK.mjs → chunk-ZHXUMAPK.mjs} +1706 -1484
- package/dist/chunk-ZHXUMAPK.mjs.map +1 -0
- package/dist/export-mermaid-CbER9roE.d.mts +23 -0
- package/dist/{elk-layout-CpbZ6hB9.d.ts → export-mermaid-xL98eL1l.d.ts} +21 -1
- package/dist/index.d.mts +57 -41
- package/dist/index.d.ts +58 -42
- package/dist/index.js +2159 -1246
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +7 -5
- package/dist/layout.d.mts +1 -0
- package/dist/layout.d.ts +1 -1
- package/dist/layout.js +453 -0
- package/dist/layout.js.map +1 -1
- package/dist/layout.mjs +4 -2
- package/dist/model.d.mts +2 -2
- package/dist/model.mjs +1 -1
- package/dist/{schema-DKA0EQ_H.d.mts → schema-CKdQ-Ak2.d.mts} +7 -7
- package/dist/studio.d.mts +13 -3
- package/dist/studio.mjs +98 -90
- package/dist/studio.mjs.map +1 -1
- package/dist/styles-core.css +122 -120
- package/dist/styles.css +122 -120
- package/package.json +1 -2
- package/dist/chunk-KVTGV7VK.mjs.map +0 -1
- package/dist/chunk-NOHQEQD7.mjs +0 -468
- package/dist/chunk-NOHQEQD7.mjs.map +0 -1
- package/dist/chunk-Q3OM5AL5.mjs +0 -1
- package/dist/chunk-R3QHQ7LF.mjs.map +0 -1
- /package/dist/{chunk-Q3OM5AL5.mjs.map → chunk-STJQWGKW.mjs.map} +0 -0
|
@@ -0,0 +1,1196 @@
|
|
|
1
|
+
// src/nodes/node-types.ts
|
|
2
|
+
var SERVICE = ["service", "services"];
|
|
3
|
+
var AGENT = ["agent", "agents"];
|
|
4
|
+
var AGENT_TOOL = ["agentTool", "agent-tool"];
|
|
5
|
+
var EVENT = ["event", "events"];
|
|
6
|
+
var QUERY = ["queries", "query", "querie"];
|
|
7
|
+
var COMMAND = ["command", "commands"];
|
|
8
|
+
var CHANNEL = ["channel", "channels"];
|
|
9
|
+
var ACTOR = ["actor", "actors"];
|
|
10
|
+
var DATA = ["data"];
|
|
11
|
+
var VIEW = ["view"];
|
|
12
|
+
var MESSAGE = [...EVENT, ...COMMAND, ...QUERY];
|
|
13
|
+
|
|
14
|
+
// src/utils/utils/utils.ts
|
|
15
|
+
import { MarkerType, Position } from "@xyflow/react";
|
|
16
|
+
var generateIdForNode = (node) => {
|
|
17
|
+
return `${node.data.id}-${node.data.version}`;
|
|
18
|
+
};
|
|
19
|
+
var generateIdForNodes = (nodes) => {
|
|
20
|
+
return nodes.map((node) => `${node.data.id}-${node.data.version}`).join("-");
|
|
21
|
+
};
|
|
22
|
+
var generatedIdForEdge = (source, target) => {
|
|
23
|
+
return `${source.data.id}-${source.data.version}-${target.data.id}-${target.data.version}`;
|
|
24
|
+
};
|
|
25
|
+
var getColorFromString = (id) => {
|
|
26
|
+
let hash = 0;
|
|
27
|
+
for (let i = 0; i < id.length; i++) {
|
|
28
|
+
hash = id.charCodeAt(i) + ((hash << 5) - hash);
|
|
29
|
+
}
|
|
30
|
+
let color = "#";
|
|
31
|
+
for (let i = 0; i < 3; i++) {
|
|
32
|
+
const value = hash >> i * 8 & 255;
|
|
33
|
+
color += value.toString(16).padStart(2, "0");
|
|
34
|
+
}
|
|
35
|
+
return color;
|
|
36
|
+
};
|
|
37
|
+
var getEdgeLabelForServiceAsTarget = (data) => {
|
|
38
|
+
const type = data.collection;
|
|
39
|
+
switch (type) {
|
|
40
|
+
case "commands":
|
|
41
|
+
return "invokes";
|
|
42
|
+
case "events":
|
|
43
|
+
return "publishes \nevent";
|
|
44
|
+
case "queries":
|
|
45
|
+
return "requests";
|
|
46
|
+
default:
|
|
47
|
+
return "sends to";
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
var getEdgeLabelForMessageAsSource = (data, throughChannel = false) => {
|
|
51
|
+
const type = data.collection;
|
|
52
|
+
switch (type) {
|
|
53
|
+
case "commands":
|
|
54
|
+
return "accepts";
|
|
55
|
+
case "events":
|
|
56
|
+
return throughChannel ? "subscribed to" : "subscribed by";
|
|
57
|
+
case "queries":
|
|
58
|
+
return "accepts";
|
|
59
|
+
default:
|
|
60
|
+
return "sends to";
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
var getEdgeLabelSize = (label) => {
|
|
64
|
+
if (typeof label !== "string" || !label.trim())
|
|
65
|
+
return { width: 0, height: 0 };
|
|
66
|
+
const lines = label.split("\n");
|
|
67
|
+
const longestLine = Math.max(...lines.map((line) => line.trim().length));
|
|
68
|
+
return { width: longestLine * 6 + 20, height: lines.length * 14 + 12 };
|
|
69
|
+
};
|
|
70
|
+
var createEdge = (edgeOptions) => {
|
|
71
|
+
return {
|
|
72
|
+
label: "subscribed by",
|
|
73
|
+
animated: false,
|
|
74
|
+
// markerStart: {
|
|
75
|
+
// type: MarkerType.Arrow,
|
|
76
|
+
// width: 40,
|
|
77
|
+
// height: 40,
|
|
78
|
+
// },
|
|
79
|
+
markerEnd: {
|
|
80
|
+
type: MarkerType.ArrowClosed,
|
|
81
|
+
width: 40,
|
|
82
|
+
height: 40,
|
|
83
|
+
color: "rgb(var(--ec-page-text-muted))"
|
|
84
|
+
},
|
|
85
|
+
style: {
|
|
86
|
+
strokeWidth: 1.5,
|
|
87
|
+
stroke: "rgb(var(--ec-page-text-muted))",
|
|
88
|
+
strokeDasharray: "5 5"
|
|
89
|
+
},
|
|
90
|
+
...edgeOptions
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
var createNode = (values) => {
|
|
94
|
+
return {
|
|
95
|
+
sourcePosition: Position.Right,
|
|
96
|
+
targetPosition: Position.Left,
|
|
97
|
+
...values
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// src/utils/elk-layout.ts
|
|
102
|
+
var DEFAULT_SIZE = { width: 240, height: 112 };
|
|
103
|
+
var NODE_SIZES = {
|
|
104
|
+
events: { width: 240, height: 104 },
|
|
105
|
+
commands: { width: 240, height: 126 },
|
|
106
|
+
queries: { width: 240, height: 126 },
|
|
107
|
+
services: { width: 240, height: 112 },
|
|
108
|
+
data: { width: 240, height: 108 },
|
|
109
|
+
systems: { width: 240, height: 120 },
|
|
110
|
+
system: { width: 240, height: 120 },
|
|
111
|
+
"context-domain": { width: 240, height: 112 },
|
|
112
|
+
"context-actor": { width: 180, height: 80 },
|
|
113
|
+
actor: { width: 180, height: 80 },
|
|
114
|
+
note: { width: 200, height: 150 },
|
|
115
|
+
step: { width: 240, height: 80 },
|
|
116
|
+
// Groups with nothing in them (groups with children are sized to fit them)
|
|
117
|
+
"domain-group": { width: 320, height: 160 },
|
|
118
|
+
"system-group": { width: 320, height: 160 }
|
|
119
|
+
};
|
|
120
|
+
var GROUP_TYPES = /* @__PURE__ */ new Set(["domain-group", "system-group", "group"]);
|
|
121
|
+
var getNodeSize = (node) => {
|
|
122
|
+
if (node.measured?.width && node.measured?.height) {
|
|
123
|
+
return { width: node.measured.width, height: node.measured.height };
|
|
124
|
+
}
|
|
125
|
+
if (typeof node.width === "number" && typeof node.height === "number") {
|
|
126
|
+
return { width: node.width, height: node.height };
|
|
127
|
+
}
|
|
128
|
+
if (node.type === "domains" || node.type === "domain") {
|
|
129
|
+
const services = node.data?.domain?.data?.services || [];
|
|
130
|
+
return { width: 260, height: 60 + services.length * 40 };
|
|
131
|
+
}
|
|
132
|
+
return NODE_SIZES[node.type || ""] ?? DEFAULT_SIZE;
|
|
133
|
+
};
|
|
134
|
+
var GROUP_PADDING = "[top=100,left=40,bottom=40,right=40]";
|
|
135
|
+
var SPACING = {
|
|
136
|
+
"elk.layered.spacing.nodeNodeBetweenLayers": "60",
|
|
137
|
+
"elk.spacing.nodeNode": "40",
|
|
138
|
+
"elk.spacing.edgeNode": "25",
|
|
139
|
+
"elk.spacing.edgeEdge": "15"
|
|
140
|
+
};
|
|
141
|
+
var LARGE_GRAPH_NODES = 80;
|
|
142
|
+
var LARGE_GRAPH_EDGES = 200;
|
|
143
|
+
var LARGE_GRAPH_OPTIONS = {
|
|
144
|
+
"elk.layered.nodePlacement.strategy": "BRANDES_KOEPF",
|
|
145
|
+
"elk.layered.thoroughness": "1",
|
|
146
|
+
"elk.layered.crossingMinimization.greedySwitch.type": "OFF"
|
|
147
|
+
};
|
|
148
|
+
var elk;
|
|
149
|
+
var getElk = async () => {
|
|
150
|
+
if (!elk) {
|
|
151
|
+
const { default: ELK } = await import("elkjs/lib/elk.bundled.js");
|
|
152
|
+
elk = new ELK();
|
|
153
|
+
}
|
|
154
|
+
return elk;
|
|
155
|
+
};
|
|
156
|
+
var layoutWithElk = async ({ nodes, edges }, { sizeOf = getNodeSize } = {}) => {
|
|
157
|
+
const nodesById = new Map(nodes.map((node) => [node.id, node]));
|
|
158
|
+
const groupIds = new Set(
|
|
159
|
+
nodes.map((node) => node.parentId).filter((id) => !!id && nodesById.has(id))
|
|
160
|
+
);
|
|
161
|
+
const parentOf = (node) => node.parentId && groupIds.has(node.parentId) ? node.parentId : void 0;
|
|
162
|
+
const layoutEdges = edges.filter(
|
|
163
|
+
(edge) => nodesById.has(edge.source) && nodesById.has(edge.target)
|
|
164
|
+
);
|
|
165
|
+
const ports = /* @__PURE__ */ new Map();
|
|
166
|
+
const addPort = (nodeId, id, side) => {
|
|
167
|
+
const nodePorts = ports.get(nodeId) || [];
|
|
168
|
+
if (!nodePorts.some((port) => port.id === id)) {
|
|
169
|
+
ports.set(nodeId, [
|
|
170
|
+
...nodePorts,
|
|
171
|
+
{ id, layoutOptions: { "elk.port.side": side } }
|
|
172
|
+
]);
|
|
173
|
+
}
|
|
174
|
+
return id;
|
|
175
|
+
};
|
|
176
|
+
const edgePorts = layoutEdges.map((edge, index) => ({
|
|
177
|
+
source: addPort(
|
|
178
|
+
edge.source,
|
|
179
|
+
edge.sourceHandle ? `${edge.source}__${edge.sourceHandle}` : `e${index}__out`,
|
|
180
|
+
"EAST"
|
|
181
|
+
),
|
|
182
|
+
target: addPort(
|
|
183
|
+
edge.target,
|
|
184
|
+
edge.targetHandle ? `${edge.target}__${edge.targetHandle}` : `e${index}__in`,
|
|
185
|
+
"WEST"
|
|
186
|
+
)
|
|
187
|
+
}));
|
|
188
|
+
const toElkNode = (node) => ({
|
|
189
|
+
id: node.id,
|
|
190
|
+
...groupIds.has(node.id) ? {
|
|
191
|
+
children: nodes.filter((child) => parentOf(child) === node.id).map(toElkNode)
|
|
192
|
+
} : sizeOf(node),
|
|
193
|
+
layoutOptions: {
|
|
194
|
+
"elk.portConstraints": "FIXED_SIDE",
|
|
195
|
+
...groupIds.has(node.id) ? { "elk.padding": GROUP_PADDING, ...SPACING } : {},
|
|
196
|
+
// A node's own options (e.g. a group's padding) win
|
|
197
|
+
...node.data?.layoutOptions ?? {}
|
|
198
|
+
},
|
|
199
|
+
ports: ports.get(node.id) || []
|
|
200
|
+
});
|
|
201
|
+
const layout = await (await getElk()).layout({
|
|
202
|
+
id: "root",
|
|
203
|
+
layoutOptions: {
|
|
204
|
+
"elk.algorithm": "layered",
|
|
205
|
+
"elk.direction": "RIGHT",
|
|
206
|
+
"elk.hierarchyHandling": "INCLUDE_CHILDREN",
|
|
207
|
+
"elk.edgeRouting": "ORTHOGONAL",
|
|
208
|
+
// Edge routes in absolute coordinates (node positions stay relative to their parent)
|
|
209
|
+
"elk.json.edgeCoords": "ROOT",
|
|
210
|
+
"elk.edgeLabels.placement": "CENTER",
|
|
211
|
+
...SPACING,
|
|
212
|
+
...nodes.length >= LARGE_GRAPH_NODES || edges.length >= LARGE_GRAPH_EDGES ? LARGE_GRAPH_OPTIONS : { "elk.layered.nodePlacement.strategy": "NETWORK_SIMPLEX" }
|
|
213
|
+
},
|
|
214
|
+
children: nodes.filter((node) => !parentOf(node)).map(toElkNode),
|
|
215
|
+
edges: layoutEdges.map((edge, index) => ({
|
|
216
|
+
id: `e${index}`,
|
|
217
|
+
sources: [edgePorts[index].source],
|
|
218
|
+
targets: [edgePorts[index].target],
|
|
219
|
+
// Labels sit on their edge, rather than beside it (only works set per label)
|
|
220
|
+
labels: edge.label ? [
|
|
221
|
+
{
|
|
222
|
+
text: String(edge.label),
|
|
223
|
+
...getEdgeLabelSize(edge.label),
|
|
224
|
+
layoutOptions: { "elk.edgeLabels.inline": "true" }
|
|
225
|
+
}
|
|
226
|
+
] : []
|
|
227
|
+
}))
|
|
228
|
+
});
|
|
229
|
+
const laidOut = /* @__PURE__ */ new Map();
|
|
230
|
+
const collect = (elkNode) => (elkNode.children || []).forEach((child) => {
|
|
231
|
+
laidOut.set(child.id, child);
|
|
232
|
+
collect(child);
|
|
233
|
+
});
|
|
234
|
+
collect(layout);
|
|
235
|
+
const absolute = (nodeId) => {
|
|
236
|
+
const node = nodesById.get(nodeId);
|
|
237
|
+
const parent = node && parentOf(node);
|
|
238
|
+
const offset = parent ? absolute(parent) : { x: 0, y: 0 };
|
|
239
|
+
const elkNode = laidOut.get(nodeId);
|
|
240
|
+
return { x: offset.x + (elkNode?.x ?? 0), y: offset.y + (elkNode?.y ?? 0) };
|
|
241
|
+
};
|
|
242
|
+
const laidOutAt = (nodeId) => ({
|
|
243
|
+
...absolute(nodeId),
|
|
244
|
+
height: laidOut.get(nodeId)?.height
|
|
245
|
+
});
|
|
246
|
+
const routes = /* @__PURE__ */ new Map();
|
|
247
|
+
(layout.edges || []).forEach((elkEdge) => {
|
|
248
|
+
const section = elkEdge.sections?.[0];
|
|
249
|
+
if (!section) return;
|
|
250
|
+
const label = elkEdge.labels?.[0];
|
|
251
|
+
const edge = layoutEdges[Number(elkEdge.id.slice(1))];
|
|
252
|
+
routes.set(edge, {
|
|
253
|
+
points: [
|
|
254
|
+
section.startPoint,
|
|
255
|
+
...section.bendPoints || [],
|
|
256
|
+
section.endPoint
|
|
257
|
+
],
|
|
258
|
+
label: label ? {
|
|
259
|
+
x: (label.x ?? 0) + (label.width ?? 0) / 2,
|
|
260
|
+
y: (label.y ?? 0) + (label.height ?? 0) / 2
|
|
261
|
+
} : void 0,
|
|
262
|
+
source: laidOutAt(edge.source),
|
|
263
|
+
target: laidOutAt(edge.target)
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
const depth = (node) => {
|
|
267
|
+
const parent = node && parentOf(node);
|
|
268
|
+
return parent ? depth(nodesById.get(parent)) + 1 : 0;
|
|
269
|
+
};
|
|
270
|
+
return {
|
|
271
|
+
// Parents must come before their children in the array for React Flow
|
|
272
|
+
nodes: [...nodes].sort((a, b) => depth(a) - depth(b)).map((node) => {
|
|
273
|
+
const elkNode = laidOut.get(node.id);
|
|
274
|
+
if (!elkNode) return node;
|
|
275
|
+
return {
|
|
276
|
+
...node,
|
|
277
|
+
origin: [0, 0],
|
|
278
|
+
position: { x: elkNode.x ?? 0, y: elkNode.y ?? 0 },
|
|
279
|
+
...groupIds.has(node.id) || GROUP_TYPES.has(node.type || "") && typeof node.style?.width !== "number" ? {
|
|
280
|
+
style: {
|
|
281
|
+
...node.style,
|
|
282
|
+
width: elkNode.width,
|
|
283
|
+
height: elkNode.height
|
|
284
|
+
},
|
|
285
|
+
// Re-measured at its new size
|
|
286
|
+
measured: void 0
|
|
287
|
+
} : {}
|
|
288
|
+
};
|
|
289
|
+
}),
|
|
290
|
+
edges: edges.map((edge) => {
|
|
291
|
+
const route = routes.get(edge);
|
|
292
|
+
return route ? { ...edge, data: { ...edge.data, route } } : edge;
|
|
293
|
+
})
|
|
294
|
+
};
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
// src/utils/swimlanes.ts
|
|
298
|
+
var SWIMLANE_NODE_TYPE = "swimlane";
|
|
299
|
+
var FLOW_GROUP_BYS = [
|
|
300
|
+
"domain",
|
|
301
|
+
"system",
|
|
302
|
+
"team",
|
|
303
|
+
"domain-system"
|
|
304
|
+
];
|
|
305
|
+
var isFlowGroupBy = (value) => FLOW_GROUP_BYS.includes(value);
|
|
306
|
+
var isFlowGroupStyle = (value) => value === "lanes" || value === "boxes";
|
|
307
|
+
var SWIMLANE_GROUP_BY_LABELS = {
|
|
308
|
+
domain: "Domain",
|
|
309
|
+
system: "System",
|
|
310
|
+
team: "Team",
|
|
311
|
+
"domain-system": "Domain, then system"
|
|
312
|
+
};
|
|
313
|
+
var EXTERNAL_LANE = "__external";
|
|
314
|
+
var UNASSIGNED_LANE = "__unassigned";
|
|
315
|
+
var LANE_HEADER_WIDTH = 96;
|
|
316
|
+
var LANE_PADDING = { x: 48, y: 48 };
|
|
317
|
+
var ROW_GAP = 32;
|
|
318
|
+
var COLUMN_GAP = 24;
|
|
319
|
+
var LANE_LABEL = { fontSize: 20, iconSize: 20, gap: 10 };
|
|
320
|
+
var LANE_LABEL_PADDING = 40;
|
|
321
|
+
var labelLength = (label) => LANE_LABEL.iconSize + LANE_LABEL.gap + label.length * LANE_LABEL.fontSize * 0.62;
|
|
322
|
+
var lanesOf = (node) => node.data?.lanes;
|
|
323
|
+
var isSwimlaneNode = (node) => node.type === SWIMLANE_NODE_TYPE;
|
|
324
|
+
var hasSwimlanes = (nodes, groupBy) => groupBy === "domain-system" ? hasSwimlanes(nodes, "domain") && hasSwimlanes(nodes, "system") : nodes.some((node) => !!lanesOf(node)?.[groupBy]);
|
|
325
|
+
var countGroups = (nodes, groupBy) => {
|
|
326
|
+
const level = groupBy === "domain-system" ? "domain" : groupBy;
|
|
327
|
+
return new Set(
|
|
328
|
+
nodes.map((node) => lanesOf(node)?.[level]?.id).filter(Boolean)
|
|
329
|
+
).size;
|
|
330
|
+
};
|
|
331
|
+
var assignLanes = (nodes, edges, groupBy) => {
|
|
332
|
+
const laneOf = /* @__PURE__ */ new Map();
|
|
333
|
+
const names = /* @__PURE__ */ new Map();
|
|
334
|
+
nodes.forEach((node) => {
|
|
335
|
+
const lanes = lanesOf(node);
|
|
336
|
+
const lane = lanes?.[groupBy];
|
|
337
|
+
if (lane) {
|
|
338
|
+
laneOf.set(node.id, lane.id);
|
|
339
|
+
names.set(lane.id, lane.name);
|
|
340
|
+
} else if (lanes?.external) {
|
|
341
|
+
laneOf.set(node.id, EXTERNAL_LANE);
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
const ids = new Set(nodes.map((node) => node.id));
|
|
345
|
+
const ownLanes = new Set(
|
|
346
|
+
nodes.filter((node) => lanesOf(node)).map((node) => node.id)
|
|
347
|
+
);
|
|
348
|
+
const links = edges.filter(
|
|
349
|
+
(edge) => ids.has(edge.source) && ids.has(edge.target)
|
|
350
|
+
);
|
|
351
|
+
const inherit = (from, to) => {
|
|
352
|
+
let changed = true;
|
|
353
|
+
while (changed) {
|
|
354
|
+
changed = false;
|
|
355
|
+
links.forEach((edge) => {
|
|
356
|
+
const lane = laneOf.get(edge[from]);
|
|
357
|
+
if (lane && !laneOf.has(edge[to]) && !ownLanes.has(edge[to])) {
|
|
358
|
+
laneOf.set(edge[to], lane);
|
|
359
|
+
changed = true;
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
inherit("source", "target");
|
|
365
|
+
inherit("target", "source");
|
|
366
|
+
nodes.forEach((node) => {
|
|
367
|
+
if (!laneOf.has(node.id)) laneOf.set(node.id, UNASSIGNED_LANE);
|
|
368
|
+
});
|
|
369
|
+
return { laneOf, names };
|
|
370
|
+
};
|
|
371
|
+
var layoutSwimlanes = ({ nodes, edges }, groupBy, { sizeOf = getNodeSize } = {}) => {
|
|
372
|
+
const topLevel = nodes.filter((node) => !node.parentId);
|
|
373
|
+
if (topLevel.length === 0) return { nodes, edges };
|
|
374
|
+
const { laneOf, names } = assignLanes(topLevel, edges, groupBy);
|
|
375
|
+
const boxes = new Map(
|
|
376
|
+
topLevel.map((node) => [node.id, { ...node.position, ...sizeOf(node) }])
|
|
377
|
+
);
|
|
378
|
+
const order = (lane) => lane === EXTERNAL_LANE ? -Infinity : lane === UNASSIGNED_LANE ? Infinity : Math.min(
|
|
379
|
+
...topLevel.filter((node) => laneOf.get(node.id) === lane).map((node) => boxes.get(node.id).x)
|
|
380
|
+
);
|
|
381
|
+
const lanes = [...new Set(laneOf.values())].sort(
|
|
382
|
+
(a, b) => order(a) - order(b)
|
|
383
|
+
);
|
|
384
|
+
const minX = Math.min(...[...boxes.values()].map((box) => box.x));
|
|
385
|
+
const maxX = Math.max(...[...boxes.values()].map((box) => box.x + box.width));
|
|
386
|
+
const laneX = minX - LANE_HEADER_WIDTH - LANE_PADDING.x;
|
|
387
|
+
const laneWidth = maxX - laneX + LANE_PADDING.x;
|
|
388
|
+
const laneNodes = [];
|
|
389
|
+
const positions = /* @__PURE__ */ new Map();
|
|
390
|
+
let laneY = 0;
|
|
391
|
+
lanes.forEach((lane, index) => {
|
|
392
|
+
const members = topLevel.filter((node) => laneOf.get(node.id) === lane).sort((a, b) => boxes.get(a.id).y - boxes.get(b.id).y);
|
|
393
|
+
const rows = [];
|
|
394
|
+
const rowOf = /* @__PURE__ */ new Map();
|
|
395
|
+
members.forEach((node) => {
|
|
396
|
+
const box = boxes.get(node.id);
|
|
397
|
+
const overlaps = (other) => box.x < other.x + other.width + COLUMN_GAP && other.x < box.x + box.width + COLUMN_GAP;
|
|
398
|
+
let row = rows.findIndex((r) => !r.boxes.some(overlaps));
|
|
399
|
+
if (row === -1) {
|
|
400
|
+
rows.push({ boxes: [], height: 0 });
|
|
401
|
+
row = rows.length - 1;
|
|
402
|
+
}
|
|
403
|
+
rows[row].boxes.push(box);
|
|
404
|
+
rows[row].height = Math.max(rows[row].height, box.height);
|
|
405
|
+
rowOf.set(node.id, row);
|
|
406
|
+
});
|
|
407
|
+
const label = lane === EXTERNAL_LANE ? "External" : lane === UNASSIGNED_LANE ? `No ${SWIMLANE_GROUP_BY_LABELS[groupBy].toLowerCase()}` : names.get(lane) ?? lane;
|
|
408
|
+
const rowsHeight = rows.reduce((total, row) => total + row.height, 0) + ROW_GAP * (rows.length - 1);
|
|
409
|
+
const laneHeight = Math.max(
|
|
410
|
+
rowsHeight + LANE_PADDING.y * 2,
|
|
411
|
+
labelLength(label) + LANE_LABEL_PADDING * 2
|
|
412
|
+
);
|
|
413
|
+
const rowTops = [];
|
|
414
|
+
let rowY = (laneHeight - rowsHeight) / 2;
|
|
415
|
+
rows.forEach((row) => {
|
|
416
|
+
rowTops.push(rowY);
|
|
417
|
+
rowY += row.height + ROW_GAP;
|
|
418
|
+
});
|
|
419
|
+
const laneId = `swimlane-${lane}`;
|
|
420
|
+
members.forEach((node) => {
|
|
421
|
+
const box = boxes.get(node.id);
|
|
422
|
+
const row = rowOf.get(node.id);
|
|
423
|
+
positions.set(node.id, {
|
|
424
|
+
x: box.x - laneX,
|
|
425
|
+
// Centred in its row
|
|
426
|
+
y: rowTops[row] + (rows[row].height - box.height) / 2
|
|
427
|
+
});
|
|
428
|
+
});
|
|
429
|
+
laneNodes.push({
|
|
430
|
+
id: laneId,
|
|
431
|
+
type: SWIMLANE_NODE_TYPE,
|
|
432
|
+
position: { x: laneX, y: laneY },
|
|
433
|
+
origin: [0, 0],
|
|
434
|
+
style: { width: laneWidth, height: laneHeight },
|
|
435
|
+
draggable: false,
|
|
436
|
+
selectable: false,
|
|
437
|
+
focusable: false,
|
|
438
|
+
data: {
|
|
439
|
+
label,
|
|
440
|
+
groupBy,
|
|
441
|
+
level: groupBy,
|
|
442
|
+
style: "lanes",
|
|
443
|
+
kind: lane === EXTERNAL_LANE ? "external" : lane === UNASSIGNED_LANE ? "unassigned" : "lane",
|
|
444
|
+
index
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
laneY += laneHeight;
|
|
448
|
+
});
|
|
449
|
+
return {
|
|
450
|
+
// Lanes come before their nodes, as React Flow needs parents first
|
|
451
|
+
nodes: [
|
|
452
|
+
...laneNodes,
|
|
453
|
+
...nodes.map((node) => {
|
|
454
|
+
const position = positions.get(node.id);
|
|
455
|
+
if (!position) return node;
|
|
456
|
+
return {
|
|
457
|
+
...node,
|
|
458
|
+
parentId: `swimlane-${laneOf.get(node.id)}`,
|
|
459
|
+
origin: [0, 0],
|
|
460
|
+
position
|
|
461
|
+
};
|
|
462
|
+
})
|
|
463
|
+
],
|
|
464
|
+
edges: edges.map((edge) => {
|
|
465
|
+
if (!edge.data?.route) return edge;
|
|
466
|
+
const { route: _route, ...data } = edge.data;
|
|
467
|
+
return { ...edge, data };
|
|
468
|
+
})
|
|
469
|
+
};
|
|
470
|
+
};
|
|
471
|
+
var getGrouping = (nodes) => {
|
|
472
|
+
const data = nodes.find(isSwimlaneNode)?.data;
|
|
473
|
+
return data ? { groupBy: data.groupBy, style: data.style } : null;
|
|
474
|
+
};
|
|
475
|
+
var removeSwimlanes = ({
|
|
476
|
+
nodes,
|
|
477
|
+
edges
|
|
478
|
+
}) => {
|
|
479
|
+
const groups = new Map(
|
|
480
|
+
nodes.filter(isSwimlaneNode).map((group) => [group.id, group])
|
|
481
|
+
);
|
|
482
|
+
if (groups.size === 0) return { nodes, edges };
|
|
483
|
+
const offset = (id) => {
|
|
484
|
+
const group = id ? groups.get(id) : void 0;
|
|
485
|
+
if (!group) return { x: 0, y: 0 };
|
|
486
|
+
const parent = offset(group.parentId);
|
|
487
|
+
return { x: parent.x + group.position.x, y: parent.y + group.position.y };
|
|
488
|
+
};
|
|
489
|
+
return {
|
|
490
|
+
nodes: nodes.filter((node) => !groups.has(node.id)).map((node) => {
|
|
491
|
+
if (!node.parentId || !groups.has(node.parentId)) return node;
|
|
492
|
+
const { parentId, ...rest } = node;
|
|
493
|
+
const at = offset(parentId);
|
|
494
|
+
return {
|
|
495
|
+
...rest,
|
|
496
|
+
position: { x: at.x + node.position.x, y: at.y + node.position.y }
|
|
497
|
+
};
|
|
498
|
+
}),
|
|
499
|
+
edges
|
|
500
|
+
};
|
|
501
|
+
};
|
|
502
|
+
var BOX_PADDING = 40;
|
|
503
|
+
var groupIntoBoxes = async ({ nodes, edges }, groupBy, { sizeOf = getNodeSize } = {}) => {
|
|
504
|
+
const topLevel = nodes.filter((node) => !node.parentId);
|
|
505
|
+
const levels = groupBy === "domain-system" ? ["domain", "system"] : [groupBy];
|
|
506
|
+
const assignments = levels.map(
|
|
507
|
+
(level) => assignLanes(topLevel, edges, level)
|
|
508
|
+
);
|
|
509
|
+
const groups = /* @__PURE__ */ new Map();
|
|
510
|
+
const parentOf = /* @__PURE__ */ new Map();
|
|
511
|
+
topLevel.forEach((node) => {
|
|
512
|
+
let parentId;
|
|
513
|
+
assignments.forEach(({ laneOf, names }, depth) => {
|
|
514
|
+
const lane = laneOf.get(node.id);
|
|
515
|
+
if (lane === UNASSIGNED_LANE || depth > 0 && lane === EXTERNAL_LANE)
|
|
516
|
+
return;
|
|
517
|
+
const level = levels[depth];
|
|
518
|
+
const id = `${parentId ?? "swimlane"}__${level}-${lane}`;
|
|
519
|
+
if (!groups.has(id)) {
|
|
520
|
+
const label = lane === EXTERNAL_LANE ? "External" : names.get(lane) ?? lane;
|
|
521
|
+
const minHeight = labelLength(label) + LANE_LABEL_PADDING * 2;
|
|
522
|
+
groups.set(id, {
|
|
523
|
+
id,
|
|
524
|
+
type: SWIMLANE_NODE_TYPE,
|
|
525
|
+
...parentId && { parentId },
|
|
526
|
+
position: { x: 0, y: 0 },
|
|
527
|
+
selectable: false,
|
|
528
|
+
focusable: false,
|
|
529
|
+
data: {
|
|
530
|
+
label,
|
|
531
|
+
groupBy,
|
|
532
|
+
level,
|
|
533
|
+
style: "boxes",
|
|
534
|
+
kind: lane === EXTERNAL_LANE ? "external" : "lane",
|
|
535
|
+
index: groups.size,
|
|
536
|
+
// Room for its name on the left, and at least as tall as it
|
|
537
|
+
layoutOptions: {
|
|
538
|
+
"elk.padding": `[top=${BOX_PADDING},left=${LANE_HEADER_WIDTH + BOX_PADDING},bottom=${BOX_PADDING},right=${BOX_PADDING}]`,
|
|
539
|
+
"elk.nodeSize.constraints": "MINIMUM_SIZE",
|
|
540
|
+
"elk.nodeSize.minimum": `(0, ${Math.ceil(minHeight)})`
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
parentId = id;
|
|
546
|
+
});
|
|
547
|
+
if (parentId) parentOf.set(node.id, parentId);
|
|
548
|
+
});
|
|
549
|
+
return layoutWithElk(
|
|
550
|
+
{
|
|
551
|
+
nodes: [
|
|
552
|
+
...groups.values(),
|
|
553
|
+
...nodes.map((node) => {
|
|
554
|
+
const parentId = parentOf.get(node.id);
|
|
555
|
+
return parentId ? { ...node, parentId } : node;
|
|
556
|
+
})
|
|
557
|
+
],
|
|
558
|
+
edges
|
|
559
|
+
},
|
|
560
|
+
{ sizeOf }
|
|
561
|
+
);
|
|
562
|
+
};
|
|
563
|
+
|
|
564
|
+
// src/utils/export-mermaid.ts
|
|
565
|
+
var NODE_SHAPE_MAP = {
|
|
566
|
+
agents: ["[[", "]]"],
|
|
567
|
+
agent: ["[[", "]]"],
|
|
568
|
+
agentTool: ["[", "]"],
|
|
569
|
+
"agent-tool": ["[", "]"],
|
|
570
|
+
services: ["[[", "]]"],
|
|
571
|
+
// stadium shape
|
|
572
|
+
service: ["[[", "]]"],
|
|
573
|
+
events: [">", "]"],
|
|
574
|
+
// flag/asymmetric shape (message-like)
|
|
575
|
+
event: [">", "]"],
|
|
576
|
+
commands: [">", "]"],
|
|
577
|
+
// flag/asymmetric shape (message-like)
|
|
578
|
+
command: [">", "]"],
|
|
579
|
+
queries: ["{{", "}}"],
|
|
580
|
+
// hexagon
|
|
581
|
+
query: ["{{", "}}"],
|
|
582
|
+
// Parallelogram: what messages pass through, not a cylinder, which reads as
|
|
583
|
+
// a database (and is what data stores are drawn as)
|
|
584
|
+
channels: ["[/", "/]"],
|
|
585
|
+
channel: ["[/", "/]"],
|
|
586
|
+
domains: ["[", "]"],
|
|
587
|
+
// rectangle
|
|
588
|
+
domain: ["[", "]"],
|
|
589
|
+
"context-domain": ["[", "]"],
|
|
590
|
+
// another domain, shown as a single card
|
|
591
|
+
flows: ["([", "])"],
|
|
592
|
+
// stadium (rounded)
|
|
593
|
+
flow: ["([", "])"],
|
|
594
|
+
flowExpanded: ["([", "])"],
|
|
595
|
+
systems: ["[[", "]]"],
|
|
596
|
+
// a system shown as a single node
|
|
597
|
+
system: ["[[", "]]"],
|
|
598
|
+
step: ["[", "]"],
|
|
599
|
+
// rectangle
|
|
600
|
+
user: ["((", "))"],
|
|
601
|
+
// circle
|
|
602
|
+
actor: ["((", "))"],
|
|
603
|
+
// circle
|
|
604
|
+
"context-actor": ["((", "))"],
|
|
605
|
+
// circle
|
|
606
|
+
externalSystem: ["[[", "]]"],
|
|
607
|
+
// stadium
|
|
608
|
+
"external-system": ["[[", "]]"],
|
|
609
|
+
data: ["[(", ")]"],
|
|
610
|
+
// cylinder (database)
|
|
611
|
+
container: ["[(", ")]"],
|
|
612
|
+
"data-product": ["[[", "]]"],
|
|
613
|
+
// stadium
|
|
614
|
+
"data-products": ["[[", "]]"],
|
|
615
|
+
entities: ["[", "]"],
|
|
616
|
+
// rectangle
|
|
617
|
+
entity: ["[", "]"],
|
|
618
|
+
custom: ["[", "]"],
|
|
619
|
+
// rectangle
|
|
620
|
+
view: ["[", "]"],
|
|
621
|
+
// rectangle
|
|
622
|
+
note: ["[", "]"],
|
|
623
|
+
// rectangle
|
|
624
|
+
field: ["[(", ")]"],
|
|
625
|
+
// cylinder
|
|
626
|
+
fields: ["[(", ")]"],
|
|
627
|
+
// cylinder
|
|
628
|
+
messageGroup: ["[[", "]]"],
|
|
629
|
+
messageGroupExpanded: ["[[", "]]"]
|
|
630
|
+
};
|
|
631
|
+
var NODE_STYLE_CLASSES = {
|
|
632
|
+
agents: "fill:#0ea5e9,stroke:#0369a1,color:#fff",
|
|
633
|
+
agent: "fill:#0ea5e9,stroke:#0369a1,color:#fff",
|
|
634
|
+
agentTool: "fill:#8b5cf6,stroke:#6d28d9,color:#fff",
|
|
635
|
+
"agent-tool": "fill:#8b5cf6,stroke:#6d28d9,color:#fff",
|
|
636
|
+
services: "fill:#ec4899,stroke:#be185d,color:#fff",
|
|
637
|
+
service: "fill:#ec4899,stroke:#be185d,color:#fff",
|
|
638
|
+
events: "fill:#f97316,stroke:#c2410c,color:#fff",
|
|
639
|
+
event: "fill:#f97316,stroke:#c2410c,color:#fff",
|
|
640
|
+
commands: "fill:#3b82f6,stroke:#1d4ed8,color:#fff",
|
|
641
|
+
command: "fill:#3b82f6,stroke:#1d4ed8,color:#fff",
|
|
642
|
+
queries: "fill:#22c55e,stroke:#15803d,color:#fff",
|
|
643
|
+
query: "fill:#22c55e,stroke:#15803d,color:#fff",
|
|
644
|
+
channels: "fill:#6b7280,stroke:#374151,color:#fff",
|
|
645
|
+
channel: "fill:#6b7280,stroke:#374151,color:#fff",
|
|
646
|
+
domains: "fill:#eab308,stroke:#a16207,color:#000",
|
|
647
|
+
domain: "fill:#eab308,stroke:#a16207,color:#000",
|
|
648
|
+
"context-domain": "fill:#eab308,stroke:#a16207,color:#000",
|
|
649
|
+
flows: "fill:#14b8a6,stroke:#0f766e,color:#fff",
|
|
650
|
+
flow: "fill:#14b8a6,stroke:#0f766e,color:#fff",
|
|
651
|
+
flowExpanded: "fill:#14b8a6,stroke:#0f766e,color:#fff",
|
|
652
|
+
systems: "fill:#8b5cf6,stroke:#6d28d9,color:#fff",
|
|
653
|
+
system: "fill:#8b5cf6,stroke:#6d28d9,color:#fff",
|
|
654
|
+
step: "fill:#374151,stroke:#1f2937,color:#fff",
|
|
655
|
+
user: "fill:#8b5cf6,stroke:#6d28d9,color:#fff",
|
|
656
|
+
actor: "fill:#eab308,stroke:#a16207,color:#000",
|
|
657
|
+
"context-actor": "fill:#eab308,stroke:#a16207,color:#000",
|
|
658
|
+
// yellow, as actors are on the diagram
|
|
659
|
+
externalSystem: "fill:#ec4899,stroke:#be185d,color:#fff",
|
|
660
|
+
"external-system": "fill:#ec4899,stroke:#be185d,color:#fff",
|
|
661
|
+
data: "fill:#3b82f6,stroke:#1d4ed8,color:#fff",
|
|
662
|
+
container: "fill:#3b82f6,stroke:#1d4ed8,color:#fff",
|
|
663
|
+
"data-product": "fill:#6366f1,stroke:#4338ca,color:#fff",
|
|
664
|
+
"data-products": "fill:#6366f1,stroke:#4338ca,color:#fff",
|
|
665
|
+
entities: "fill:#6b7280,stroke:#374151,color:#fff",
|
|
666
|
+
entity: "fill:#6b7280,stroke:#374151,color:#fff",
|
|
667
|
+
custom: "fill:#9ca3af,stroke:#6b7280,color:#000",
|
|
668
|
+
view: "fill:#9ca3af,stroke:#6b7280,color:#000",
|
|
669
|
+
note: "fill:#fef3c7,stroke:#d97706,color:#000",
|
|
670
|
+
field: "fill:#06b6d4,stroke:#0891b2,color:#fff",
|
|
671
|
+
fields: "fill:#06b6d4,stroke:#0891b2,color:#fff",
|
|
672
|
+
messageGroup: "fill:#7c3aed,stroke:#5b21b6,color:#fff",
|
|
673
|
+
messageGroupExpanded: "fill:#7c3aed,stroke:#5b21b6,color:#fff"
|
|
674
|
+
};
|
|
675
|
+
var GROUP_NODE_TYPES = /* @__PURE__ */ new Set(["system-group", "domain-group", "group"]);
|
|
676
|
+
var GROUP_STYLE_CLASSES = {
|
|
677
|
+
domainGroup: "fill:#eab30814,stroke:#ca8a04,stroke-width:2px,stroke-dasharray:6 4,color:#a16207",
|
|
678
|
+
subdomainGroup: "fill:#eab3080d,stroke:#ca8a04,stroke-dasharray:4 4,color:#a16207",
|
|
679
|
+
otherDomainGroup: "fill:#9ca3af14,stroke:#9ca3af,stroke-dasharray:4 4,color:#6b7280",
|
|
680
|
+
systemGroup: "fill:#8b5cf614,stroke:#8b5cf6,stroke-width:2px,color:#7c3aed",
|
|
681
|
+
laneGroup: "fill:#9ca3af0d,stroke:#9ca3af,stroke-dasharray:4 4,color:#6b7280"
|
|
682
|
+
};
|
|
683
|
+
var FOCUSED_STYLE = "stroke-width:4px";
|
|
684
|
+
var CROSS_DOMAIN_LINK_STYLE = "stroke:#4f46e5,stroke-width:3px";
|
|
685
|
+
var RESERVED_IDS = /* @__PURE__ */ new Set([
|
|
686
|
+
"end",
|
|
687
|
+
"subgraph",
|
|
688
|
+
"graph",
|
|
689
|
+
"flowchart",
|
|
690
|
+
"style",
|
|
691
|
+
"class",
|
|
692
|
+
"classdef",
|
|
693
|
+
"click",
|
|
694
|
+
"linkstyle",
|
|
695
|
+
"call",
|
|
696
|
+
"href"
|
|
697
|
+
]);
|
|
698
|
+
function sanitizeMermaidId(id) {
|
|
699
|
+
const sanitized = id.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
700
|
+
return RESERVED_IDS.has(sanitized.toLowerCase()) ? `node_${sanitized}` : sanitized;
|
|
701
|
+
}
|
|
702
|
+
function normaliseLines(label) {
|
|
703
|
+
return label.split("\n").map((line) => line.replace(/\s+/g, " ").trim()).filter(Boolean);
|
|
704
|
+
}
|
|
705
|
+
function escapeMermaidLabel(label) {
|
|
706
|
+
return label.replace(/#/g, "#35;").replace(/"/g, "#quot;");
|
|
707
|
+
}
|
|
708
|
+
function getMermaidNodeShape(type) {
|
|
709
|
+
return NODE_SHAPE_MAP[type] || ["[", "]"];
|
|
710
|
+
}
|
|
711
|
+
function formatLabelWithVersion(name, version) {
|
|
712
|
+
if (version) {
|
|
713
|
+
return `${name} (${version})`;
|
|
714
|
+
}
|
|
715
|
+
return name;
|
|
716
|
+
}
|
|
717
|
+
function resourceLabel(resource, fallback) {
|
|
718
|
+
const name = resource?.name || resource?.data?.name || resource?.id || resource?.data?.id;
|
|
719
|
+
const version = resource?.version || resource?.data?.version;
|
|
720
|
+
return formatLabelWithVersion(name || fallback, version);
|
|
721
|
+
}
|
|
722
|
+
function getNodeLabel(node) {
|
|
723
|
+
const { type } = node;
|
|
724
|
+
const data = node.data;
|
|
725
|
+
if (!data) return node.id;
|
|
726
|
+
if (type === "agents" || type === "agent") {
|
|
727
|
+
return resourceLabel(data.agent, node.id);
|
|
728
|
+
}
|
|
729
|
+
if (type === "agentTool" || type === "agent-tool") {
|
|
730
|
+
const agentTool = data.agentTool;
|
|
731
|
+
return agentTool?.name || agentTool?.id || node.id;
|
|
732
|
+
}
|
|
733
|
+
if (type === "services" || type === "service") {
|
|
734
|
+
return resourceLabel(data.service, node.id);
|
|
735
|
+
}
|
|
736
|
+
if (type === "events" || type === "event" || type === "commands" || type === "command" || type === "queries" || type === "query") {
|
|
737
|
+
return resourceLabel(data.message, node.id);
|
|
738
|
+
}
|
|
739
|
+
if (type === "channels" || type === "channel") {
|
|
740
|
+
return resourceLabel(data.channel, node.id);
|
|
741
|
+
}
|
|
742
|
+
if (type === "domains" || type === "domain" || type === "context-domain" || type === "domain-group" || type === "group") {
|
|
743
|
+
return resourceLabel(data.domain, node.id);
|
|
744
|
+
}
|
|
745
|
+
if (type === "systems" || type === "system" || type === "system-group") {
|
|
746
|
+
return resourceLabel(data.system, node.id);
|
|
747
|
+
}
|
|
748
|
+
if (type === "flows" || type === "flow") {
|
|
749
|
+
return resourceLabel(data.flow, node.id);
|
|
750
|
+
}
|
|
751
|
+
if (type === "flowExpanded") {
|
|
752
|
+
return formatLabelWithVersion(data.flowName || node.id, data.version);
|
|
753
|
+
}
|
|
754
|
+
if (type === "step") {
|
|
755
|
+
const step = data.step;
|
|
756
|
+
return step?.title || step?.name || step?.id || node.id;
|
|
757
|
+
}
|
|
758
|
+
if (type === "custom") {
|
|
759
|
+
return data.custom?.title || data.step?.title || data.label || node.id;
|
|
760
|
+
}
|
|
761
|
+
if (type === "externalSystem" || type === "external-system") {
|
|
762
|
+
const system = data.externalSystem || data;
|
|
763
|
+
return system?.name || system?.id || node.id;
|
|
764
|
+
}
|
|
765
|
+
if (type === "data" || type === "container") {
|
|
766
|
+
const dataNode = data.data;
|
|
767
|
+
return dataNode?.name || dataNode?.id || node.id;
|
|
768
|
+
}
|
|
769
|
+
if (type === "data-product" || type === "data-products") {
|
|
770
|
+
return resourceLabel(data.dataProduct, node.id);
|
|
771
|
+
}
|
|
772
|
+
if (type === "entities" || type === "entity") {
|
|
773
|
+
const entity = data.entity;
|
|
774
|
+
return entity?.name || entity?.id || node.id;
|
|
775
|
+
}
|
|
776
|
+
if (type === "view") {
|
|
777
|
+
return data.view?.name || data.view?.id || node.id;
|
|
778
|
+
}
|
|
779
|
+
if (type === "note") {
|
|
780
|
+
return data.text || data.label || "Note";
|
|
781
|
+
}
|
|
782
|
+
if (type === "field" || type === "fields") {
|
|
783
|
+
const name = data.name || node.id;
|
|
784
|
+
return data.type ? `${name} (${data.type})` : name;
|
|
785
|
+
}
|
|
786
|
+
if (type === "messageGroup" || type === "messageGroupExpanded") {
|
|
787
|
+
const groupName = data.groupName || node.id;
|
|
788
|
+
const count = data.messageCount || 0;
|
|
789
|
+
return `${groupName} (${count} messages)`;
|
|
790
|
+
}
|
|
791
|
+
return data.name || data.label || data.title || data.id || node.id;
|
|
792
|
+
}
|
|
793
|
+
function getEdgeLabel(edge) {
|
|
794
|
+
if (edge.label && typeof edge.label === "string") {
|
|
795
|
+
return edge.label;
|
|
796
|
+
}
|
|
797
|
+
if (edge.data?.label && typeof edge.data.label === "string") {
|
|
798
|
+
return edge.data.label;
|
|
799
|
+
}
|
|
800
|
+
return void 0;
|
|
801
|
+
}
|
|
802
|
+
function getMermaidIds(nodes) {
|
|
803
|
+
const mermaidIds = /* @__PURE__ */ new Map();
|
|
804
|
+
const usedIds = /* @__PURE__ */ new Set();
|
|
805
|
+
nodes.forEach((node) => {
|
|
806
|
+
const base = sanitizeMermaidId(node.id);
|
|
807
|
+
let id = base;
|
|
808
|
+
for (let n = 2; usedIds.has(id); n++) id = `${base}_${n}`;
|
|
809
|
+
usedIds.add(id);
|
|
810
|
+
mermaidIds.set(node.id, id);
|
|
811
|
+
});
|
|
812
|
+
return mermaidIds;
|
|
813
|
+
}
|
|
814
|
+
var isEntityNode = (node) => node.type === "entities" || node.type === "entity";
|
|
815
|
+
var CARDINALITY_RELATIONS = /* @__PURE__ */ new Set([
|
|
816
|
+
"hasOne",
|
|
817
|
+
"hasMany",
|
|
818
|
+
"belongsTo",
|
|
819
|
+
"references"
|
|
820
|
+
]);
|
|
821
|
+
var ENTITY_STYLE_CLASSES = {
|
|
822
|
+
externalEntity: "fill:#9ca3af1a,stroke:#9ca3af,stroke-dasharray:4 4",
|
|
823
|
+
aggregateRoot: "stroke-width:3px"
|
|
824
|
+
};
|
|
825
|
+
function sanitizeErToken(value, fallback) {
|
|
826
|
+
const token = value.trim().replace(/[^A-Za-z0-9_\-[\]().]/g, "_");
|
|
827
|
+
return /^[A-Za-z_]/.test(token) ? token : `${fallback}_${token}`;
|
|
828
|
+
}
|
|
829
|
+
function getErCardinality(property) {
|
|
830
|
+
const required = !!property.required;
|
|
831
|
+
if (property.relationType === "hasMany" || property.type === "array") {
|
|
832
|
+
return required ? "||--|{" : "||--o{";
|
|
833
|
+
}
|
|
834
|
+
if (property.relationType === "hasOne") {
|
|
835
|
+
return required ? "||--||" : "||--o|";
|
|
836
|
+
}
|
|
837
|
+
return required ? "}o--||" : "}o--o|";
|
|
838
|
+
}
|
|
839
|
+
function convertEntitiesToMermaid(nodes, edges, { includeStyles = true } = {}) {
|
|
840
|
+
const mermaidIds = getMermaidIds(nodes);
|
|
841
|
+
const lines = ["erDiagram"];
|
|
842
|
+
const classes = /* @__PURE__ */ new Map();
|
|
843
|
+
const addClass = (name, id) => classes.set(name, [...classes.get(name) ?? [], id]);
|
|
844
|
+
nodes.forEach((node) => {
|
|
845
|
+
const data = node.data;
|
|
846
|
+
const entity = data?.entity?.data ?? {};
|
|
847
|
+
const id = mermaidIds.get(node.id);
|
|
848
|
+
const name = entity.name || data?.label || node.id;
|
|
849
|
+
const label = data?.externalToDomain && data?.domainName ? `${name} (${data.domainName})` : name;
|
|
850
|
+
const references = new Set(data?.referencePropertyNames ?? []);
|
|
851
|
+
const properties = entity.properties ?? [];
|
|
852
|
+
const attributes = properties.map((property) => {
|
|
853
|
+
const type = property.type === "array" && property.items?.type ? `${property.items.type}[]` : property.type || "unknown";
|
|
854
|
+
const keys = [
|
|
855
|
+
property.name === entity.identifier && "PK",
|
|
856
|
+
(property.references || references.has(property.name)) && "FK"
|
|
857
|
+
].filter(Boolean);
|
|
858
|
+
return ` ${sanitizeErToken(type, "t")} ${sanitizeErToken(property.name, "p")}${keys.length ? ` ${keys.join(", ")}` : ""}`;
|
|
859
|
+
});
|
|
860
|
+
const definition = ` ${id}["${escapeMermaidLabel(label)}"]`;
|
|
861
|
+
lines.push(
|
|
862
|
+
...attributes.length ? [`${definition} {`, ...attributes, " }"] : [definition]
|
|
863
|
+
);
|
|
864
|
+
if (data?.externalToDomain) addClass("externalEntity", id);
|
|
865
|
+
if (entity.aggregateRoot) addClass("aggregateRoot", id);
|
|
866
|
+
});
|
|
867
|
+
const nodesById = new Map(nodes.map((node) => [node.id, node]));
|
|
868
|
+
const relationships = edges.filter(
|
|
869
|
+
(edge) => !edge.hidden && mermaidIds.has(edge.source) && mermaidIds.has(edge.target)
|
|
870
|
+
).map((edge) => {
|
|
871
|
+
const propertyName = edge.sourceHandle?.replace(/-source$/, "");
|
|
872
|
+
const properties = nodesById.get(edge.source)?.data?.entity?.data?.properties ?? [];
|
|
873
|
+
const property = properties.find((p) => p.name === propertyName);
|
|
874
|
+
const relation = property?.relationType?.trim();
|
|
875
|
+
const label = relation && !CARDINALITY_RELATIONS.has(relation) ? relation : propertyName || getEdgeLabel(edge) || "references";
|
|
876
|
+
const cardinality = property ? getErCardinality(property) : "}o--o|";
|
|
877
|
+
return ` ${mermaidIds.get(edge.source)} ${cardinality} ${mermaidIds.get(edge.target)} : "${escapeMermaidLabel(label)}"`;
|
|
878
|
+
});
|
|
879
|
+
if (relationships.length > 0) lines.push("", ...relationships);
|
|
880
|
+
if (includeStyles && classes.size > 0) {
|
|
881
|
+
lines.push("");
|
|
882
|
+
classes.forEach((ids, name) => {
|
|
883
|
+
lines.push(` classDef ${name} ${ENTITY_STYLE_CLASSES[name]}`);
|
|
884
|
+
lines.push(` class ${ids.join(",")} ${name}`);
|
|
885
|
+
});
|
|
886
|
+
}
|
|
887
|
+
return lines.join("\n");
|
|
888
|
+
}
|
|
889
|
+
function getGroupClass(node) {
|
|
890
|
+
const data = node.data;
|
|
891
|
+
if (isSwimlaneNode(node)) return "laneGroup";
|
|
892
|
+
if (node.type === "system-group") return "systemGroup";
|
|
893
|
+
if (data?.otherDomain) return "otherDomainGroup";
|
|
894
|
+
if (data?.subdomain) return "subdomainGroup";
|
|
895
|
+
return "domainGroup";
|
|
896
|
+
}
|
|
897
|
+
var isCrossDomain = (edge) => !!edge.data?.crossDomain;
|
|
898
|
+
function convertToMermaid(graphNodes, graphEdges, options = {}) {
|
|
899
|
+
const { includeStyles = true, direction = "LR" } = options;
|
|
900
|
+
const nodes = graphNodes.filter((node) => !node.hidden);
|
|
901
|
+
if (nodes.length > 0 && nodes.every(isEntityNode)) {
|
|
902
|
+
return convertEntitiesToMermaid(nodes, graphEdges, { includeStyles });
|
|
903
|
+
}
|
|
904
|
+
const mermaidIds = getMermaidIds(nodes);
|
|
905
|
+
const lines = [];
|
|
906
|
+
lines.push(`flowchart ${direction}`);
|
|
907
|
+
const childrenOf = /* @__PURE__ */ new Map();
|
|
908
|
+
const topLevelNodes = [];
|
|
909
|
+
nodes.forEach((node) => {
|
|
910
|
+
if (node.parentId && mermaidIds.has(node.parentId)) {
|
|
911
|
+
childrenOf.set(node.parentId, [
|
|
912
|
+
...childrenOf.get(node.parentId) ?? [],
|
|
913
|
+
node
|
|
914
|
+
]);
|
|
915
|
+
} else {
|
|
916
|
+
topLevelNodes.push(node);
|
|
917
|
+
}
|
|
918
|
+
});
|
|
919
|
+
const isGroup = (node) => childrenOf.has(node.id) || GROUP_NODE_TYPES.has(node.type ?? "") || isSwimlaneNode(node);
|
|
920
|
+
const usedTypes = /* @__PURE__ */ new Set();
|
|
921
|
+
const groupsByClass = /* @__PURE__ */ new Map();
|
|
922
|
+
const focusedIds = [];
|
|
923
|
+
nodes.forEach((node) => {
|
|
924
|
+
const id = mermaidIds.get(node.id);
|
|
925
|
+
if (isGroup(node)) {
|
|
926
|
+
const groupClass = getGroupClass(node);
|
|
927
|
+
groupsByClass.set(groupClass, [
|
|
928
|
+
...groupsByClass.get(groupClass) ?? [],
|
|
929
|
+
id
|
|
930
|
+
]);
|
|
931
|
+
return;
|
|
932
|
+
}
|
|
933
|
+
if (node.type && NODE_STYLE_CLASSES[node.type]) usedTypes.add(node.type);
|
|
934
|
+
if (node.data?.isFocused) focusedIds.push(id);
|
|
935
|
+
});
|
|
936
|
+
if (includeStyles) {
|
|
937
|
+
lines.push("");
|
|
938
|
+
lines.push(" %% Style definitions");
|
|
939
|
+
usedTypes.forEach((type) => {
|
|
940
|
+
lines.push(
|
|
941
|
+
` classDef ${sanitizeMermaidId(type)} ${NODE_STYLE_CLASSES[type]}`
|
|
942
|
+
);
|
|
943
|
+
});
|
|
944
|
+
groupsByClass.forEach((_, groupClass) => {
|
|
945
|
+
lines.push(
|
|
946
|
+
` classDef ${groupClass} ${GROUP_STYLE_CLASSES[groupClass]}`
|
|
947
|
+
);
|
|
948
|
+
});
|
|
949
|
+
if (focusedIds.length > 0) {
|
|
950
|
+
lines.push(` classDef focused ${FOCUSED_STYLE}`);
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
lines.push("");
|
|
954
|
+
lines.push(" %% Nodes");
|
|
955
|
+
const addNode = (node, depth) => {
|
|
956
|
+
const indent = " ".repeat(depth);
|
|
957
|
+
const id = mermaidIds.get(node.id);
|
|
958
|
+
const label = escapeMermaidLabel(
|
|
959
|
+
normaliseLines(getNodeLabel(node)).join("<br/>")
|
|
960
|
+
);
|
|
961
|
+
if (isGroup(node)) {
|
|
962
|
+
lines.push(`${indent}subgraph ${id}["${label}"]`);
|
|
963
|
+
childrenOf.get(node.id)?.forEach((child) => addNode(child, depth + 1));
|
|
964
|
+
lines.push(`${indent}end`);
|
|
965
|
+
return;
|
|
966
|
+
}
|
|
967
|
+
const [prefix, suffix] = getMermaidNodeShape(node.type || "custom");
|
|
968
|
+
let nodeLine = `${indent}${id}${prefix}"${label}"${suffix}`;
|
|
969
|
+
if (includeStyles && node.type && usedTypes.has(node.type)) {
|
|
970
|
+
nodeLine += `:::${sanitizeMermaidId(node.type)}`;
|
|
971
|
+
}
|
|
972
|
+
lines.push(nodeLine);
|
|
973
|
+
};
|
|
974
|
+
topLevelNodes.forEach((node) => addNode(node, 1));
|
|
975
|
+
lines.push("");
|
|
976
|
+
lines.push(" %% Edges");
|
|
977
|
+
const crossDomainLinks = [];
|
|
978
|
+
graphEdges.filter(
|
|
979
|
+
(edge) => !edge.hidden && mermaidIds.has(edge.source) && mermaidIds.has(edge.target)
|
|
980
|
+
).forEach((edge, index) => {
|
|
981
|
+
const sourceId = mermaidIds.get(edge.source);
|
|
982
|
+
const targetId = mermaidIds.get(edge.target);
|
|
983
|
+
const label = normaliseLines(getEdgeLabel(edge) ?? "").join(" ");
|
|
984
|
+
lines.push(
|
|
985
|
+
label ? ` ${sourceId} -->|"${escapeMermaidLabel(label)}"| ${targetId}` : ` ${sourceId} --> ${targetId}`
|
|
986
|
+
);
|
|
987
|
+
if (isCrossDomain(edge)) crossDomainLinks.push(index);
|
|
988
|
+
});
|
|
989
|
+
if (includeStyles) {
|
|
990
|
+
const styleLines = [];
|
|
991
|
+
groupsByClass.forEach((ids, groupClass) => {
|
|
992
|
+
styleLines.push(` class ${ids.join(",")} ${groupClass}`);
|
|
993
|
+
});
|
|
994
|
+
if (focusedIds.length > 0) {
|
|
995
|
+
styleLines.push(` class ${focusedIds.join(",")} focused`);
|
|
996
|
+
}
|
|
997
|
+
if (crossDomainLinks.length > 0) {
|
|
998
|
+
styleLines.push(
|
|
999
|
+
` linkStyle ${crossDomainLinks.join(",")} ${CROSS_DOMAIN_LINK_STYLE}`
|
|
1000
|
+
);
|
|
1001
|
+
}
|
|
1002
|
+
if (styleLines.length > 0) {
|
|
1003
|
+
lines.push("");
|
|
1004
|
+
lines.push(" %% Boundaries and highlights");
|
|
1005
|
+
lines.push(...styleLines);
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
return lines.join("\n");
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
// src/utils/hide-messages.ts
|
|
1012
|
+
import { MarkerType as MarkerType2 } from "@xyflow/react";
|
|
1013
|
+
var MESSAGE_NODE_TYPES = [...MESSAGE, "messageGroup", "messageGroupExpanded"];
|
|
1014
|
+
var isMessageNode = (node) => MESSAGE_NODE_TYPES.includes(node.type || "");
|
|
1015
|
+
var getCollection = (type = "") => {
|
|
1016
|
+
if (EVENT.includes(type)) return "events";
|
|
1017
|
+
if (COMMAND.includes(type)) return "commands";
|
|
1018
|
+
if (QUERY.includes(type)) return "queries";
|
|
1019
|
+
return "messages";
|
|
1020
|
+
};
|
|
1021
|
+
var getMessages = (node) => {
|
|
1022
|
+
const data = node.data;
|
|
1023
|
+
if (node.type === "messageGroup") {
|
|
1024
|
+
return (data?.messages || []).map(({ message: message2 }) => [
|
|
1025
|
+
message2?.data?.name || message2?.data?.id,
|
|
1026
|
+
getCollection(message2?.collection)
|
|
1027
|
+
]);
|
|
1028
|
+
}
|
|
1029
|
+
const message = data?.message;
|
|
1030
|
+
return message ? [[message.name || message.id, getCollection(node.type)]] : [];
|
|
1031
|
+
};
|
|
1032
|
+
var VERBS = {
|
|
1033
|
+
events: "publishes",
|
|
1034
|
+
commands: "invokes",
|
|
1035
|
+
queries: "requests"
|
|
1036
|
+
};
|
|
1037
|
+
var getMessagesLabel = (messages) => {
|
|
1038
|
+
if (messages.size === 0) return void 0;
|
|
1039
|
+
const collections = new Set(messages.values());
|
|
1040
|
+
const collection = collections.size === 1 ? Array.from(collections)[0] : "messages";
|
|
1041
|
+
const verb = VERBS[collection] || "sends";
|
|
1042
|
+
const sent = messages.size === 1 ? Array.from(messages.keys())[0] : `${messages.size} ${collection}`;
|
|
1043
|
+
return `${verb}
|
|
1044
|
+
${sent}`;
|
|
1045
|
+
};
|
|
1046
|
+
var isCarrier = (node) => isMessageNode(node) || node.type === "channels";
|
|
1047
|
+
var isCrossDomain2 = (edge) => !!edge.data?.crossDomain;
|
|
1048
|
+
var getRoute = (edge) => edge.data?.route;
|
|
1049
|
+
var joinRoutes = (routes) => {
|
|
1050
|
+
if (!routes.every((route) => route && route.points.length > 0)) return;
|
|
1051
|
+
const laidOut = routes;
|
|
1052
|
+
const arrives = laidOut[0].points[laidOut[0].points.length - 1];
|
|
1053
|
+
const leaves = laidOut[1].points[0];
|
|
1054
|
+
return {
|
|
1055
|
+
points: laidOut.flatMap((route) => route.points),
|
|
1056
|
+
label: { x: (arrives.x + leaves.x) / 2, y: (arrives.y + leaves.y) / 2 },
|
|
1057
|
+
source: laidOut[0].source,
|
|
1058
|
+
target: laidOut[laidOut.length - 1].target
|
|
1059
|
+
};
|
|
1060
|
+
};
|
|
1061
|
+
var hideNodes = (nodes, edges, isHidden) => {
|
|
1062
|
+
const hiddenNodes = new Map(
|
|
1063
|
+
nodes.filter(isHidden).map((node) => [node.id, node])
|
|
1064
|
+
);
|
|
1065
|
+
if (hiddenNodes.size === 0) return { nodes, edges };
|
|
1066
|
+
const outgoingEdges = /* @__PURE__ */ new Map();
|
|
1067
|
+
for (const edge of edges) {
|
|
1068
|
+
const outgoing = outgoingEdges.get(edge.source) || [];
|
|
1069
|
+
outgoing.push(edge);
|
|
1070
|
+
outgoingEdges.set(edge.source, outgoing);
|
|
1071
|
+
}
|
|
1072
|
+
const keptEdges = [];
|
|
1073
|
+
const bridgedEdges = /* @__PURE__ */ new Map();
|
|
1074
|
+
for (const edge of edges) {
|
|
1075
|
+
if (hiddenNodes.has(edge.source)) continue;
|
|
1076
|
+
const target = hiddenNodes.get(edge.target);
|
|
1077
|
+
if (!target) {
|
|
1078
|
+
keptEdges.push(edge);
|
|
1079
|
+
continue;
|
|
1080
|
+
}
|
|
1081
|
+
if (!isCarrier(target)) continue;
|
|
1082
|
+
const stack = [
|
|
1083
|
+
{
|
|
1084
|
+
id: edge.target,
|
|
1085
|
+
messages: [],
|
|
1086
|
+
routes: [getRoute(edge)],
|
|
1087
|
+
crossDomain: isCrossDomain2(edge)
|
|
1088
|
+
}
|
|
1089
|
+
];
|
|
1090
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1091
|
+
while (stack.length > 0) {
|
|
1092
|
+
const current = stack.pop();
|
|
1093
|
+
if (visited.has(current.id)) continue;
|
|
1094
|
+
visited.add(current.id);
|
|
1095
|
+
const messages = [
|
|
1096
|
+
...current.messages,
|
|
1097
|
+
...getMessages(hiddenNodes.get(current.id))
|
|
1098
|
+
];
|
|
1099
|
+
for (const next of outgoingEdges.get(current.id) || []) {
|
|
1100
|
+
const routes = [...current.routes, getRoute(next)];
|
|
1101
|
+
const crossDomain = current.crossDomain || isCrossDomain2(next);
|
|
1102
|
+
const nextNode = hiddenNodes.get(next.target);
|
|
1103
|
+
if (nextNode) {
|
|
1104
|
+
if (isCarrier(nextNode))
|
|
1105
|
+
stack.push({ id: next.target, messages, routes, crossDomain });
|
|
1106
|
+
continue;
|
|
1107
|
+
}
|
|
1108
|
+
if (next.target === edge.source) continue;
|
|
1109
|
+
const id = `bridged-${edge.source}-${next.target}`;
|
|
1110
|
+
const bridged = bridgedEdges.get(id) || {
|
|
1111
|
+
source: edge.source,
|
|
1112
|
+
target: next.target,
|
|
1113
|
+
messages: /* @__PURE__ */ new Map(),
|
|
1114
|
+
route: joinRoutes(routes),
|
|
1115
|
+
crossDomain: false
|
|
1116
|
+
};
|
|
1117
|
+
bridged.crossDomain || (bridged.crossDomain = crossDomain);
|
|
1118
|
+
messages.forEach(
|
|
1119
|
+
([name, collection]) => bridged.messages.set(name, collection)
|
|
1120
|
+
);
|
|
1121
|
+
bridgedEdges.set(id, bridged);
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
const newEdges = Array.from(
|
|
1126
|
+
bridgedEdges,
|
|
1127
|
+
([id, bridged]) => createEdge({
|
|
1128
|
+
id,
|
|
1129
|
+
source: bridged.source,
|
|
1130
|
+
target: bridged.target,
|
|
1131
|
+
label: getMessagesLabel(bridged.messages),
|
|
1132
|
+
// The same size arrow as the rest of the graph's edges
|
|
1133
|
+
markerEnd: {
|
|
1134
|
+
type: MarkerType2.ArrowClosed,
|
|
1135
|
+
width: 20,
|
|
1136
|
+
height: 20,
|
|
1137
|
+
color: "rgb(var(--ec-page-text-muted))"
|
|
1138
|
+
},
|
|
1139
|
+
// Along the same route, and crossing domains if any edge it replaces did
|
|
1140
|
+
data: {
|
|
1141
|
+
...bridged.route ? { route: bridged.route } : {},
|
|
1142
|
+
...bridged.crossDomain ? { crossDomain: true } : {}
|
|
1143
|
+
}
|
|
1144
|
+
})
|
|
1145
|
+
);
|
|
1146
|
+
return {
|
|
1147
|
+
nodes: nodes.filter((node) => !hiddenNodes.has(node.id)),
|
|
1148
|
+
edges: [...keptEdges, ...newEdges]
|
|
1149
|
+
};
|
|
1150
|
+
};
|
|
1151
|
+
var hideMessageNodes = (nodes, edges) => hideNodes(nodes, edges, isCarrier);
|
|
1152
|
+
|
|
1153
|
+
export {
|
|
1154
|
+
SERVICE,
|
|
1155
|
+
AGENT,
|
|
1156
|
+
AGENT_TOOL,
|
|
1157
|
+
EVENT,
|
|
1158
|
+
QUERY,
|
|
1159
|
+
COMMAND,
|
|
1160
|
+
CHANNEL,
|
|
1161
|
+
ACTOR,
|
|
1162
|
+
DATA,
|
|
1163
|
+
VIEW,
|
|
1164
|
+
MESSAGE,
|
|
1165
|
+
generateIdForNode,
|
|
1166
|
+
generateIdForNodes,
|
|
1167
|
+
generatedIdForEdge,
|
|
1168
|
+
getColorFromString,
|
|
1169
|
+
getEdgeLabelForServiceAsTarget,
|
|
1170
|
+
getEdgeLabelForMessageAsSource,
|
|
1171
|
+
getEdgeLabelSize,
|
|
1172
|
+
createEdge,
|
|
1173
|
+
createNode,
|
|
1174
|
+
getNodeSize,
|
|
1175
|
+
layoutWithElk,
|
|
1176
|
+
FLOW_GROUP_BYS,
|
|
1177
|
+
isFlowGroupBy,
|
|
1178
|
+
isFlowGroupStyle,
|
|
1179
|
+
SWIMLANE_GROUP_BY_LABELS,
|
|
1180
|
+
LANE_HEADER_WIDTH,
|
|
1181
|
+
LANE_LABEL,
|
|
1182
|
+
isSwimlaneNode,
|
|
1183
|
+
hasSwimlanes,
|
|
1184
|
+
countGroups,
|
|
1185
|
+
layoutSwimlanes,
|
|
1186
|
+
getGrouping,
|
|
1187
|
+
removeSwimlanes,
|
|
1188
|
+
groupIntoBoxes,
|
|
1189
|
+
convertToMermaid,
|
|
1190
|
+
isMessageNode,
|
|
1191
|
+
getMessagesLabel,
|
|
1192
|
+
isCarrier,
|
|
1193
|
+
hideNodes,
|
|
1194
|
+
hideMessageNodes
|
|
1195
|
+
};
|
|
1196
|
+
//# sourceMappingURL=chunk-P2DH6CFV.mjs.map
|