@bpmnkit/core 0.0.27 → 0.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.
Files changed (56) hide show
  1. package/dist/bpmn/auto-layout.js +39 -126
  2. package/dist/bpmn/bpmn-builder.d.ts +30 -0
  3. package/dist/bpmn/bpmn-builder.js +350 -31
  4. package/dist/bpmn/bpmn-model.d.ts +35 -2
  5. package/dist/bpmn/bpmn-parser.js +39 -1
  6. package/dist/bpmn/bpmn-serializer.js +27 -0
  7. package/dist/bpmn/compact.js +11 -1
  8. package/dist/bpmn/di-check.d.ts +14 -0
  9. package/dist/bpmn/di-check.js +51 -0
  10. package/dist/bpmn/di-planes.d.ts +13 -0
  11. package/dist/bpmn/di-planes.js +20 -0
  12. package/dist/bpmn/optimize/tasks.js +1 -0
  13. package/dist/bpmn/svg.js +36 -4
  14. package/dist/bpmn/type-guards.d.ts +7 -1
  15. package/dist/bpmn/type-guards.js +13 -0
  16. package/dist/index.d.ts +5 -2
  17. package/dist/index.js +3 -1
  18. package/dist/layout/annotations.d.ts +27 -0
  19. package/dist/layout/annotations.js +251 -0
  20. package/dist/layout/grid/edge-labels.d.ts +8 -0
  21. package/dist/layout/grid/edge-labels.js +126 -0
  22. package/dist/layout/grid/flow-graph.d.ts +25 -0
  23. package/dist/layout/grid/flow-graph.js +99 -0
  24. package/dist/layout/grid/grid-engine.d.ts +4 -0
  25. package/dist/layout/grid/grid-engine.js +214 -0
  26. package/dist/layout/grid/grid-router.d.ts +36 -0
  27. package/dist/layout/grid/grid-router.js +190 -0
  28. package/dist/layout/grid/grid.d.ts +43 -0
  29. package/dist/layout/grid/grid.js +174 -0
  30. package/dist/layout/grid/walker.d.ts +11 -0
  31. package/dist/layout/grid/walker.js +126 -0
  32. package/dist/layout/index.d.ts +2 -5
  33. package/dist/layout/index.js +1 -4
  34. package/dist/layout/layout-engine.d.ts +5 -15
  35. package/dist/layout/layout-engine.js +8 -486
  36. package/dist/layout/types.js +4 -0
  37. package/dist/xml/xml-parser.js +5 -0
  38. package/package.json +1 -1
  39. package/dist/layout/astar.d.ts +0 -15
  40. package/dist/layout/astar.js +0 -191
  41. package/dist/layout/block-builder.d.ts +0 -37
  42. package/dist/layout/block-builder.js +0 -154
  43. package/dist/layout/block-layout.d.ts +0 -9
  44. package/dist/layout/block-layout.js +0 -163
  45. package/dist/layout/coordinates.d.ts +0 -85
  46. package/dist/layout/coordinates.js +0 -1392
  47. package/dist/layout/crossing.d.ts +0 -8
  48. package/dist/layout/crossing.js +0 -60
  49. package/dist/layout/graph.d.ts +0 -28
  50. package/dist/layout/graph.js +0 -126
  51. package/dist/layout/layers.d.ts +0 -13
  52. package/dist/layout/layers.js +0 -49
  53. package/dist/layout/routing.d.ts +0 -33
  54. package/dist/layout/routing.js +0 -622
  55. package/dist/layout/subprocess.d.ts +0 -14
  56. package/dist/layout/subprocess.js +0 -115
@@ -127,6 +127,7 @@ function makeFlowElement(id, type, options) {
127
127
  sequenceFlows: [],
128
128
  textAnnotations: [],
129
129
  associations: [],
130
+ groups: [],
130
131
  };
131
132
  case "adHocSubProcess":
