@aranzatech/diagrams-bpmn 0.1.3 → 0.2.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/CHANGELOG.md +20 -0
- package/README.md +121 -0
- package/dist/catalog-OVnBDD8R.d.ts +9 -0
- package/dist/catalog-OWfI_yHU.d.cts +9 -0
- package/dist/{chunk-W3ROOC6E.js → chunk-33AR3PXF.js} +177 -40
- package/dist/chunk-33AR3PXF.js.map +1 -0
- package/dist/{chunk-3AFZDIMQ.js → chunk-ECTJRD7Z.js} +3 -3
- package/dist/{chunk-3AFZDIMQ.js.map → chunk-ECTJRD7Z.js.map} +1 -1
- package/dist/{chunk-NXMUX67A.js → chunk-H3YMTGFG.js} +79 -38
- package/dist/chunk-H3YMTGFG.js.map +1 -0
- package/dist/chunk-KALSGH4D.js +36 -0
- package/dist/chunk-KALSGH4D.js.map +1 -0
- package/dist/{chunk-DNR5WBQH.js → chunk-L5Z22RLX.js} +81 -20
- package/dist/chunk-L5Z22RLX.js.map +1 -0
- package/dist/chunk-OZKTOILD.js +3 -0
- package/dist/chunk-OZKTOILD.js.map +1 -0
- package/dist/{chunk-4AX573IV.js → chunk-RLAJNRF2.js} +3 -3
- package/dist/{chunk-4AX573IV.js.map → chunk-RLAJNRF2.js.map} +1 -1
- package/dist/chunk-YQTIODXH.js +532 -0
- package/dist/chunk-YQTIODXH.js.map +1 -0
- package/dist/chunk-ZFGQVLHB.js +226 -0
- package/dist/chunk-ZFGQVLHB.js.map +1 -0
- package/dist/edges/index.cjs +1 -1
- package/dist/edges/index.cjs.map +1 -1
- package/dist/edges/index.js +2 -2
- package/dist/elements/index.cjs +81 -17
- package/dist/elements/index.cjs.map +1 -1
- package/dist/elements/index.d.cts +4 -6
- package/dist/elements/index.d.ts +4 -6
- package/dist/elements/index.js +3 -2
- package/dist/index.cjs +1120 -118
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -63
- package/dist/index.d.ts +10 -63
- package/dist/index.js +9 -42
- package/dist/index.js.map +1 -1
- package/dist/modeling/index.cjs +1241 -0
- package/dist/modeling/index.cjs.map +1 -0
- package/dist/modeling/index.d.cts +146 -0
- package/dist/modeling/index.d.ts +146 -0
- package/dist/modeling/index.js +5 -0
- package/dist/modeling/index.js.map +1 -0
- package/dist/nodes/index.cjs +91 -38
- package/dist/nodes/index.cjs.map +1 -1
- package/dist/nodes/index.js +2 -2
- package/dist/types-BxjCV2oX.d.ts +20 -0
- package/dist/{types-C78d_Kdh.d.cts → types-DznxZxpV.d.cts} +17 -19
- package/dist/{types-C78d_Kdh.d.ts → types-DznxZxpV.d.ts} +17 -19
- package/dist/types-vVi5T7qj.d.cts +20 -0
- package/dist/validation/index.cjs +848 -0
- package/dist/validation/index.cjs.map +1 -0
- package/dist/validation/index.d.cts +25 -0
- package/dist/validation/index.d.ts +25 -0
- package/dist/validation/index.js +5 -0
- package/dist/validation/index.js.map +1 -0
- package/dist/xml/index.cjs +215 -54
- package/dist/xml/index.cjs.map +1 -1
- package/dist/xml/index.d.cts +4 -19
- package/dist/xml/index.d.ts +4 -19
- package/dist/xml/index.js +2 -2
- package/package.json +16 -4
- package/dist/chunk-23B2IGK5.js +0 -24
- package/dist/chunk-23B2IGK5.js.map +0 -1
- package/dist/chunk-DNR5WBQH.js.map +0 -1
- package/dist/chunk-NXMUX67A.js.map +0 -1
- package/dist/chunk-W3ROOC6E.js.map +0 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
- Expanded BPMN modeling helpers on top of the new `diagrams-core` primitives.
|
|
6
|
+
- Added BPMN node factory, edge-type inference and BPMN document serialization helpers.
|
|
7
|
+
- Added replace, resize, reparent, select, copy/paste and batch-command helpers.
|
|
8
|
+
- Improved BPMN connection rules to allow subprocesses as flow nodes while blocking pools/lanes/artifacts without handles.
|
|
9
|
+
- Added sequence-flow cardinality checks based on the BPMN element catalog.
|
|
10
|
+
- Boundary attachment now updates both `parentId` and BPMN `attachedToRef` data.
|
|
11
|
+
|
|
12
|
+
## 0.2.1
|
|
13
|
+
|
|
14
|
+
- Added BPMN modeling helpers built on `@aranzatech/diagrams-core` commands and rules.
|
|
15
|
+
- Added public `@aranzatech/diagrams-bpmn/modeling` subpath.
|
|
16
|
+
- Improved XML roundtrip for default sequence flows, boundary event attachment,
|
|
17
|
+
non-interrupting boundary events, documentation and parent-relative coordinates.
|
|
18
|
+
- Removed Flowable adapter exports from the root public API; Flowable integration
|
|
19
|
+
is planned as a separate wrapper concern.
|
|
20
|
+
- Added README coverage matrix and stable-scope notes.
|
package/README.md
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# @aranzatech/diagrams-bpmn
|
|
2
|
+
|
|
3
|
+
BPMN 2.0 building blocks for the Aranza diagram ecosystem. This package owns
|
|
4
|
+
BPMN-specific visual components, element metadata, BPMN modeling helpers, XML
|
|
5
|
+
import/export and preview token simulation.
|
|
6
|
+
|
|
7
|
+
It is intentionally not responsible for execution-engine communication. Flowable
|
|
8
|
+
integration belongs in a future wrapper package or in the consuming app backend.
|
|
9
|
+
|
|
10
|
+
## Public Subpaths
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
import { BPMN_NODE_TYPES } from "@aranzatech/diagrams-bpmn/nodes";
|
|
14
|
+
import { BPMN_EDGE_TYPES } from "@aranzatech/diagrams-bpmn/edges";
|
|
15
|
+
import { BPMN_ELEMENT_CATALOG } from "@aranzatech/diagrams-bpmn/elements";
|
|
16
|
+
import { parseBpmnXml, serializeBpmnXml } from "@aranzatech/diagrams-bpmn/xml";
|
|
17
|
+
import {
|
|
18
|
+
createBpmnNodeCommand,
|
|
19
|
+
replaceBpmnNodeCommand,
|
|
20
|
+
serializeBpmnDiagram,
|
|
21
|
+
} from "@aranzatech/diagrams-bpmn/modeling";
|
|
22
|
+
import { createSimulation } from "@aranzatech/diagrams-bpmn/simulation";
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Scope
|
|
26
|
+
|
|
27
|
+
- BPMN visual node and edge renderers for ReactFlow.
|
|
28
|
+
- BPMN element catalog and guards.
|
|
29
|
+
- BPMN XML import/export through `bpmn-moddle`.
|
|
30
|
+
- BPMN modeling commands and interaction rules on top of `diagrams-core`.
|
|
31
|
+
- Client-side preview token simulation.
|
|
32
|
+
|
|
33
|
+
## Out Of Scope
|
|
34
|
+
|
|
35
|
+
- Flowable REST/backend communication.
|
|
36
|
+
- BPMN business validation rules. Those belong in `@aranzatech/flowslint`.
|
|
37
|
+
- Full execution semantics.
|
|
38
|
+
|
|
39
|
+
## Coverage Matrix
|
|
40
|
+
|
|
41
|
+
| Area | Status | Notes |
|
|
42
|
+
|---|---:|---|
|
|
43
|
+
| Events | Partial | Start, end, intermediate catch/throw, boundary; common triggers rendered/imported. |
|
|
44
|
+
| Tasks | Partial | Task variants and call activity rendered; advanced task semantics still need richer XML mapping. |
|
|
45
|
+
| Gateways | Good | Exclusive, inclusive, parallel, event-based and complex rendered. |
|
|
46
|
+
| Containers | Partial | Pool, lane, subprocess, transaction, event subprocess and ad-hoc subprocess rendered; lane resizing/modeling still needs depth. |
|
|
47
|
+
| Artifacts | Partial | Text annotation and group rendered; association semantics are basic. |
|
|
48
|
+
| Data | Partial | Data object/input/output/store and refs rendered; full item definitions/data states pending. |
|
|
49
|
+
| Conversation | Partial | Conversation nodes and links rendered; full conversation model pending. |
|
|
50
|
+
| Choreography | Partial | Choreography nodes rendered; participant semantics are lightweight. |
|
|
51
|
+
| XML import/export | Partial | Basic BPMN + DI, default flows, boundary attachment, docs and relative child coordinates; full lossless roundtrip pending. |
|
|
52
|
+
| Modeling | Growing | Commands and rules for create/connect/attach/delete/replace/resize/reparent/copy/paste; palette/context-pad/auto-place can build on this. |
|
|
53
|
+
| Simulation | Preview | Useful design-time token simulation, not an execution engine. |
|
|
54
|
+
|
|
55
|
+
## Modeling Example
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
import { createCommandStackState } from "@aranzatech/diagrams-core/commands";
|
|
59
|
+
import {
|
|
60
|
+
createBpmnNodeCommand,
|
|
61
|
+
connectBpmnCommand,
|
|
62
|
+
replaceBpmnNodeCommand,
|
|
63
|
+
runBpmnCommands,
|
|
64
|
+
runBpmnCommand,
|
|
65
|
+
} from "@aranzatech/diagrams-bpmn/modeling";
|
|
66
|
+
|
|
67
|
+
let stack = createCommandStackState({ nodes: [], edges: [] });
|
|
68
|
+
|
|
69
|
+
stack = runBpmnCommand(
|
|
70
|
+
stack,
|
|
71
|
+
createBpmnNodeCommand({
|
|
72
|
+
id: "task_1",
|
|
73
|
+
elementType: "Task",
|
|
74
|
+
position: { x: 100, y: 100 },
|
|
75
|
+
label: "Review request",
|
|
76
|
+
}),
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
stack = runBpmnCommand(
|
|
80
|
+
stack,
|
|
81
|
+
connectBpmnCommand({
|
|
82
|
+
source: "start_1",
|
|
83
|
+
target: "task_1",
|
|
84
|
+
}),
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
stack = runBpmnCommands(
|
|
88
|
+
stack,
|
|
89
|
+
[
|
|
90
|
+
replaceBpmnNodeCommand({
|
|
91
|
+
id: "task_1",
|
|
92
|
+
elementType: "UserTask",
|
|
93
|
+
label: "Human review",
|
|
94
|
+
}),
|
|
95
|
+
],
|
|
96
|
+
{ id: "review-as-user-task" },
|
|
97
|
+
);
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## BPMN Diagram Document Example
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
import {
|
|
104
|
+
deserializeBpmnDiagram,
|
|
105
|
+
serializeBpmnDiagram,
|
|
106
|
+
} from "@aranzatech/diagrams-bpmn/modeling";
|
|
107
|
+
|
|
108
|
+
const json = serializeBpmnDiagram(stack.current, {
|
|
109
|
+
metadata: { source: "designer" },
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const restored = deserializeBpmnDiagram(json);
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Road To Stable
|
|
116
|
+
|
|
117
|
+
- Expand XML to preserve more BPMN semantics losslessly.
|
|
118
|
+
- Add real-world XML fixtures from bpmn.io/Camunda/Flowable modelers.
|
|
119
|
+
- Add palette/context-pad and auto-place commands on top of the current modeling API.
|
|
120
|
+
- Add robust lane/pool resize and reparent behavior.
|
|
121
|
+
- Move engine-specific extensions to a dedicated package.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { e as BpmnElementType, c as BpmnElementMeta, d as BpmnElementSize } from './types-DznxZxpV.js';
|
|
2
|
+
|
|
3
|
+
declare const BPMN_ELEMENT_CATALOG: Record<BpmnElementType, BpmnElementMeta>;
|
|
4
|
+
declare function getElementMeta(type: BpmnElementType): BpmnElementMeta;
|
|
5
|
+
declare const BPMN_RESIZABLE_ELEMENT_TYPES: ("Task" | "UserTask" | "ServiceTask" | "ScriptTask" | "ManualTask" | "BusinessRuleTask" | "ReceiveTask" | "SendTask" | "CallActivity" | "SubProcess" | "Transaction" | "AdHocSubProcess" | "EventSubProcess" | "Pool" | "Lane" | "Annotation" | "Group" | "SubConversation" | "ChoreographyTask" | "SubChoreography" | "CallChoreography")[];
|
|
6
|
+
declare function isBpmnElementResizable(type: BpmnElementType): boolean;
|
|
7
|
+
declare function getBpmnElementSize(type: BpmnElementType): BpmnElementSize;
|
|
8
|
+
|
|
9
|
+
export { BPMN_ELEMENT_CATALOG as B, BPMN_RESIZABLE_ELEMENT_TYPES as a, getElementMeta as b, getBpmnElementSize as g, isBpmnElementResizable as i };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { e as BpmnElementType, c as BpmnElementMeta, d as BpmnElementSize } from './types-DznxZxpV.cjs';
|
|
2
|
+
|
|
3
|
+
declare const BPMN_ELEMENT_CATALOG: Record<BpmnElementType, BpmnElementMeta>;
|
|
4
|
+
declare function getElementMeta(type: BpmnElementType): BpmnElementMeta;
|
|
5
|
+
declare const BPMN_RESIZABLE_ELEMENT_TYPES: ("Task" | "UserTask" | "ServiceTask" | "ScriptTask" | "ManualTask" | "BusinessRuleTask" | "ReceiveTask" | "SendTask" | "CallActivity" | "SubProcess" | "Transaction" | "AdHocSubProcess" | "EventSubProcess" | "Pool" | "Lane" | "Annotation" | "Group" | "SubConversation" | "ChoreographyTask" | "SubChoreography" | "CallChoreography")[];
|
|
6
|
+
declare function isBpmnElementResizable(type: BpmnElementType): boolean;
|
|
7
|
+
declare function getBpmnElementSize(type: BpmnElementType): BpmnElementSize;
|
|
8
|
+
|
|
9
|
+
export { BPMN_ELEMENT_CATALOG as B, BPMN_RESIZABLE_ELEMENT_TYPES as a, getElementMeta as b, getBpmnElementSize as g, isBpmnElementResizable as i };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BPMN_ELEMENT_CATALOG } from './chunk-
|
|
1
|
+
import { BPMN_ELEMENT_CATALOG } from './chunk-L5Z22RLX.js';
|
|
2
2
|
import { BpmnModdle } from 'bpmn-moddle';
|
|
3
3
|
|
|
4
4
|
// src/xml/mapper.ts
|
|
@@ -23,8 +23,8 @@ var MODDLE_TO_ELEMENT_TYPE = {
|
|
|
23
23
|
"bpmn:EventBasedGateway": "EventBasedGateway",
|
|
24
24
|
"bpmn:ComplexGateway": "ComplexGateway",
|
|
25
25
|
"bpmn:SubProcess": "SubProcess",
|
|
26
|
-
"bpmn:AdHocSubProcess": "
|
|
27
|
-
"bpmn:Transaction": "
|
|
26
|
+
"bpmn:AdHocSubProcess": "AdHocSubProcess",
|
|
27
|
+
"bpmn:Transaction": "Transaction",
|
|
28
28
|
"bpmn:TextAnnotation": "Annotation",
|
|
29
29
|
"bpmn:Group": "Group",
|
|
30
30
|
"bpmn:DataObject": "DataObject",
|
|
@@ -62,6 +62,9 @@ var ELEMENT_TYPE_TO_MODDLE = {
|
|
|
62
62
|
EventBasedGateway: "bpmn:EventBasedGateway",
|
|
63
63
|
ComplexGateway: "bpmn:ComplexGateway",
|
|
64
64
|
SubProcess: "bpmn:SubProcess",
|
|
65
|
+
Transaction: "bpmn:Transaction",
|
|
66
|
+
EventSubProcess: "bpmn:SubProcess",
|
|
67
|
+
AdHocSubProcess: "bpmn:AdHocSubProcess",
|
|
65
68
|
Pool: "bpmn:Participant",
|
|
66
69
|
Lane: "bpmn:Lane",
|
|
67
70
|
Annotation: "bpmn:TextAnnotation",
|
|
@@ -126,6 +129,10 @@ function asElements(v) {
|
|
|
126
129
|
function asString(v) {
|
|
127
130
|
return typeof v === "string" && v.trim() ? v.trim() : void 0;
|
|
128
131
|
}
|
|
132
|
+
function extractDocumentation(el) {
|
|
133
|
+
const [doc] = asElements(el.documentation);
|
|
134
|
+
return asString(doc?.text);
|
|
135
|
+
}
|
|
129
136
|
function extractDiagramInfo(definitions) {
|
|
130
137
|
const shapes = /* @__PURE__ */ new Map();
|
|
131
138
|
const waypoints = /* @__PURE__ */ new Map();
|
|
@@ -181,6 +188,7 @@ function extractTrigger(el) {
|
|
|
181
188
|
function extractSubProcessVariant(el) {
|
|
182
189
|
if (el.$type === "bpmn:Transaction") return "transaction";
|
|
183
190
|
if (el.$type === "bpmn:AdHocSubProcess") return "adhoc";
|
|
191
|
+
if (el.$type === "bpmn:SubProcess" && el.triggeredByEvent === true) return "event";
|
|
184
192
|
if (el.triggeredByEvent === true) return "event";
|
|
185
193
|
return "embedded";
|
|
186
194
|
}
|
|
@@ -194,7 +202,7 @@ function walkFlowElements(elements, parentId, ctx, nodes, edges) {
|
|
|
194
202
|
continue;
|
|
195
203
|
}
|
|
196
204
|
if ($type === "bpmn:LaneSet") continue;
|
|
197
|
-
const elementType = MODDLE_TO_ELEMENT_TYPE[$type];
|
|
205
|
+
const elementType = $type === "bpmn:SubProcess" && el.triggeredByEvent === true ? "EventSubProcess" : MODDLE_TO_ELEMENT_TYPE[$type];
|
|
198
206
|
if (!elementType) {
|
|
199
207
|
ctx.warnings.push(`Unknown element type "${$type}" (id=${id}) \u2014 skipped.`);
|
|
200
208
|
continue;
|
|
@@ -215,22 +223,26 @@ function buildNode(el, elementType, parentId, ctx, nodes) {
|
|
|
215
223
|
const y = shape?.y ?? 100;
|
|
216
224
|
if (!shape) ctx.autoX.value += (meta?.defaultWidth ?? 120) + 20;
|
|
217
225
|
const label = asString(el.name);
|
|
226
|
+
const documentation = extractDocumentation(el);
|
|
218
227
|
const trigger = extractTrigger(el);
|
|
219
228
|
const isNonInterrupting = el.cancelActivity === false;
|
|
229
|
+
const attachedToRef = el.attachedToRef?.id;
|
|
220
230
|
const data = {
|
|
221
231
|
elementType,
|
|
222
232
|
...label ? { label } : {},
|
|
233
|
+
...documentation ? { documentation } : {},
|
|
223
234
|
...trigger ? { trigger } : {},
|
|
224
|
-
...isNonInterrupting ? { isNonInterrupting: true } : {}
|
|
235
|
+
...isNonInterrupting ? { isNonInterrupting: true } : {},
|
|
236
|
+
...attachedToRef ? { attachedToRef } : {}
|
|
225
237
|
};
|
|
226
|
-
if (elementType === "SubProcess") {
|
|
238
|
+
if (elementType === "SubProcess" || elementType === "Transaction" || elementType === "EventSubProcess" || elementType === "AdHocSubProcess") {
|
|
227
239
|
const variant = extractSubProcessVariant(el);
|
|
228
240
|
if (variant) data.subProcessVariant = variant;
|
|
229
241
|
const isExpanded = shape?.isExpanded ?? true;
|
|
230
242
|
data.isExpanded = isExpanded;
|
|
231
243
|
}
|
|
232
244
|
const laneId = ctx.laneMembership.get(id);
|
|
233
|
-
const effectiveParentId = laneId ?? parentId;
|
|
245
|
+
const effectiveParentId = attachedToRef ?? laneId ?? parentId;
|
|
234
246
|
const node = {
|
|
235
247
|
id,
|
|
236
248
|
type: elementType,
|
|
@@ -251,10 +263,12 @@ function buildEdge(el, edgeType, ctx, edges) {
|
|
|
251
263
|
return;
|
|
252
264
|
}
|
|
253
265
|
const label = asString(el.name);
|
|
266
|
+
const documentation = extractDocumentation(el);
|
|
254
267
|
const condExpr = el.conditionExpression;
|
|
255
268
|
const data = {
|
|
256
269
|
edgeType,
|
|
257
270
|
...label ? { label } : {},
|
|
271
|
+
...documentation ? { documentation } : {},
|
|
258
272
|
...condExpr?.body ? { conditionExpression: condExpr.body } : {}
|
|
259
273
|
};
|
|
260
274
|
const waypoints = ctx.waypoints.get(id);
|
|
@@ -355,7 +369,46 @@ async function parseBpmnXml(xml) {
|
|
|
355
369
|
);
|
|
356
370
|
}
|
|
357
371
|
}
|
|
358
|
-
|
|
372
|
+
const defaultFlowById = /* @__PURE__ */ new Set();
|
|
373
|
+
const nodeIds = new Set(nodes.map((node) => node.id));
|
|
374
|
+
for (const rootEl of asElements(rootElement.rootElements)) {
|
|
375
|
+
collectDefaultFlows(rootEl, defaultFlowById);
|
|
376
|
+
}
|
|
377
|
+
const normalizedEdges = edges.map((edge) => {
|
|
378
|
+
if (!defaultFlowById.has(edge.id)) return edge;
|
|
379
|
+
const data = {
|
|
380
|
+
edgeType: edge.data?.edgeType ?? edge.type,
|
|
381
|
+
...edge.data ?? {},
|
|
382
|
+
isDefault: true
|
|
383
|
+
};
|
|
384
|
+
return { ...edge, data };
|
|
385
|
+
});
|
|
386
|
+
return {
|
|
387
|
+
nodes: normalizeChildPositions(nodes, nodeIds),
|
|
388
|
+
edges: normalizedEdges,
|
|
389
|
+
warnings
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
function collectDefaultFlows(el, defaultFlowById) {
|
|
393
|
+
const defaultRef = el.default;
|
|
394
|
+
if (defaultRef?.id) defaultFlowById.add(defaultRef.id);
|
|
395
|
+
for (const child of asElements(el.rootElements)) collectDefaultFlows(child, defaultFlowById);
|
|
396
|
+
for (const child of asElements(el.flowElements)) collectDefaultFlows(child, defaultFlowById);
|
|
397
|
+
}
|
|
398
|
+
function normalizeChildPositions(nodes, nodeIds) {
|
|
399
|
+
const absoluteById = new Map(nodes.map((node) => [node.id, node.position]));
|
|
400
|
+
return nodes.map((node) => {
|
|
401
|
+
if (!node.parentId || !nodeIds.has(node.parentId)) return node;
|
|
402
|
+
const parentPosition = absoluteById.get(node.parentId);
|
|
403
|
+
if (!parentPosition) return node;
|
|
404
|
+
return {
|
|
405
|
+
...node,
|
|
406
|
+
position: {
|
|
407
|
+
x: node.position.x - parentPosition.x,
|
|
408
|
+
y: node.position.y - parentPosition.y
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
});
|
|
359
412
|
}
|
|
360
413
|
function uid(prefix, id) {
|
|
361
414
|
return `${prefix}_${id}`;
|
|
@@ -363,19 +416,6 @@ function uid(prefix, id) {
|
|
|
363
416
|
function asNodes(nodes, types) {
|
|
364
417
|
return nodes.filter((n) => types.includes(n.data.elementType));
|
|
365
418
|
}
|
|
366
|
-
function buildFlowableAttrs(data) {
|
|
367
|
-
const attrs = {};
|
|
368
|
-
if (data.flowableAssignee) attrs["flowable:assignee"] = data.flowableAssignee;
|
|
369
|
-
if (data.flowableCandidateGroups) attrs["flowable:candidateGroups"] = data.flowableCandidateGroups;
|
|
370
|
-
if (data.flowableCandidateUsers) attrs["flowable:candidateUsers"] = data.flowableCandidateUsers;
|
|
371
|
-
if (data.flowableFormKey) attrs["flowable:formKey"] = data.flowableFormKey;
|
|
372
|
-
if (data.flowableDueDate) attrs["flowable:dueDate"] = data.flowableDueDate;
|
|
373
|
-
if (data.flowableType) attrs["flowable:type"] = data.flowableType;
|
|
374
|
-
if (data.flowableExpression) attrs["flowable:expression"] = data.flowableExpression;
|
|
375
|
-
if (data.flowableClass) attrs["flowable:class"] = data.flowableClass;
|
|
376
|
-
if (data.flowableDelegateExpression) attrs["flowable:delegateExpression"] = data.flowableDelegateExpression;
|
|
377
|
-
return attrs;
|
|
378
|
-
}
|
|
379
419
|
function buildSemanticModel(moddle, nodes, edges, opts) {
|
|
380
420
|
const defId = opts.id ?? "Definitions_1";
|
|
381
421
|
const defName = opts.name;
|
|
@@ -434,13 +474,32 @@ function buildSemanticModel(moddle, nodes, edges, opts) {
|
|
|
434
474
|
return definitions;
|
|
435
475
|
}
|
|
436
476
|
function buildProcess(moddle, allNodes, allEdges, poolId, laneNodes, processId) {
|
|
437
|
-
const
|
|
438
|
-
|
|
439
|
-
|
|
477
|
+
const subProcessIds = new Set(
|
|
478
|
+
allNodes.filter(
|
|
479
|
+
(n) => n.data.elementType === "SubProcess" || n.data.elementType === "Transaction" || n.data.elementType === "EventSubProcess" || n.data.elementType === "AdHocSubProcess"
|
|
480
|
+
).map((n) => n.id)
|
|
481
|
+
);
|
|
482
|
+
const isInsideSubProcess = (node) => {
|
|
483
|
+
let parentId = node.parentId;
|
|
484
|
+
while (parentId) {
|
|
485
|
+
if (subProcessIds.has(parentId)) return true;
|
|
486
|
+
parentId = allNodes.find((candidate) => candidate.id === parentId)?.parentId;
|
|
487
|
+
}
|
|
488
|
+
return false;
|
|
489
|
+
};
|
|
490
|
+
const belongsToPool = (node) => {
|
|
491
|
+
let parentId = node.parentId;
|
|
492
|
+
while (parentId) {
|
|
493
|
+
if (parentId === poolId) return true;
|
|
494
|
+
parentId = allNodes.find((candidate) => candidate.id === parentId)?.parentId;
|
|
495
|
+
}
|
|
496
|
+
return false;
|
|
497
|
+
};
|
|
498
|
+
const myNodes = (poolId ? allNodes.filter((n) => belongsToPool(n)) : allNodes.filter((n) => n.data.elementType !== "Pool" && n.data.elementType !== "Lane")).filter((n) => !isInsideSubProcess(n));
|
|
440
499
|
const myLanes = laneNodes.filter((l) => poolId ? l.parentId === poolId : true);
|
|
441
500
|
const flowElements = [];
|
|
442
501
|
for (const node of myNodes) {
|
|
443
|
-
const el = buildFlowElement(moddle, node);
|
|
502
|
+
const el = buildFlowElement(moddle, node, allNodes, allEdges);
|
|
444
503
|
if (el) flowElements.push(el);
|
|
445
504
|
}
|
|
446
505
|
const myNodeIds = new Set(myNodes.map((n) => n.id));
|
|
@@ -451,6 +510,17 @@ function buildProcess(moddle, allNodes, allEdges, poolId, laneNodes, processId)
|
|
|
451
510
|
const edgeMeta = buildEdgeElement(moddle, edge);
|
|
452
511
|
if (edgeMeta) flowElements.push(edgeMeta);
|
|
453
512
|
}
|
|
513
|
+
const elementById = new Map(
|
|
514
|
+
flowElements.filter((element) => typeof element.id === "string").map((element) => [element.id, element])
|
|
515
|
+
);
|
|
516
|
+
for (const edge of myEdges) {
|
|
517
|
+
if (!edge.data?.isDefault) continue;
|
|
518
|
+
const sourceElement = elementById.get(edge.source);
|
|
519
|
+
const edgeElement = elementById.get(edge.id);
|
|
520
|
+
if (sourceElement && edgeElement) {
|
|
521
|
+
sourceElement.default = edgeElement;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
454
524
|
const process = moddle.create("bpmn:Process", {
|
|
455
525
|
id: processId,
|
|
456
526
|
isExecutable: true,
|
|
@@ -471,7 +541,7 @@ function buildProcess(moddle, allNodes, allEdges, poolId, laneNodes, processId)
|
|
|
471
541
|
}
|
|
472
542
|
return process;
|
|
473
543
|
}
|
|
474
|
-
function buildFlowElement(moddle, node,
|
|
544
|
+
function buildFlowElement(moddle, node, allNodes, allEdges) {
|
|
475
545
|
const { elementType, label, trigger } = node.data;
|
|
476
546
|
if (elementType === "Pool" || elementType === "Lane") return null;
|
|
477
547
|
const moddleType = ELEMENT_TYPE_TO_MODDLE[elementType];
|
|
@@ -480,25 +550,46 @@ function buildFlowElement(moddle, node, _allNodes, _allEdges) {
|
|
|
480
550
|
id: node.id,
|
|
481
551
|
name: label ?? ""
|
|
482
552
|
};
|
|
553
|
+
if (node.data.documentation) {
|
|
554
|
+
attrs.documentation = [
|
|
555
|
+
moddle.create("bpmn:Documentation", { text: node.data.documentation })
|
|
556
|
+
];
|
|
557
|
+
}
|
|
483
558
|
if (trigger && trigger !== "none") {
|
|
484
559
|
const defType = TRIGGER_TO_EVENT_DEF[trigger];
|
|
485
560
|
if (defType) {
|
|
486
561
|
attrs.eventDefinitions = [moddle.create(defType, { id: uid("EventDef", node.id) })];
|
|
487
562
|
}
|
|
488
563
|
}
|
|
489
|
-
if (elementType === "
|
|
490
|
-
|
|
564
|
+
if (elementType === "BoundaryEvent") {
|
|
565
|
+
attrs.attachedToRef = { id: node.data.attachedToRef ?? node.parentId };
|
|
566
|
+
attrs.cancelActivity = node.data.isNonInterrupting ? false : true;
|
|
491
567
|
}
|
|
492
|
-
|
|
493
|
-
|
|
568
|
+
const isSubProcess = elementType === "SubProcess" || elementType === "Transaction" || elementType === "EventSubProcess" || elementType === "AdHocSubProcess";
|
|
569
|
+
if (isSubProcess) {
|
|
570
|
+
attrs.flowElements = buildNestedFlowElements(moddle, node, allNodes, allEdges);
|
|
571
|
+
if (elementType === "EventSubProcess" || node.data.subProcessVariant === "event") {
|
|
572
|
+
attrs.triggeredByEvent = true;
|
|
573
|
+
}
|
|
494
574
|
}
|
|
495
575
|
const element = moddle.create(moddleType, attrs);
|
|
496
|
-
const flowableAttrs = buildFlowableAttrs(node.data);
|
|
497
|
-
if (Object.keys(flowableAttrs).length > 0) {
|
|
498
|
-
element.$attrs = flowableAttrs;
|
|
499
|
-
}
|
|
500
576
|
return element;
|
|
501
577
|
}
|
|
578
|
+
function buildNestedFlowElements(moddle, parent, allNodes, allEdges) {
|
|
579
|
+
const childNodes = allNodes.filter((node) => node.parentId === parent.id);
|
|
580
|
+
const childNodeIds = new Set(childNodes.map((node) => node.id));
|
|
581
|
+
const flowElements = [];
|
|
582
|
+
for (const child of childNodes) {
|
|
583
|
+
const element = buildFlowElement(moddle, child, allNodes, allEdges);
|
|
584
|
+
if (element) flowElements.push(element);
|
|
585
|
+
}
|
|
586
|
+
for (const edge of allEdges) {
|
|
587
|
+
if (!childNodeIds.has(edge.source) || !childNodeIds.has(edge.target)) continue;
|
|
588
|
+
const element = buildEdgeElement(moddle, edge);
|
|
589
|
+
if (element) flowElements.push(element);
|
|
590
|
+
}
|
|
591
|
+
return flowElements;
|
|
592
|
+
}
|
|
502
593
|
function buildEdgeElement(moddle, edge) {
|
|
503
594
|
if (!edge.data) return null;
|
|
504
595
|
const moddleType = EDGE_TYPE_TO_MODDLE[edge.data.edgeType];
|
|
@@ -509,6 +600,11 @@ function buildEdgeElement(moddle, edge) {
|
|
|
509
600
|
sourceRef: { id: edge.source },
|
|
510
601
|
targetRef: { id: edge.target }
|
|
511
602
|
};
|
|
603
|
+
if (edge.data.documentation) {
|
|
604
|
+
attrs.documentation = [
|
|
605
|
+
moddle.create("bpmn:Documentation", { text: edge.data.documentation })
|
|
606
|
+
];
|
|
607
|
+
}
|
|
512
608
|
if (edge.data.conditionExpression) {
|
|
513
609
|
attrs.conditionExpression = moddle.create("bpmn:FormalExpression", {
|
|
514
610
|
body: edge.data.conditionExpression
|
|
@@ -519,13 +615,14 @@ function buildEdgeElement(moddle, edge) {
|
|
|
519
615
|
function buildBpmnDI(moddle, definitions, nodes, edges) {
|
|
520
616
|
const shapes = [];
|
|
521
617
|
const edgeShapes = [];
|
|
618
|
+
const absolutePositionById = buildAbsolutePositionMap(nodes);
|
|
522
619
|
for (const node of nodes) {
|
|
523
620
|
const meta = BPMN_ELEMENT_CATALOG[node.data.elementType];
|
|
524
621
|
const w = node.width ?? meta?.defaultWidth ?? 120;
|
|
525
622
|
const h = node.height ?? meta?.defaultHeight ?? 60;
|
|
526
623
|
const bounds = moddle.create("dc:Bounds", {
|
|
527
|
-
x: node.position.x,
|
|
528
|
-
y: node.position.y,
|
|
624
|
+
x: absolutePositionById.get(node.id)?.x ?? node.position.x,
|
|
625
|
+
y: absolutePositionById.get(node.id)?.y ?? node.position.y,
|
|
529
626
|
width: w,
|
|
530
627
|
height: h
|
|
531
628
|
});
|
|
@@ -540,9 +637,9 @@ function buildBpmnDI(moddle, definitions, nodes, edges) {
|
|
|
540
637
|
shapes.push(shape);
|
|
541
638
|
}
|
|
542
639
|
for (const edge of edges) {
|
|
543
|
-
const waypoints = edge.
|
|
640
|
+
const waypoints = resolveEdgeWaypoints(edge, nodes, absolutePositionById).map(
|
|
544
641
|
(p) => moddle.create("dc:Point", { x: p.x, y: p.y })
|
|
545
|
-
)
|
|
642
|
+
);
|
|
546
643
|
edgeShapes.push(
|
|
547
644
|
moddle.create("bpmndi:BPMNEdge", {
|
|
548
645
|
id: uid("BPMNEdge", edge.id),
|
|
@@ -564,6 +661,46 @@ function buildBpmnDI(moddle, definitions, nodes, edges) {
|
|
|
564
661
|
});
|
|
565
662
|
definitions.diagrams = [diagram];
|
|
566
663
|
}
|
|
664
|
+
function resolveEdgeWaypoints(edge, nodes, absolutePositionById) {
|
|
665
|
+
if (edge.data?.routingPoints && edge.data.routingPoints.length >= 2) {
|
|
666
|
+
return edge.data.routingPoints;
|
|
667
|
+
}
|
|
668
|
+
const source = nodes.find((node) => node.id === edge.source);
|
|
669
|
+
const target = nodes.find((node) => node.id === edge.target);
|
|
670
|
+
if (!source || !target) return [];
|
|
671
|
+
const sourceMeta = BPMN_ELEMENT_CATALOG[source.data.elementType];
|
|
672
|
+
const targetMeta = BPMN_ELEMENT_CATALOG[target.data.elementType];
|
|
673
|
+
const sourcePosition = absolutePositionById.get(source.id) ?? source.position;
|
|
674
|
+
const targetPosition = absolutePositionById.get(target.id) ?? target.position;
|
|
675
|
+
return [
|
|
676
|
+
{
|
|
677
|
+
x: sourcePosition.x + (source.width ?? sourceMeta.defaultWidth) / 2,
|
|
678
|
+
y: sourcePosition.y + (source.height ?? sourceMeta.defaultHeight) / 2
|
|
679
|
+
},
|
|
680
|
+
{
|
|
681
|
+
x: targetPosition.x + (target.width ?? targetMeta.defaultWidth) / 2,
|
|
682
|
+
y: targetPosition.y + (target.height ?? targetMeta.defaultHeight) / 2
|
|
683
|
+
}
|
|
684
|
+
];
|
|
685
|
+
}
|
|
686
|
+
function buildAbsolutePositionMap(nodes) {
|
|
687
|
+
const nodeById = new Map(nodes.map((node) => [node.id, node]));
|
|
688
|
+
const absoluteById = /* @__PURE__ */ new Map();
|
|
689
|
+
function resolve(node) {
|
|
690
|
+
const cached = absoluteById.get(node.id);
|
|
691
|
+
if (cached) return cached;
|
|
692
|
+
const parent = node.parentId ? nodeById.get(node.parentId) : void 0;
|
|
693
|
+
const parentPosition = parent ? resolve(parent) : { x: 0, y: 0 };
|
|
694
|
+
const absolute = {
|
|
695
|
+
x: parentPosition.x + node.position.x,
|
|
696
|
+
y: parentPosition.y + node.position.y
|
|
697
|
+
};
|
|
698
|
+
absoluteById.set(node.id, absolute);
|
|
699
|
+
return absolute;
|
|
700
|
+
}
|
|
701
|
+
for (const node of nodes) resolve(node);
|
|
702
|
+
return absoluteById;
|
|
703
|
+
}
|
|
567
704
|
async function serializeBpmnXml(nodes, edges, opts = {}) {
|
|
568
705
|
const moddle = new BpmnModdle();
|
|
569
706
|
const definitions = buildSemanticModel(moddle, nodes, edges, opts);
|
|
@@ -575,5 +712,5 @@ async function serializeBpmnXml(nodes, edges, opts = {}) {
|
|
|
575
712
|
}
|
|
576
713
|
|
|
577
714
|
export { parseBpmnXml, serializeBpmnXml };
|
|
578
|
-
//# sourceMappingURL=chunk-
|
|
579
|
-
//# sourceMappingURL=chunk-
|
|
715
|
+
//# sourceMappingURL=chunk-33AR3PXF.js.map
|
|
716
|
+
//# sourceMappingURL=chunk-33AR3PXF.js.map
|