132
133
  return {
@@ -136,6 +137,7 @@ function makeFlowElement(id, type, options) {
136
137
  sequenceFlows: [],
137
138
  textAnnotations: [],
138
139
  associations: [],
140
+ groups: [],
139
141
  };
140
142
  case "eventSubProcess":
141
143
  return {
@@ -145,6 +147,7 @@ function makeFlowElement(id, type, options) {
145
147
  sequenceFlows: [],
146
148
  textAnnotations: [],
147
149
  associations: [],
150
+ groups: [],
148
151
  };
149
152
  case "transaction":
150
153
  return {
@@ -154,7 +157,10 @@ function makeFlowElement(id, type, options) {
154
157
  sequenceFlows: [],
155
158
  textAnnotations: [],
156
159
  associations: [],
160
+ groups: [],
157
161
  };
162
+ default:
163
+ return { ...base, type };
158
164
  }
159
165
  }
160
166
  function buildMultiInstance(options) {
@@ -333,6 +339,31 @@ function makeInclusiveGatewayEl(id, options) {
333
339
  }
334
340
  return el;
335
341
  }
342
+ /**
343
+ * `subProcess`/`eventSubProcess`/`adHocSubProcess` all take a required content
344
+ * callback as their 2nd argument and an optional options object as their 3rd.
345
+ * That shape isn't demonstrated anywhere in this SDK's docs/examples, and
346
+ * callers that only see the parameter *names* (not enforced types — e.g.
347
+ * generated code run without type-checking) sometimes guess the common
348
+ * "options before callback" order instead. Detect that by runtime type and
349
+ * swap, so a reversed call still succeeds instead of throwing on `content`
350
+ * not being callable.
351
+ */
352
+ function resolveSubProcessArgs(content, options) {
353
+ if (typeof content === "function") {
354
+ return {
355
+ content: content,
356
+ options: options,
357
+ };
358
+ }
359
+ if (typeof options === "function") {
360
+ return {
361
+ content: options,
362
+ options: content,
363
+ };
364
+ }
365
+ throw new TypeError("subProcess() requires a content callback function");
366
+ }
336
367
  // ---------------------------------------------------------------------------
337
368
  // Shared graph helpers — used by ProcessBuilder and SubProcessContentBuilder
338
369
  // ---------------------------------------------------------------------------
@@ -712,6 +743,120 @@ export class BranchBuilder {
712
743
  this.openBranchEnds = savedOpenEnds;
713
744
  return this;
714
745
  }
746
+ // ---- Sub-process ----
747
+ /** Add a sub-process (mirrors `ProcessBuilder.subProcess`). */
748
+ subProcess(id, content, options) {
749
+ const resolved = resolveSubProcessArgs(content, options);
750
+ const sub = new SubProcessContentBuilder(this.rootMessages);
751
+ resolved.content(sub);
752
+ insertJoinGateways(sub._elements, sub._flows);
753
+ recomputeIncomingOutgoing(sub._elements, sub._flows);
754
+ const element = makeFlowElement(id, "subProcess", resolved.options);
755
+ if (element.type === "subProcess") {
756
+ element.flowElements = sub._elements;
757
+ element.sequenceFlows = sub._flows;
758
+ element.textAnnotations = sub._textAnnotations;
759
+ element.associations = sub._associations;
760
+ if (resolved.options?.multiInstance) {
761
+ element.loopCharacteristics = buildMultiInstance(resolved.options.multiInstance);
762
+ }
763
+ }
764
+ return this.addElement(element);
765
+ }
766
+ /** Add an ad-hoc sub-process (mirrors `ProcessBuilder.adHocSubProcess`). */
767
+ adHocSubProcess(id, content, options) {
768
+ const resolved = resolveSubProcessArgs(content, options);
769
+ const sub = new SubProcessContentBuilder(this.rootMessages);
770
+ resolved.content(sub);
771
+ insertJoinGateways(sub._elements, sub._flows);
772
+ recomputeIncomingOutgoing(sub._elements, sub._flows);
773
+ const zeebeExt = {};
774
+ if (resolved.options?.taskDefinition) {
775
+ zeebeExt.taskDefinition = resolved.options.taskDefinition;
776
+ }
777
+ if (resolved.options?.ioMapping) {
778
+ zeebeExt.ioMapping = {
779
+ inputs: resolved.options.ioMapping.inputs ?? [],
780
+ outputs: resolved.options.ioMapping.outputs ?? [],
781
+ };
782
+ }
783
+ if (resolved.options?.taskHeaders) {
784
+ zeebeExt.taskHeaders = {
785
+ headers: Object.entries(resolved.options.taskHeaders).map(([key, value]) => ({
786
+ key,
787
+ value,
788
+ })),
789
+ };
790
+ }
791
+ const extensionElements = zeebeExtensionsToXmlElements(zeebeExt);
792
+ const adHocAttrs = {};
793
+ if (resolved.options?.activeElementsCollection) {
794
+ adHocAttrs.activeElementsCollection = resolved.options.activeElementsCollection;
795
+ }
796
+ if (resolved.options?.outputCollection) {
797
+ adHocAttrs.outputCollection = resolved.options.outputCollection;
798
+ }
799
+ if (resolved.options?.outputElement) {
800
+ adHocAttrs.outputElement = resolved.options.outputElement;
801
+ }
802
+ if (Object.keys(adHocAttrs).length > 0) {
803
+ extensionElements.push({
804
+ name: "zeebe:adHoc",
805
+ attributes: adHocAttrs,
806
+ children: [],
807
+ });
808
+ }
809
+ const element = makeFlowElement(id, "adHocSubProcess", {
810
+ name: resolved.options?.name,
811
+ extensionElements,
812
+ });
813
+ if (resolved.options?.modelerTemplate) {
814
+ element.unknownAttributes["zeebe:modelerTemplate"] = resolved.options.modelerTemplate;
815
+ }
816
+ if (resolved.options?.modelerTemplateVersion) {
817
+ element.unknownAttributes["zeebe:modelerTemplateVersion"] =
818
+ resolved.options.modelerTemplateVersion;
819
+ }
820
+ if (resolved.options?.modelerTemplateIcon) {
821
+ element.unknownAttributes["zeebe:modelerTemplateIcon"] = resolved.options.modelerTemplateIcon;
822
+ }
823
+ if (element.type === "adHocSubProcess") {
824
+ element.flowElements = sub._elements;
825
+ element.sequenceFlows = sub._flows;
826
+ element.textAnnotations = sub._textAnnotations;
827
+ element.associations = sub._associations;
828
+ if (resolved.options?.loopCharacteristics) {
829
+ element.loopCharacteristics = buildAdHocLoopCharacteristics(resolved.options.loopCharacteristics);
830
+ }
831
+ else if (resolved.options?.multiInstance) {
832
+ element.loopCharacteristics = buildMultiInstance(resolved.options.multiInstance);
833
+ }
834
+ }
835
+ return this.addElement(element);
836
+ }
837
+ /** Add an event sub-process. Triggered by its start event — no incoming or outgoing sequence flows. */
838
+ eventSubProcess(id, content, options) {
839
+ const resolved = resolveSubProcessArgs(content, options);
840
+ const sub = new SubProcessContentBuilder(this.rootMessages);
841
+ resolved.content(sub);
842
+ insertJoinGateways(sub._elements, sub._flows);
843
+ recomputeIncomingOutgoing(sub._elements, sub._flows);
844
+ const element = makeFlowElement(id, "subProcess", resolved.options);
845
+ if (element.type === "subProcess") {
846
+ element.triggeredByEvent = true;
847
+ element.flowElements = sub._elements;
848
+ element.sequenceFlows = sub._flows;
849
+ element.textAnnotations = sub._textAnnotations;
850
+ element.associations = sub._associations;
851
+ }
852
+ // Event sub-processes have no incoming/outgoing sequence flows and must not
853
+ // advance the branch cursor — mirrors ProcessBuilder.eventSubProcess.
854
+ if (this._elements.some((n) => n.id === element.id)) {
855
+ throw new Error(`Duplicate element ID "${element.id}"`);
856
+ }
857
+ this._elements.push(element);
858
+ return this;
859
+ }
715
860
  /**
716
861
  * Create a named branch from the last gateway added inside this branch.
717
862
  *
@@ -976,6 +1121,172 @@ export class SubProcessContentBuilder {
976
1121
  this.currentGatewayId = undefined;
977
1122
  return this;
978
1123
  }
1124
+ // ---- Boundary events ----
1125
+ /**
1126
+ * Add a boundary event attached to an existing activity in this sub-process.
1127
+ *
1128
+ * The boundary event is NOT connected by a sequence flow — it attaches via
1129
+ * `attachedToRef`. The builder cursor advances to the boundary event so
1130
+ * subsequent elements chain from it. Use `withBoundary()` if you want the
1131
+ * cursor to return to the task afterward.
1132
+ */
1133
+ boundaryEvent(id, options) {
1134
+ const element = makeFlowElement(id, "boundaryEvent", options);
1135
+ if (element.type === "boundaryEvent") {
1136
+ element.attachedToRef = options.attachedTo;
1137
+ element.cancelActivity = options.cancelActivity;
1138
+ element.eventDefinitions = buildEventDefinitions(options);
1139
+ }
1140
+ // Push directly — no sequence flow, boundary events attach via attachedToRef
1141
+ this._elements.push(element);
1142
+ this.lastNodeId = element.id;
1143
+ return this;
1144
+ }
1145
+ /**
1146
+ * Attach a boundary event to the preceding task and build its outgoing path,
1147
+ * then restore the builder cursor to the preceding task so the main flow continues.
1148
+ *
1149
+ * @param id - ID for the boundary event element.
1150
+ * @param options - Boundary event options (without `attachedTo` — inferred from cursor).
1151
+ * @param handler - Callback that chains elements from the boundary event.
1152
+ */
1153
+ withBoundary(id, options, handler) {
1154
+ const attachedTo = this.lastNodeId;
1155
+ if (!attachedTo) {
1156
+ throw new Error("withBoundary() must follow a task element inside the sub-process. Current builder position has no active task.");
1157
+ }
1158
+ const attachedEl = this._elements.find((n) => n.id === attachedTo);
1159
+ if (attachedEl?.type === "boundaryEvent") {
1160
+ throw new Error("withBoundary() cannot attach to a boundary event. It must follow a task or activity element.");
1161
+ }
1162
+ const savedLast = this.lastNodeId;
1163
+ const savedGateway = this.currentGatewayId;
1164
+ const savedOpenEnds = [...this.openBranchEnds];
1165
+ this.openBranchEnds = [];
1166
+ // Create and push the boundary event (no sequence flow)
1167
+ this.boundaryEvent(id, { ...options, attachedTo });
1168
+ // Build the boundary event's outgoing path
1169
+ handler(this);
1170
+ // Restore cursor to the task so the sub-process main flow continues
1171
+ this.lastNodeId = savedLast;
1172
+ this.currentGatewayId = savedGateway;
1173
+ this.openBranchEnds = savedOpenEnds;
1174
+ return this;
1175
+ }
1176
+ // ---- Sub-process ----
1177
+ /** Add a sub-process nested inside this sub-process's content. */
1178
+ subProcess(id, content, options) {
1179
+ const resolved = resolveSubProcessArgs(content, options);
1180
+ const sub = new SubProcessContentBuilder(this.rootMessages);
1181
+ resolved.content(sub);
1182
+ insertJoinGateways(sub._elements, sub._flows);
1183
+ recomputeIncomingOutgoing(sub._elements, sub._flows);
1184
+ const element = makeFlowElement(id, "subProcess", resolved.options);
1185
+ if (element.type === "subProcess") {
1186
+ element.flowElements = sub._elements;
1187
+ element.sequenceFlows = sub._flows;
1188
+ element.textAnnotations = sub._textAnnotations;
1189
+ element.associations = sub._associations;
1190
+ if (resolved.options?.multiInstance) {
1191
+ element.loopCharacteristics = buildMultiInstance(resolved.options.multiInstance);
1192
+ }
1193
+ }
1194
+ return this.addElement(element);
1195
+ }
1196
+ /** Add an ad-hoc sub-process nested inside this sub-process's content. */
1197
+ adHocSubProcess(id, content, options) {
1198
+ const resolved = resolveSubProcessArgs(content, options);
1199
+ const sub = new SubProcessContentBuilder(this.rootMessages);
1200
+ resolved.content(sub);
1201
+ insertJoinGateways(sub._elements, sub._flows);
1202
+ recomputeIncomingOutgoing(sub._elements, sub._flows);
1203
+ const zeebeExt = {};
1204
+ if (resolved.options?.taskDefinition) {
1205
+ zeebeExt.taskDefinition = resolved.options.taskDefinition;
1206
+ }
1207
+ if (resolved.options?.ioMapping) {
1208
+ zeebeExt.ioMapping = {
1209
+ inputs: resolved.options.ioMapping.inputs ?? [],
1210
+ outputs: resolved.options.ioMapping.outputs ?? [],
1211
+ };
1212
+ }
1213
+ if (resolved.options?.taskHeaders) {
1214
+ zeebeExt.taskHeaders = {
1215
+ headers: Object.entries(resolved.options.taskHeaders).map(([key, value]) => ({
1216
+ key,
1217
+ value,
1218
+ })),
1219
+ };
1220
+ }
1221
+ const extensionElements = zeebeExtensionsToXmlElements(zeebeExt);
1222
+ const adHocAttrs = {};
1223
+ if (resolved.options?.activeElementsCollection) {
1224
+ adHocAttrs.activeElementsCollection = resolved.options.activeElementsCollection;
1225
+ }
1226
+ if (resolved.options?.outputCollection) {
1227
+ adHocAttrs.outputCollection = resolved.options.outputCollection;
1228
+ }
1229
+ if (resolved.options?.outputElement) {
1230
+ adHocAttrs.outputElement = resolved.options.outputElement;
1231
+ }
1232
+ if (Object.keys(adHocAttrs).length > 0) {
1233
+ extensionElements.push({
1234
+ name: "zeebe:adHoc",
1235
+ attributes: adHocAttrs,
1236
+ children: [],
1237
+ });
1238
+ }
1239
+ const element = makeFlowElement(id, "adHocSubProcess", {
1240
+ name: resolved.options?.name,
1241
+ extensionElements,
1242
+ });
1243
+ if (resolved.options?.modelerTemplate) {
1244
+ element.unknownAttributes["zeebe:modelerTemplate"] = resolved.options.modelerTemplate;
1245
+ }
1246
+ if (resolved.options?.modelerTemplateVersion) {
1247
+ element.unknownAttributes["zeebe:modelerTemplateVersion"] =
1248
+ resolved.options.modelerTemplateVersion;
1249
+ }
1250
+ if (resolved.options?.modelerTemplateIcon) {
1251
+ element.unknownAttributes["zeebe:modelerTemplateIcon"] = resolved.options.modelerTemplateIcon;
1252
+ }
1253
+ if (element.type === "adHocSubProcess") {
1254
+ element.flowElements = sub._elements;
1255
+ element.sequenceFlows = sub._flows;
1256
+ element.textAnnotations = sub._textAnnotations;
1257
+ element.associations = sub._associations;
1258
+ if (resolved.options?.loopCharacteristics) {
1259
+ element.loopCharacteristics = buildAdHocLoopCharacteristics(resolved.options.loopCharacteristics);
1260
+ }
1261
+ else if (resolved.options?.multiInstance) {
1262
+ element.loopCharacteristics = buildMultiInstance(resolved.options.multiInstance);
1263
+ }
1264
+ }
1265
+ return this.addElement(element);
1266
+ }
1267
+ /** Add an event sub-process. Triggered by its start event — no incoming or outgoing sequence flows. */
1268
+ eventSubProcess(id, content, options) {
1269
+ const resolved = resolveSubProcessArgs(content, options);
1270
+ const sub = new SubProcessContentBuilder(this.rootMessages);
1271
+ resolved.content(sub);
1272
+ insertJoinGateways(sub._elements, sub._flows);
1273
+ recomputeIncomingOutgoing(sub._elements, sub._flows);
1274
+ const element = makeFlowElement(id, "subProcess", resolved.options);
1275
+ if (element.type === "subProcess") {
1276
+ element.triggeredByEvent = true;
1277
+ element.flowElements = sub._elements;
1278
+ element.sequenceFlows = sub._flows;
1279
+ element.textAnnotations = sub._textAnnotations;
1280
+ element.associations = sub._associations;
1281
+ }
1282
+ // Event sub-processes have no incoming/outgoing sequence flows and must not
1283
+ // advance the cursor — mirrors ProcessBuilder.eventSubProcess.
1284
+ if (this._elements.some((n) => n.id === element.id)) {
1285
+ throw new Error(`Duplicate element ID "${element.id}" in sub-process`);
1286
+ }
1287
+ this._elements.push(element);
1288
+ return this;
1289
+ }
979
1290
  }
980
1291
  // ---------------------------------------------------------------------------
981
1292
  // Process builder (top-level entry point)
@@ -1374,36 +1685,40 @@ export class ProcessBuilder {
1374
1685
  // ---- Sub-processes ----
1375
1686
  /** Add an ad-hoc sub-process with optional AI agent or multi-instance configuration. */
1376
1687
  adHocSubProcess(id, content, options) {
1688
+ const resolved = resolveSubProcessArgs(content, options);
1377
1689
  const sub = new SubProcessContentBuilder(this.rootMessages);
1378
- content(sub);
1690
+ resolved.content(sub);
1379
1691
  insertJoinGateways(sub._elements, sub._flows);
1380
1692
  recomputeIncomingOutgoing(sub._elements, sub._flows);
1381
1693
  const zeebeExt = {};
1382
- if (options?.taskDefinition) {
1383
- zeebeExt.taskDefinition = options.taskDefinition;
1694
+ if (resolved.options?.taskDefinition) {
1695
+ zeebeExt.taskDefinition = resolved.options.taskDefinition;
1384
1696
  }
1385
- if (options?.ioMapping) {
1697
+ if (resolved.options?.ioMapping) {
1386
1698
  zeebeExt.ioMapping = {
1387
- inputs: options.ioMapping.inputs ?? [],
1388
- outputs: options.ioMapping.outputs ?? [],
1699
+ inputs: resolved.options.ioMapping.inputs ?? [],
1700
+ outputs: resolved.options.ioMapping.outputs ?? [],
1389
1701
  };
1390
1702
  }
1391
- if (options?.taskHeaders) {
1703
+ if (resolved.options?.taskHeaders) {
1392
1704
  zeebeExt.taskHeaders = {
1393
- headers: Object.entries(options.taskHeaders).map(([key, value]) => ({ key, value })),
1705
+ headers: Object.entries(resolved.options.taskHeaders).map(([key, value]) => ({
1706
+ key,
1707
+ value,
1708
+ })),
1394
1709
  };
1395
1710
  }
1396
1711
  const extensionElements = zeebeExtensionsToXmlElements(zeebeExt);
1397
1712
  // zeebe:adHoc element
1398
1713
  const adHocAttrs = {};
1399
- if (options?.activeElementsCollection) {
1400
- adHocAttrs.activeElementsCollection = options.activeElementsCollection;
1714
+ if (resolved.options?.activeElementsCollection) {
1715
+ adHocAttrs.activeElementsCollection = resolved.options.activeElementsCollection;
1401
1716
  }
1402
- if (options?.outputCollection) {
1403
- adHocAttrs.outputCollection = options.outputCollection;
1717
+ if (resolved.options?.outputCollection) {
1718
+ adHocAttrs.outputCollection = resolved.options.outputCollection;
1404
1719
  }
1405
- if (options?.outputElement) {
1406
- adHocAttrs.outputElement = options.outputElement;
1720
+ if (resolved.options?.outputElement) {
1721
+ adHocAttrs.outputElement = resolved.options.outputElement;
1407
1722
  }
1408
1723
  if (Object.keys(adHocAttrs).length > 0) {
1409
1724
  extensionElements.push({
@@ -1413,28 +1728,29 @@ export class ProcessBuilder {
1413
1728
  });
1414
1729
  }
1415
1730
  const element = makeFlowElement(id, "adHocSubProcess", {
1416
- name: options?.name,
1731
+ name: resolved.options?.name,
1417
1732
  extensionElements,
1418
1733
  });
1419
- if (options?.modelerTemplate) {
1420
- element.unknownAttributes["zeebe:modelerTemplate"] = options.modelerTemplate;
1734
+ if (resolved.options?.modelerTemplate) {
1735
+ element.unknownAttributes["zeebe:modelerTemplate"] = resolved.options.modelerTemplate;
1421
1736
  }
1422
- if (options?.modelerTemplateVersion) {
1423
- element.unknownAttributes["zeebe:modelerTemplateVersion"] = options.modelerTemplateVersion;
1737
+ if (resolved.options?.modelerTemplateVersion) {
1738
+ element.unknownAttributes["zeebe:modelerTemplateVersion"] =
1739
+ resolved.options.modelerTemplateVersion;
1424
1740
  }
1425
- if (options?.modelerTemplateIcon) {
1426
- element.unknownAttributes["zeebe:modelerTemplateIcon"] = options.modelerTemplateIcon;
1741
+ if (resolved.options?.modelerTemplateIcon) {
1742
+ element.unknownAttributes["zeebe:modelerTemplateIcon"] = resolved.options.modelerTemplateIcon;
1427
1743
  }
1428
1744
  if (element.type === "adHocSubProcess") {
1429
1745
  element.flowElements = sub._elements;
1430
1746
  element.sequenceFlows = sub._flows;
1431
1747
  element.textAnnotations = sub._textAnnotations;
1432
1748
  element.associations = sub._associations;
1433
- if (options?.loopCharacteristics) {
1434
- element.loopCharacteristics = buildAdHocLoopCharacteristics(options.loopCharacteristics);
1749
+ if (resolved.options?.loopCharacteristics) {
1750
+ element.loopCharacteristics = buildAdHocLoopCharacteristics(resolved.options.loopCharacteristics);
1435
1751
  }
1436
- else if (options?.multiInstance) {
1437
- element.loopCharacteristics = buildMultiInstance(options.multiInstance);
1752
+ else if (resolved.options?.multiInstance) {
1753
+ element.loopCharacteristics = buildMultiInstance(resolved.options.multiInstance);
1438
1754
  }
1439
1755
  }
1440
1756
  this.addFlowElement(element);
@@ -1442,18 +1758,19 @@ export class ProcessBuilder {
1442
1758
  }
1443
1759
  /** Add a sub-process (aspirational). */
1444
1760
  subProcess(id, content, options) {
1761
+ const resolved = resolveSubProcessArgs(content, options);
1445
1762
  const sub = new SubProcessContentBuilder(this.rootMessages);
1446
- content(sub);
1763
+ resolved.content(sub);
1447
1764
  insertJoinGateways(sub._elements, sub._flows);
1448
1765
  recomputeIncomingOutgoing(sub._elements, sub._flows);
1449
- const element = makeFlowElement(id, "subProcess", options);
1766
+ const element = makeFlowElement(id, "subProcess", resolved.options);
1450
1767
  if (element.type === "subProcess") {
1451
1768
  element.flowElements = sub._elements;
1452
1769
  element.sequenceFlows = sub._flows;
1453
1770
  element.textAnnotations = sub._textAnnotations;
1454
1771
  element.associations = sub._associations;
1455
- if (options?.multiInstance) {
1456
- element.loopCharacteristics = buildMultiInstance(options.multiInstance);
1772
+ if (resolved.options?.multiInstance) {
1773
+ element.loopCharacteristics = buildMultiInstance(resolved.options.multiInstance);
1457
1774
  }
1458
1775
  }
1459
1776
  this.addFlowElement(element);
@@ -1461,11 +1778,12 @@ export class ProcessBuilder {
1461
1778
  }
1462
1779
  /** Add an event sub-process. Triggered by its start event — no incoming or outgoing sequence flows. */
1463
1780
  eventSubProcess(id, content, options) {
1781
+ const resolved = resolveSubProcessArgs(content, options);
1464
1782
  const sub = new SubProcessContentBuilder(this.rootMessages);
1465
- content(sub);
1783
+ resolved.content(sub);
1466
1784
  insertJoinGateways(sub._elements, sub._flows);
1467
1785
  recomputeIncomingOutgoing(sub._elements, sub._flows);
1468
- const element = makeFlowElement(id, "subProcess", options);
1786
+ const element = makeFlowElement(id, "subProcess", resolved.options);
1469
1787
  if (element.type === "subProcess") {
1470
1788
  element.triggeredByEvent = true;
1471
1789
  element.flowElements = sub._elements;
@@ -1543,6 +1861,7 @@ export class ProcessBuilder {
1543
1861
  sequenceFlows: this.sequenceFlows,
1544
1862
  textAnnotations: this._textAnnotations,
1545
1863
  associations: this._associations,
1864
+ groups: [],
1546
1865
  unknownAttributes: {},
1547
1866
  };
1548
1867
  const defs = {
@@ -5,7 +5,7 @@ import type { XmlElement } from "../types/xml-element.js";
5
5
  * exhaustive `switch` statements and type-narrowing with the type guard helpers
6
6
  * exported from `@bpmnkit/core`.
7
7
  */
8
- export type BpmnElementType = "startEvent" | "endEvent" | "intermediateThrowEvent" | "intermediateCatchEvent" | "boundaryEvent" | "task" | "serviceTask" | "scriptTask" | "userTask" | "sendTask" | "receiveTask" | "businessRuleTask" | "manualTask" | "callActivity" | "exclusiveGateway" | "parallelGateway" | "inclusiveGateway" | "eventBasedGateway" | "complexGateway" | "subProcess" | "adHocSubProcess" | "eventSubProcess" | "transaction";
8
+ export type BpmnElementType = "startEvent" | "endEvent" | "intermediateThrowEvent" | "intermediateCatchEvent" | "boundaryEvent" | "task" | "serviceTask" | "scriptTask" | "userTask" | "sendTask" | "receiveTask" | "businessRuleTask" | "manualTask" | "callActivity" | "exclusiveGateway" | "parallelGateway" | "inclusiveGateway" | "eventBasedGateway" | "complexGateway" | "subProcess" | "adHocSubProcess" | "eventSubProcess" | "transaction" | "dataObject" | "dataObjectReference" | "dataStoreReference";
9
9
  /** Axis-aligned bounding box used by BPMN diagram interchange (BPMNDi). */
10
10
  export interface BpmnBounds {
11
11
  x: number;
@@ -150,6 +150,26 @@ export interface BpmnCallActivity extends BpmnFlowNodeBase {
150
150
  type: "callActivity";
151
151
  loopCharacteristics?: BpmnMultiInstanceLoopCharacteristics;
152
152
  }
153
+ /** A data object — a piece of information flowing through the process. */
154
+ export interface BpmnDataObject extends BpmnFlowNodeBase {
155
+ type: "dataObject";
156
+ /** When true, represents a collection of items. */
157
+ isCollection?: boolean;
158
+ }
159
+ /** A visual reference to a {@link BpmnDataObject} (the shape drawn on the canvas). */
160
+ export interface BpmnDataObjectReference extends BpmnFlowNodeBase {
161
+ type: "dataObjectReference";
162
+ /** Id of the referenced `dataObject`. */
163
+ dataObjectRef?: string;
164
+ /** When true, drawn with the collection (parallel-bars) marker. */
165
+ isCollection?: boolean;
166
+ }
167
+ /** A visual reference to a data store (drawn as a cylinder). */
168
+ export interface BpmnDataStoreReference extends BpmnFlowNodeBase {
169
+ type: "dataStoreReference";
170
+ /** Id of the referenced `dataStore`. */
171
+ dataStoreRef?: string;
172
+ }
153
173
  export interface BpmnSendTask extends BpmnFlowNodeBase {
154
174
  type: "sendTask";
155
175
  messageRef?: string;
@@ -167,6 +187,7 @@ export interface BpmnAdHocSubProcess extends BpmnFlowNodeBase {
167
187
  sequenceFlows: BpmnSequenceFlow[];
168
188
  textAnnotations: BpmnTextAnnotation[];
169
189
  associations: BpmnAssociation[];
190
+ groups: BpmnGroup[];
170
191
  }
171
192
  export interface BpmnSubProcess extends BpmnFlowNodeBase {
172
193
  type: "subProcess";
@@ -176,6 +197,7 @@ export interface BpmnSubProcess extends BpmnFlowNodeBase {
176
197
  sequenceFlows: BpmnSequenceFlow[];
177
198
  textAnnotations: BpmnTextAnnotation[];
178
199
  associations: BpmnAssociation[];
200
+ groups: BpmnGroup[];
179
201
  }
180
202
  export interface BpmnEventSubProcess extends BpmnFlowNodeBase {
181
203
  type: "eventSubProcess";
@@ -183,6 +205,7 @@ export interface BpmnEventSubProcess extends BpmnFlowNodeBase {
183
205
  sequenceFlows: BpmnSequenceFlow[];
184
206
  textAnnotations: BpmnTextAnnotation[];
185
207
  associations: BpmnAssociation[];
208
+ groups: BpmnGroup[];
186
209
  }
187
210
  export interface BpmnExclusiveGateway extends BpmnFlowNodeBase {
188
211
  type: "exclusiveGateway";
@@ -217,6 +240,7 @@ export interface BpmnTransaction extends BpmnFlowNodeBase {
217
240
  sequenceFlows: BpmnSequenceFlow[];
218
241
  textAnnotations: BpmnTextAnnotation[];
219
242
  associations: BpmnAssociation[];
243
+ groups: BpmnGroup[];
220
244
  }
221
245
  /**
222
246
  * Discriminated union of every BPMN flow node that can appear inside a
@@ -233,7 +257,7 @@ export interface BpmnTransaction extends BpmnFlowNodeBase {
233
257
  * }
234
258
  * ```
235
259
  */
236
- export type BpmnFlowElement = BpmnStartEvent | BpmnEndEvent | BpmnIntermediateCatchEvent | BpmnIntermediateThrowEvent | BpmnBoundaryEvent | BpmnTask | BpmnServiceTask | BpmnScriptTask | BpmnUserTask | BpmnSendTask | BpmnReceiveTask | BpmnBusinessRuleTask | BpmnManualTask | BpmnCallActivity | BpmnSubProcess | BpmnAdHocSubProcess | BpmnEventSubProcess | BpmnTransaction | BpmnExclusiveGateway | BpmnParallelGateway | BpmnInclusiveGateway | BpmnEventBasedGateway | BpmnComplexGateway;
260
+ export type BpmnFlowElement = BpmnStartEvent | BpmnEndEvent | BpmnIntermediateCatchEvent | BpmnIntermediateThrowEvent | BpmnBoundaryEvent | BpmnTask | BpmnServiceTask | BpmnScriptTask | BpmnUserTask | BpmnSendTask | BpmnReceiveTask | BpmnBusinessRuleTask | BpmnManualTask | BpmnCallActivity | BpmnSubProcess | BpmnAdHocSubProcess | BpmnEventSubProcess | BpmnTransaction | BpmnExclusiveGateway | BpmnParallelGateway | BpmnInclusiveGateway | BpmnEventBasedGateway | BpmnComplexGateway | BpmnDataObject | BpmnDataObjectReference | BpmnDataStoreReference;
237
261
  /** Backward-compat alias used by the layout module. */
238
262
  export type BpmnFlowNode = BpmnFlowElement;
239
263
  /**
@@ -264,6 +288,13 @@ export interface BpmnAssociation {
264
288
  associationDirection?: string;
265
289
  unknownAttributes: Record<string, string>;
266
290
  }
291
+ /** A group artifact — a dashed rounded rectangle visually grouping elements. */
292
+ export interface BpmnGroup {
293
+ id: string;
294
+ /** Id of the `categoryValue` supplying the group's label, if any. */
295
+ categoryValueRef?: string;
296
+ unknownAttributes: Record<string, string>;
297
+ }
267
298
  /** A swim lane within a pool (organises flow nodes visually). */
268
299
  export interface BpmnLane {
269
300
  id: string;
@@ -294,6 +325,7 @@ export interface BpmnProcess {
294
325
  sequenceFlows: BpmnSequenceFlow[];
295
326
  textAnnotations: BpmnTextAnnotation[];
296
327
  associations: BpmnAssociation[];
328
+ groups: BpmnGroup[];
297
329
  laneSet?: BpmnLaneSet;
298
330
  unknownAttributes: Record<string, string>;
299
331
  }
@@ -319,6 +351,7 @@ export interface BpmnCollaboration {
319
351
  messageFlows: BpmnMessageFlow[];
320
352
  textAnnotations: BpmnTextAnnotation[];
321
353
  associations: BpmnAssociation[];
354
+ groups: BpmnGroup[];
322
355
  extensionElements: XmlElement[];
323
356
  unknownAttributes: Record<string, string>;
324
357
  }