@bpmnkit/core 0.0.23 → 0.0.24

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.
@@ -1,7 +1,9 @@
1
- import { layoutProcess } from "../layout/layout-engine.js";
2
1
  import { generateId } from "../types/id-generator.js";
2
+ import { applyAutoLayout } from "./auto-layout.js";
3
3
  import { restConnectorRetries, restConnectorTaskType, restConnectorToIoMappingInputs, restConnectorToTaskHeaders, } from "./rest-connector.js";
4
4
  import { zeebeExtensionsToXmlElements } from "./zeebe-extensions.js";
5
+ // Keep in sync with packages/core/package.json version
6
+ const EXPORTER_VERSION = "0.0.23";
5
7
  // ---------------------------------------------------------------------------
6
8
  // Internal helpers
7
9
  // ---------------------------------------------------------------------------
@@ -155,46 +157,6 @@ function buildAdHocLoopCharacteristics(lc) {
155
157
  ],
156
158
  };
157
159
  }
158
- /** Convert a layout engine result into a BPMN diagram interchange structure. */
159
- function layoutResultToDiagram(processId, layout) {
160
- const shapes = layout.nodes.map((node) => {
161
- const shape = {
162
- id: `${node.id}_di`,
163
- bpmnElement: node.id,
164
- bounds: { ...node.bounds },
165
- unknownAttributes: {},
166
- };
167
- if (node.isExpanded !== undefined) {
168
- shape.isExpanded = node.isExpanded;
169
- }
170
- if (node.labelBounds) {
171
- shape.label = { bounds: { ...node.labelBounds } };
172
- }
173
- return shape;
174
- });
175
- const edges = layout.edges.map((edge) => {
176
- const diEdge = {
177
- id: `${edge.id}_di`,
178
- bpmnElement: edge.id,
179
- waypoints: edge.waypoints.map((wp) => ({ ...wp })),
180
- unknownAttributes: {},
181
- };
182
- if (edge.labelBounds) {
183
- diEdge.label = { bounds: { ...edge.labelBounds } };
184
- }
185
- return diEdge;
186
- });
187
- const plane = {
188
- id: `${processId}_di_plane`,
189
- bpmnElement: processId,
190
- shapes,
191
- edges,
192
- };
193
- return {
194
- id: `${processId}_di`,
195
- plane,
196
- };
197
- }
198
160
  function recomputeIncomingOutgoing(elements, flows) {
199
161
  for (const el of elements) {
200
162
  el.incoming = [];
@@ -236,6 +198,181 @@ function makeConditionExpression(expression) {
236
198
  };
237
199
  }
238
200
  // ---------------------------------------------------------------------------
201
+ // Element factory functions — shared by all three builder classes
202
+ // ---------------------------------------------------------------------------
203
+ function makeServiceTaskEl(id, options) {
204
+ const unknownAttributes = {};
205
+ if (options.modelerTemplate)
206
+ unknownAttributes["zeebe:modelerTemplate"] = options.modelerTemplate;
207
+ if (options.modelerTemplateVersion)
208
+ unknownAttributes["zeebe:modelerTemplateVersion"] = options.modelerTemplateVersion;
209
+ if (options.modelerTemplateIcon)
210
+ unknownAttributes["zeebe:modelerTemplateIcon"] = options.modelerTemplateIcon;
211
+ const el = makeFlowElement(id, "serviceTask", {
212
+ name: options.name,
213
+ extensionElements: buildServiceTaskExtensions(options),
214
+ });
215
+ el.unknownAttributes = unknownAttributes;
216
+ return el;
217
+ }
218
+ function makeScriptTaskEl(id, options) {
219
+ return makeFlowElement(id, "scriptTask", {
220
+ name: options.name,
221
+ extensionElements: zeebeExtensionsToXmlElements({
222
+ unknownElements: [
223
+ {
224
+ name: "zeebe:script",
225
+ attributes: { expression: options.expression, resultVariable: options.resultVariable },
226
+ children: [],
227
+ },
228
+ ],
229
+ }),
230
+ });
231
+ }
232
+ function makeUserTaskEl(id, options) {
233
+ const ext = zeebeExtensionsToXmlElements({
234
+ ...(options?.zeebeUserTask ? { userTask: true } : {}),
235
+ ...(options?.formId ? { formDefinition: { formId: options.formId } } : {}),
236
+ });
237
+ return makeFlowElement(id, "userTask", { name: options?.name, extensionElements: ext });
238
+ }
239
+ function makeBusinessRuleTaskEl(id, options) {
240
+ const ext = [];
241
+ if (options?.taskType) {
242
+ ext.push(...zeebeExtensionsToXmlElements({ taskDefinition: { type: options.taskType } }));
243
+ }
244
+ if (options?.decisionId) {
245
+ ext.push(...zeebeExtensionsToXmlElements({
246
+ calledDecision: {
247
+ decisionId: options.decisionId,
248
+ resultVariable: options.resultVariable ?? "result",
249
+ },
250
+ }));
251
+ }
252
+ return makeFlowElement(id, "businessRuleTask", { name: options?.name, extensionElements: ext });
253
+ }
254
+ function makeCallActivityEl(id, options) {
255
+ const attrs = { processId: options.processId };
256
+ if (options.propagateAllChildVariables !== undefined) {
257
+ attrs.propagateAllChildVariables = String(options.propagateAllChildVariables);
258
+ }
259
+ return makeFlowElement(id, "callActivity", {
260
+ name: options.name,
261
+ extensionElements: zeebeExtensionsToXmlElements({
262
+ unknownElements: [{ name: "zeebe:calledElement", attributes: attrs, children: [] }],
263
+ }),
264
+ });
265
+ }
266
+ function makeExclusiveGatewayEl(id, options) {
267
+ const el = makeFlowElement(id, "exclusiveGateway", options);
268
+ if (options?.defaultFlow && el.type === "exclusiveGateway") {
269
+ ;
270
+ el.default = options.defaultFlow;
271
+ }
272
+ return el;
273
+ }
274
+ function makeInclusiveGatewayEl(id, options) {
275
+ const el = makeFlowElement(id, "inclusiveGateway", options);
276
+ if (options?.defaultFlow && el.type === "inclusiveGateway") {
277
+ ;
278
+ el.default = options.defaultFlow;
279
+ }
280
+ return el;
281
+ }
282
+ // ---------------------------------------------------------------------------
283
+ // Shared graph helpers — used by ProcessBuilder and SubProcessContentBuilder
284
+ // ---------------------------------------------------------------------------
285
+ function insertJoinGateways(elements, flows) {
286
+ const GATEWAY_TYPES = new Set([
287
+ "exclusiveGateway",
288
+ "parallelGateway",
289
+ "inclusiveGateway",
290
+ "eventBasedGateway",
291
+ ]);
292
+ const elementTypes = new Map();
293
+ for (const el of elements)
294
+ elementTypes.set(el.id, el.type);
295
+ const outCount = new Map();
296
+ for (const flow of flows) {
297
+ outCount.set(flow.sourceRef, (outCount.get(flow.sourceRef) ?? 0) + 1);
298
+ }
299
+ const splitGateways = new Set();
300
+ for (const [id, count] of outCount) {
301
+ const type = elementTypes.get(id);
302
+ if (type && GATEWAY_TYPES.has(type) && count >= 2)
303
+ splitGateways.add(id);
304
+ }
305
+ if (splitGateways.size === 0)
306
+ return;
307
+ const incoming = new Map();
308
+ for (const flow of flows) {
309
+ const arr = incoming.get(flow.targetRef);
310
+ if (arr)
311
+ arr.push(flow);
312
+ else
313
+ incoming.set(flow.targetRef, [flow]);
314
+ }
315
+ for (const [targetId, inFlows] of incoming) {
316
+ if (inFlows.length < 2)
317
+ continue;
318
+ const splitToFlows = new Map();
319
+ for (const flow of inFlows) {
320
+ const split = traceBackToSplit(flow.sourceRef, splitGateways, flows);
321
+ if (split) {
322
+ const arr = splitToFlows.get(split);
323
+ if (arr)
324
+ arr.push(flow);
325
+ else
326
+ splitToFlows.set(split, [flow]);
327
+ }
328
+ }
329
+ for (const [splitId, convergingFlows] of splitToFlows) {
330
+ if (convergingFlows.length < 2)
331
+ continue;
332
+ const gwType = elementTypes.get(splitId);
333
+ if (!gwType)
334
+ continue;
335
+ const targetType = elementTypes.get(targetId);
336
+ if (targetType === gwType)
337
+ continue;
338
+ const joinId = `${splitId}_join`;
339
+ if (elementTypes.has(joinId))
340
+ continue;
341
+ const joinElement = makeFlowElement(joinId, gwType, {});
342
+ elements.push(joinElement);
343
+ elementTypes.set(joinId, gwType);
344
+ for (const flow of convergingFlows)
345
+ flow.targetRef = joinId;
346
+ flows.push({
347
+ id: generateId("Flow"),
348
+ sourceRef: joinId,
349
+ targetRef: targetId,
350
+ extensionElements: [],
351
+ unknownAttributes: {},
352
+ });
353
+ }
354
+ }
355
+ }
356
+ function traceBackToSplit(nodeId, splitGateways, flows) {
357
+ const visited = new Set();
358
+ let current = nodeId;
359
+ while (current) {
360
+ if (visited.has(current))
361
+ return undefined;
362
+ visited.add(current);
363
+ if (splitGateways.has(current))
364
+ return current;
365
+ const inFlows = flows.filter((f) => f.targetRef === current);
366
+ if (inFlows.length !== 1)
367
+ return undefined;
368
+ const prev = inFlows[0];
369
+ if (!prev)
370
+ return undefined;
371
+ current = prev.sourceRef;
372
+ }
373
+ return undefined;
374
+ }
375
+ // ---------------------------------------------------------------------------
239
376
  // Branch builder (used inside gateway branch callbacks)
240
377
  // ---------------------------------------------------------------------------
241
378
  /**
@@ -260,6 +397,11 @@ export class BranchBuilder {
260
397
  /** @internal – true once connectTo() has been called, meaning the branch end is already wired */
261
398
  _connected = false;
262
399
  /** @internal */
400
+ _textAnnotations = [];
401
+ /** @internal */
402
+ _associations = [];
403
+ _annCounters = new Map();
404
+ /** @internal */
263
405
  constructor(gatewayId, branchName) {
264
406
  this.gatewayId = gatewayId;
265
407
  this.branchName = branchName;
@@ -327,47 +469,35 @@ export class BranchBuilder {
327
469
  get _lastNodeId() {
328
470
  return this.lastNodeId;
329
471
  }
472
+ // ---- Annotations ----
473
+ /** Attach a text annotation to the element at the current cursor position. */
474
+ textAnnotation(text) {
475
+ return this.annotate(this.lastNodeId, text);
476
+ }
477
+ /** Attach a text annotation to an element by explicit ID. */
478
+ annotate(elementId, text) {
479
+ const n = (this._annCounters.get(elementId) ?? 0) + 1;
480
+ this._annCounters.set(elementId, n);
481
+ const annId = `TextAnnotation_${elementId}_${n}`;
482
+ this._textAnnotations.push({ id: annId, text, unknownAttributes: {} });
483
+ this._associations.push({
484
+ id: `Association_${elementId}_${n}`,
485
+ sourceRef: elementId,
486
+ targetRef: annId,
487
+ associationDirection: "None",
488
+ unknownAttributes: {},
489
+ });
490
+ return this;
491
+ }
330
492
  // ---- Flow-node methods (mirror ProcessBuilder) ----
331
493
  serviceTask(id, options) {
332
- const unknownAttributes = {};
333
- if (options.modelerTemplate)
334
- unknownAttributes["zeebe:modelerTemplate"] = options.modelerTemplate;
335
- if (options.modelerTemplateVersion)
336
- unknownAttributes["zeebe:modelerTemplateVersion"] = options.modelerTemplateVersion;
337
- if (options.modelerTemplateIcon)
338
- unknownAttributes["zeebe:modelerTemplateIcon"] = options.modelerTemplateIcon;
339
- const el = makeFlowElement(id, "serviceTask", {
340
- name: options.name,
341
- extensionElements: buildServiceTaskExtensions(options),
342
- });
343
- el.unknownAttributes = unknownAttributes;
344
- return this.addElement(el);
494
+ return this.addElement(makeServiceTaskEl(id, options));
345
495
  }
346
496
  userTask(id, options) {
347
- const ext = options?.formId
348
- ? zeebeExtensionsToXmlElements({ formDefinition: { formId: options.formId } })
349
- : [];
350
- return this.addElement(makeFlowElement(id, "userTask", {
351
- name: options?.name,
352
- extensionElements: ext,
353
- }));
497
+ return this.addElement(makeUserTaskEl(id, options));
354
498
  }
355
499
  scriptTask(id, options) {
356
- return this.addElement(makeFlowElement(id, "scriptTask", {
357
- name: options.name,
358
- extensionElements: zeebeExtensionsToXmlElements({
359
- unknownElements: [
360
- {
361
- name: "zeebe:script",
362
- attributes: {
363
- expression: options.expression,
364
- resultVariable: options.resultVariable,
365
- },
366
- children: [],
367
- },
368
- ],
369
- }),
370
- }));
500
+ return this.addElement(makeScriptTaskEl(id, options));
371
501
  }
372
502
  sendTask(id, options) {
373
503
  return this.addElement(makeFlowElement(id, "sendTask", options));
@@ -376,36 +506,10 @@ export class BranchBuilder {
376
506
  return this.addElement(makeFlowElement(id, "receiveTask", options));
377
507
  }
378
508
  businessRuleTask(id, options) {
379
- const ext = options?.decisionId
380
- ? zeebeExtensionsToXmlElements({
381
- calledDecision: {
382
- decisionId: options.decisionId,
383
- resultVariable: options.resultVariable ?? "result",
384
- },
385
- })
386
- : [];
387
- return this.addElement(makeFlowElement(id, "businessRuleTask", {
388
- name: options?.name,
389
- extensionElements: ext,
390
- }));
509
+ return this.addElement(makeBusinessRuleTaskEl(id, options));
391
510
  }
392
511
  callActivity(id, options) {
393
- const attrs = { processId: options.processId };
394
- if (options.propagateAllChildVariables !== undefined) {
395
- attrs.propagateAllChildVariables = String(options.propagateAllChildVariables);
396
- }
397
- return this.addElement(makeFlowElement(id, "callActivity", {
398
- name: options.name,
399
- extensionElements: zeebeExtensionsToXmlElements({
400
- unknownElements: [
401
- {
402
- name: "zeebe:calledElement",
403
- attributes: attrs,
404
- children: [],
405
- },
406
- ],
407
- }),
408
- }));
512
+ return this.addElement(makeCallActivityEl(id, options));
409
513
  }
410
514
  startEvent(id, options) {
411
515
  const el = makeFlowElement(id ?? generateId("StartEvent"), "startEvent", options);
@@ -416,7 +520,11 @@ export class BranchBuilder {
416
520
  return this.addElement(el);
417
521
  }
418
522
  endEvent(id, options) {
419
- return this.addElement(makeFlowElement(id ?? generateId("EndEvent"), "endEvent", options));
523
+ const el = makeFlowElement(id ?? generateId("EndEvent"), "endEvent", options);
524
+ if (el.type === "endEvent" && options) {
525
+ el.eventDefinitions = buildEventDefinitions(options);
526
+ }
527
+ return this.addElement(el);
420
528
  }
421
529
  intermediateThrowEvent(id, options) {
422
530
  const el = makeFlowElement(id ?? generateId("IntermediateThrowEvent"), "intermediateThrowEvent", options);
@@ -433,23 +541,13 @@ export class BranchBuilder {
433
541
  return this.addElement(el);
434
542
  }
435
543
  exclusiveGateway(id, options) {
436
- const el = makeFlowElement(id, "exclusiveGateway", options);
437
- if (options?.defaultFlow && el.type === "exclusiveGateway") {
438
- ;
439
- el.default = options.defaultFlow;
440
- }
441
- return this.addElement(el);
544
+ return this.addElement(makeExclusiveGatewayEl(id, options));
442
545
  }
443
546
  parallelGateway(id, options) {
444
547
  return this.addElement(makeFlowElement(id, "parallelGateway", options));
445
548
  }
446
549
  inclusiveGateway(id, options) {
447
- const el = makeFlowElement(id, "inclusiveGateway", options);
448
- if (options?.defaultFlow && el.type === "inclusiveGateway") {
449
- ;
450
- el.default = options.defaultFlow;
451
- }
452
- return this.addElement(el);
550
+ return this.addElement(makeInclusiveGatewayEl(id, options));
453
551
  }
454
552
  eventBasedGateway(id, options) {
455
553
  return this.addElement(makeFlowElement(id, "eventBasedGateway", options));
@@ -464,98 +562,182 @@ export class SubProcessContentBuilder {
464
562
  _elements = [];
465
563
  /** @internal */
466
564
  _flows = [];
565
+ /** @internal */
566
+ _textAnnotations = [];
567
+ /** @internal */
568
+ _associations = [];
569
+ _annCounters = new Map();
467
570
  lastNodeId;
571
+ currentGatewayId;
572
+ openBranchEnds = [];
468
573
  addElement(element) {
574
+ if (this._elements.some((n) => n.id === element.id)) {
575
+ throw new Error(`Duplicate element ID "${element.id}" in sub-process`);
576
+ }
469
577
  this._elements.push(element);
470
578
  if (this.lastNodeId) {
471
- const flowId = generateId("Flow");
472
579
  this._flows.push({
473
- id: flowId,
580
+ id: generateId("Flow"),
474
581
  sourceRef: this.lastNodeId,
475
582
  targetRef: element.id,
476
583
  extensionElements: [],
477
584
  unknownAttributes: {},
478
585
  });
479
586
  }
587
+ for (const branchEnd of this.openBranchEnds) {
588
+ this._flows.push({
589
+ id: generateId("Flow"),
590
+ sourceRef: branchEnd,
591
+ targetRef: element.id,
592
+ extensionElements: [],
593
+ unknownAttributes: {},
594
+ });
595
+ }
596
+ this.openBranchEnds = [];
480
597
  this.lastNodeId = element.id;
481
598
  return this;
482
599
  }
600
+ // ---- Events ----
483
601
  startEvent(id, options) {
484
602
  const el = makeFlowElement(id ?? generateId("StartEvent"), "startEvent", options);
485
- if (el.type === "startEvent" && options) {
603
+ if (el.type === "startEvent" && options)
486
604
  el.eventDefinitions = buildEventDefinitions(options);
487
- }
488
605
  return this.addElement(el);
489
606
  }
490
607
  endEvent(id, options) {
491
- return this.addElement(makeFlowElement(id ?? generateId("EndEvent"), "endEvent", options));
608
+ const el = makeFlowElement(id ?? generateId("EndEvent"), "endEvent", options);
609
+ if (el.type === "endEvent" && options)
610
+ el.eventDefinitions = buildEventDefinitions(options);
611
+ return this.addElement(el);
492
612
  }
493
- serviceTask(id, options) {
494
- const unknownAttributes = {};
495
- if (options.modelerTemplate)
496
- unknownAttributes["zeebe:modelerTemplate"] = options.modelerTemplate;
497
- if (options.modelerTemplateVersion)
498
- unknownAttributes["zeebe:modelerTemplateVersion"] = options.modelerTemplateVersion;
499
- if (options.modelerTemplateIcon)
500
- unknownAttributes["zeebe:modelerTemplateIcon"] = options.modelerTemplateIcon;
501
- const el = makeFlowElement(id, "serviceTask", {
502
- name: options.name,
503
- extensionElements: buildServiceTaskExtensions(options),
504
- });
505
- el.unknownAttributes = unknownAttributes;
613
+ intermediateThrowEvent(id, options) {
614
+ const el = makeFlowElement(id ?? generateId("IntermediateThrowEvent"), "intermediateThrowEvent", options);
615
+ if (el.type === "intermediateThrowEvent" && options)
616
+ el.eventDefinitions = buildEventDefinitions(options);
506
617
  return this.addElement(el);
507
618
  }
508
- userTask(id, options) {
509
- return this.addElement(makeFlowElement(id, "userTask", { name: options?.name }));
619
+ intermediateCatchEvent(id, options) {
620
+ const el = makeFlowElement(id ?? generateId("IntermediateCatchEvent"), "intermediateCatchEvent", options);
621
+ if (el.type === "intermediateCatchEvent" && options)
622
+ el.eventDefinitions = buildEventDefinitions(options);
623
+ return this.addElement(el);
624
+ }
625
+ // ---- Tasks ----
626
+ serviceTask(id, options) {
627
+ return this.addElement(makeServiceTaskEl(id, options));
510
628
  }
511
629
  scriptTask(id, options) {
512
- return this.addElement(makeFlowElement(id, "scriptTask", {
513
- name: options.name,
514
- extensionElements: zeebeExtensionsToXmlElements({
515
- unknownElements: [
516
- {
517
- name: "zeebe:script",
518
- attributes: {
519
- expression: options.expression,
520
- resultVariable: options.resultVariable,
521
- },
522
- children: [],
523
- },
524
- ],
525
- }),
526
- }));
630
+ return this.addElement(makeScriptTaskEl(id, options));
631
+ }
632
+ userTask(id, options) {
633
+ return this.addElement(makeUserTaskEl(id, options));
634
+ }
635
+ businessRuleTask(id, options) {
636
+ return this.addElement(makeBusinessRuleTaskEl(id, options));
527
637
  }
528
638
  callActivity(id, options) {
529
- const attrs = { processId: options.processId };
530
- if (options.propagateAllChildVariables !== undefined) {
531
- attrs.propagateAllChildVariables = String(options.propagateAllChildVariables);
639
+ return this.addElement(makeCallActivityEl(id, options));
640
+ }
641
+ sendTask(id, options) {
642
+ return this.addElement(makeFlowElement(id, "sendTask", options));
643
+ }
644
+ receiveTask(id, options) {
645
+ return this.addElement(makeFlowElement(id, "receiveTask", options));
646
+ }
647
+ // ---- Gateways ----
648
+ exclusiveGateway(id, options) {
649
+ this.currentGatewayId = id;
650
+ return this.addElement(makeExclusiveGatewayEl(id, options));
651
+ }
652
+ parallelGateway(id, options) {
653
+ this.currentGatewayId = id;
654
+ return this.addElement(makeFlowElement(id, "parallelGateway", options));
655
+ }
656
+ inclusiveGateway(id, options) {
657
+ this.currentGatewayId = id;
658
+ return this.addElement(makeInclusiveGatewayEl(id, options));
659
+ }
660
+ eventBasedGateway(id, options) {
661
+ this.currentGatewayId = id;
662
+ return this.addElement(makeFlowElement(id, "eventBasedGateway", options));
663
+ }
664
+ // ---- Annotations ----
665
+ /** Attach a text annotation to the element at the current cursor position. */
666
+ textAnnotation(text) {
667
+ if (!this.lastNodeId) {
668
+ throw new Error("textAnnotation() must follow a flow element");
532
669
  }
533
- return this.addElement(makeFlowElement(id, "callActivity", {
534
- name: options.name,
535
- extensionElements: zeebeExtensionsToXmlElements({
536
- unknownElements: [
537
- {
538
- name: "zeebe:calledElement",
539
- attributes: attrs,
540
- children: [],
541
- },
542
- ],
543
- }),
544
- }));
670
+ return this.annotate(this.lastNodeId, text);
671
+ }
672
+ /** Attach a text annotation to an element by explicit ID. */
673
+ annotate(elementId, text) {
674
+ const n = (this._annCounters.get(elementId) ?? 0) + 1;
675
+ this._annCounters.set(elementId, n);
676
+ const annId = `TextAnnotation_${elementId}_${n}`;
677
+ this._textAnnotations.push({ id: annId, text, unknownAttributes: {} });
678
+ this._associations.push({
679
+ id: `Association_${elementId}_${n}`,
680
+ sourceRef: elementId,
681
+ targetRef: annId,
682
+ associationDirection: "None",
683
+ unknownAttributes: {},
684
+ });
685
+ return this;
545
686
  }
546
- intermediateThrowEvent(id, options) {
547
- const el = makeFlowElement(id ?? generateId("IntermediateThrowEvent"), "intermediateThrowEvent", options);
548
- if (el.type === "intermediateThrowEvent" && options) {
549
- el.eventDefinitions = buildEventDefinitions(options);
687
+ // ---- Branching & flow control ----
688
+ branch(name, callback) {
689
+ if (!this.currentGatewayId) {
690
+ throw new Error("branch() must be called after a gateway element");
550
691
  }
551
- return this.addElement(el);
692
+ const b = new BranchBuilder(this.currentGatewayId, name);
693
+ callback(b);
694
+ for (const el of b._elements) {
695
+ if (this._elements.some((n) => n.id === el.id)) {
696
+ throw new Error(`Duplicate element ID "${el.id}"`);
697
+ }
698
+ this._elements.push(el);
699
+ }
700
+ for (const fl of b._flows)
701
+ this._flows.push(fl);
702
+ for (const ann of b._textAnnotations)
703
+ this._textAnnotations.push(ann);
704
+ for (const assoc of b._associations)
705
+ this._associations.push(assoc);
706
+ if (b._defaultFlowId) {
707
+ const gw = this._elements.find((n) => n.id === this.currentGatewayId);
708
+ if (gw && (gw.type === "exclusiveGateway" || gw.type === "inclusiveGateway")) {
709
+ gw.default = b._defaultFlowId;
710
+ }
711
+ }
712
+ if (!b._connected && b._elements.length > 0) {
713
+ const lastEl = b._elements[b._elements.length - 1];
714
+ if (lastEl && lastEl.type !== "endEvent") {
715
+ this.openBranchEnds.push(b._lastNodeId);
716
+ }
717
+ }
718
+ this.lastNodeId = undefined;
719
+ return this;
552
720
  }
553
- intermediateCatchEvent(id, options) {
554
- const el = makeFlowElement(id ?? generateId("IntermediateCatchEvent"), "intermediateCatchEvent", options);
555
- if (el.type === "intermediateCatchEvent" && options) {
556
- el.eventDefinitions = buildEventDefinitions(options);
721
+ connectTo(targetId) {
722
+ if (this.lastNodeId) {
723
+ this._flows.push({
724
+ id: generateId("Flow"),
725
+ sourceRef: this.lastNodeId,
726
+ targetRef: targetId,
727
+ extensionElements: [],
728
+ unknownAttributes: {},
729
+ });
557
730
  }
558
- return this.addElement(el);
731
+ this.lastNodeId = undefined;
732
+ return this;
733
+ }
734
+ element(elementId) {
735
+ if (!this._elements.some((n) => n.id === elementId)) {
736
+ throw new Error(`Element "${elementId}" not found in sub-process`);
737
+ }
738
+ this.lastNodeId = elementId;
739
+ this.currentGatewayId = undefined;
740
+ return this;
559
741
  }
560
742
  }
561
743
  // ---------------------------------------------------------------------------
@@ -571,10 +753,15 @@ export class ProcessBuilder {
571
753
  sequenceFlows = [];
572
754
  rootErrors = [];
573
755
  rootMessages = [];
756
+ _textAnnotations = [];
757
+ _associations = [];
758
+ _annCounters = new Map();
574
759
  lastNodeId;
575
760
  currentGatewayId;
576
761
  openBranchEnds = [];
577
762
  _autoLayout = false;
763
+ _executionPlatformVersion = "8.9.0";
764
+ _serviceTaskDefaults = {};
578
765
  constructor(processId) {
579
766
  this.processId = processId;
580
767
  }
@@ -583,6 +770,17 @@ export class ProcessBuilder {
583
770
  this._autoLayout = true;
584
771
  return this;
585
772
  }
773
+ /** Set the Camunda execution platform version stamped into the BPMN definitions. Defaults to `"8.9.0"`. */
774
+ executionPlatformVersion(version) {
775
+ this._executionPlatformVersion = version;
776
+ return this;
777
+ }
778
+ /** Set process-wide defaults applied to subsequently added elements. */
779
+ defaults(options) {
780
+ if (options.serviceTask)
781
+ this._serviceTaskDefaults = { ...this._serviceTaskDefaults, ...options.serviceTask };
782
+ return this;
783
+ }
586
784
  /** Set the display name for this process. */
587
785
  name(name) {
588
786
  this.processName = name;
@@ -639,10 +837,22 @@ export class ProcessBuilder {
639
837
  this.currentGatewayId = undefined;
640
838
  return this.startEvent(id, options);
641
839
  }
840
+ /**
841
+ * Alias for `addStartEvent()` — begins a new disconnected parallel path.
842
+ *
843
+ * Use this for readability when modeling processes with multiple independent paths.
844
+ */
845
+ disconnectedStartEvent(id, options) {
846
+ return this.addStartEvent(id, options);
847
+ }
642
848
  /** Add an end event. */
643
849
  endEvent(id, options) {
644
850
  const nodeId = id ?? generateId("EndEvent");
645
- this.addFlowElement(makeFlowElement(nodeId, "endEvent", options));
851
+ const element = makeFlowElement(nodeId, "endEvent", options);
852
+ if (element.type === "endEvent" && options) {
853
+ element.eventDefinitions = buildEventDefinitions(options, this.rootErrors, this.rootMessages);
854
+ }
855
+ this.addFlowElement(element);
646
856
  return this;
647
857
  }
648
858
  /** Add an intermediate throw event (none, message, signal, escalation). */
@@ -686,22 +896,41 @@ export class ProcessBuilder {
686
896
  void prevLast;
687
897
  return this;
688
898
  }
899
+ /**
900
+ * Attach a boundary event to the preceding task and build its outgoing path,
901
+ * then restore the builder cursor to the preceding task so the main flow continues.
902
+ *
903
+ * @param id - ID for the boundary event element.
904
+ * @param options - Boundary event options (without `attachedTo` — inferred from cursor).
905
+ * @param handler - Callback that chains elements from the boundary event.
906
+ */
907
+ withBoundary(id, options, handler) {
908
+ const attachedTo = this.lastNodeId;
909
+ if (!attachedTo) {
910
+ throw new Error("withBoundary() must follow a task element. Current builder position has no active element.");
911
+ }
912
+ const savedLast = this.lastNodeId;
913
+ const savedGateway = this.currentGatewayId;
914
+ const savedOpenEnds = [...this.openBranchEnds];
915
+ this.openBranchEnds = [];
916
+ // boundaryEvent() sets lastNodeId to the boundary event id
917
+ this.boundaryEvent(id, { ...options, attachedTo });
918
+ // Build the error/timeout path chaining from the boundary event
919
+ handler(this);
920
+ // Restore cursor to the original task so the main flow continues
921
+ this.lastNodeId = savedLast;
922
+ this.currentGatewayId = savedGateway;
923
+ this.openBranchEnds = savedOpenEnds;
924
+ return this;
925
+ }
689
926
  // ---- Tasks ----
690
927
  /** Add a service task with Zeebe task definition and optional IO mappings. */
691
928
  serviceTask(id, options) {
692
- const unknownAttributes = {};
693
- if (options.modelerTemplate)
694
- unknownAttributes["zeebe:modelerTemplate"] = options.modelerTemplate;
695
- if (options.modelerTemplateVersion)
696
- unknownAttributes["zeebe:modelerTemplateVersion"] = options.modelerTemplateVersion;
697
- if (options.modelerTemplateIcon)
698
- unknownAttributes["zeebe:modelerTemplateIcon"] = options.modelerTemplateIcon;
699
- const el = makeFlowElement(id, "serviceTask", {
700
- name: options.name,
701
- extensionElements: buildServiceTaskExtensions(options),
702
- });
703
- el.unknownAttributes = unknownAttributes;
704
- this.addFlowElement(el);
929
+ const merged = {
930
+ ...options,
931
+ retries: options.retries ?? this._serviceTaskDefaults.retries,
932
+ };
933
+ this.addFlowElement(makeServiceTaskEl(id, merged));
705
934
  return this;
706
935
  }
707
936
  /** Add a REST connector task — syntactic sugar over `serviceTask()`. */
@@ -732,32 +961,12 @@ export class ProcessBuilder {
732
961
  }
733
962
  /** Add a script task with a FEEL expression. */
734
963
  scriptTask(id, options) {
735
- this.addFlowElement(makeFlowElement(id, "scriptTask", {
736
- name: options.name,
737
- extensionElements: zeebeExtensionsToXmlElements({
738
- unknownElements: [
739
- {
740
- name: "zeebe:script",
741
- attributes: {
742
- expression: options.expression,
743
- resultVariable: options.resultVariable,
744
- },
745
- children: [],
746
- },
747
- ],
748
- }),
749
- }));
964
+ this.addFlowElement(makeScriptTaskEl(id, options));
750
965
  return this;
751
966
  }
752
967
  /** Add a user task with optional form reference. */
753
968
  userTask(id, options) {
754
- const extensionElements = options?.formId
755
- ? zeebeExtensionsToXmlElements({ formDefinition: { formId: options.formId } })
756
- : [];
757
- this.addFlowElement(makeFlowElement(id, "userTask", {
758
- name: options?.name,
759
- extensionElements,
760
- }));
969
+ this.addFlowElement(makeUserTaskEl(id, options));
761
970
  return this;
762
971
  }
763
972
  /** Add a send task (aspirational). */
@@ -772,55 +981,18 @@ export class ProcessBuilder {
772
981
  }
773
982
  /** Add a business rule task. */
774
983
  businessRuleTask(id, options) {
775
- const ext = [];
776
- if (options?.taskType) {
777
- ext.push(...zeebeExtensionsToXmlElements({ taskDefinition: { type: options.taskType } }));
778
- }
779
- if (options?.decisionId) {
780
- ext.push(...zeebeExtensionsToXmlElements({
781
- calledDecision: {
782
- decisionId: options.decisionId,
783
- resultVariable: options.resultVariable ?? "result",
784
- },
785
- }));
786
- }
787
- this.addFlowElement(makeFlowElement(id, "businessRuleTask", {
788
- name: options?.name,
789
- extensionElements: ext,
790
- }));
984
+ this.addFlowElement(makeBusinessRuleTaskEl(id, options));
791
985
  return this;
792
986
  }
793
987
  /** Add a call activity referencing another process. */
794
988
  callActivity(id, options) {
795
- const attrs = {
796
- processId: options.processId,
797
- };
798
- if (options.propagateAllChildVariables !== undefined) {
799
- attrs.propagateAllChildVariables = String(options.propagateAllChildVariables);
800
- }
801
- this.addFlowElement(makeFlowElement(id, "callActivity", {
802
- name: options.name,
803
- extensionElements: zeebeExtensionsToXmlElements({
804
- unknownElements: [
805
- {
806
- name: "zeebe:calledElement",
807
- attributes: attrs,
808
- children: [],
809
- },
810
- ],
811
- }),
812
- }));
989
+ this.addFlowElement(makeCallActivityEl(id, options));
813
990
  return this;
814
991
  }
815
992
  // ---- Gateways ----
816
993
  /** Add an exclusive gateway (XOR split/join). */
817
994
  exclusiveGateway(id, options) {
818
- const element = makeFlowElement(id, "exclusiveGateway", options);
819
- if (options?.defaultFlow && element.type === "exclusiveGateway") {
820
- ;
821
- element.default = options.defaultFlow;
822
- }
823
- this.addFlowElement(element);
995
+ this.addFlowElement(makeExclusiveGatewayEl(id, options));
824
996
  this.currentGatewayId = id;
825
997
  return this;
826
998
  }
@@ -832,12 +1004,7 @@ export class ProcessBuilder {
832
1004
  }
833
1005
  /** Add an inclusive gateway (OR split/join). Aspirational. */
834
1006
  inclusiveGateway(id, options) {
835
- const element = makeFlowElement(id, "inclusiveGateway", options);
836
- if (options?.defaultFlow && element.type === "inclusiveGateway") {
837
- ;
838
- element.default = options.defaultFlow;
839
- }
840
- this.addFlowElement(element);
1007
+ this.addFlowElement(makeInclusiveGatewayEl(id, options));
841
1008
  this.currentGatewayId = id;
842
1009
  return this;
843
1010
  }
@@ -880,6 +1047,10 @@ export class ProcessBuilder {
880
1047
  for (const fl of b._flows) {
881
1048
  this.sequenceFlows.push(fl);
882
1049
  }
1050
+ for (const ann of b._textAnnotations)
1051
+ this._textAnnotations.push(ann);
1052
+ for (const assoc of b._associations)
1053
+ this._associations.push(assoc);
883
1054
  // If the branch is the default flow, set the gateway's default
884
1055
  if (b._defaultFlowId) {
885
1056
  const gateway = this.flowElements.find((n) => n.id === this.currentGatewayId);
@@ -933,6 +1104,7 @@ export class ProcessBuilder {
933
1104
  adHocSubProcess(id, content, options) {
934
1105
  const sub = new SubProcessContentBuilder();
935
1106
  content(sub);
1107
+ insertJoinGateways(sub._elements, sub._flows);
936
1108
  recomputeIncomingOutgoing(sub._elements, sub._flows);
937
1109
  const zeebeExt = {};
938
1110
  if (options?.taskDefinition) {
@@ -984,6 +1156,8 @@ export class ProcessBuilder {
984
1156
  if (element.type === "adHocSubProcess") {
985
1157
  element.flowElements = sub._elements;
986
1158
  element.sequenceFlows = sub._flows;
1159
+ element.textAnnotations = sub._textAnnotations;
1160
+ element.associations = sub._associations;
987
1161
  if (options?.loopCharacteristics) {
988
1162
  element.loopCharacteristics = buildAdHocLoopCharacteristics(options.loopCharacteristics);
989
1163
  }
@@ -998,11 +1172,14 @@ export class ProcessBuilder {
998
1172
  subProcess(id, content, options) {
999
1173
  const sub = new SubProcessContentBuilder();
1000
1174
  content(sub);
1175
+ insertJoinGateways(sub._elements, sub._flows);
1001
1176
  recomputeIncomingOutgoing(sub._elements, sub._flows);
1002
1177
  const element = makeFlowElement(id, "subProcess", options);
1003
1178
  if (element.type === "subProcess") {
1004
1179
  element.flowElements = sub._elements;
1005
1180
  element.sequenceFlows = sub._flows;
1181
+ element.textAnnotations = sub._textAnnotations;
1182
+ element.associations = sub._associations;
1006
1183
  if (options?.multiInstance) {
1007
1184
  element.loopCharacteristics = buildMultiInstance(options.multiInstance);
1008
1185
  }
@@ -1014,15 +1191,41 @@ export class ProcessBuilder {
1014
1191
  eventSubProcess(id, content, options) {
1015
1192
  const sub = new SubProcessContentBuilder();
1016
1193
  content(sub);
1194
+ insertJoinGateways(sub._elements, sub._flows);
1017
1195
  recomputeIncomingOutgoing(sub._elements, sub._flows);
1018
1196
  const element = makeFlowElement(id, "eventSubProcess", options);
1019
1197
  if (element.type === "eventSubProcess") {
1020
1198
  element.flowElements = sub._elements;
1021
1199
  element.sequenceFlows = sub._flows;
1200
+ element.textAnnotations = sub._textAnnotations;
1201
+ element.associations = sub._associations;
1022
1202
  }
1023
1203
  this.addFlowElement(element);
1024
1204
  return this;
1025
1205
  }
1206
+ // ---- Annotations ----
1207
+ /** Attach a text annotation to the element at the current cursor position. */
1208
+ textAnnotation(text) {
1209
+ if (!this.lastNodeId) {
1210
+ throw new Error("textAnnotation() must follow a flow element");
1211
+ }
1212
+ return this.annotate(this.lastNodeId, text);
1213
+ }
1214
+ /** Attach a text annotation to any flow element by explicit ID. */
1215
+ annotate(elementId, text) {
1216
+ const n = (this._annCounters.get(elementId) ?? 0) + 1;
1217
+ this._annCounters.set(elementId, n);
1218
+ const annId = `TextAnnotation_${elementId}_${n}`;
1219
+ this._textAnnotations.push({ id: annId, text, unknownAttributes: {} });
1220
+ this._associations.push({
1221
+ id: `Association_${elementId}_${n}`,
1222
+ sourceRef: elementId,
1223
+ targetRef: annId,
1224
+ associationDirection: "None",
1225
+ unknownAttributes: {},
1226
+ });
1227
+ return this;
1228
+ }
1026
1229
  // ---- Build ----
1027
1230
  /**
1028
1231
  * Build the complete BPMN definitions model.
@@ -1030,8 +1233,17 @@ export class ProcessBuilder {
1030
1233
  * Resolves all forward-referenced `incoming` / `outgoing` arrays and wraps
1031
1234
  * the process in a {@link BpmnDefinitions} ready for XML serialization.
1032
1235
  */
1033
- build() {
1034
- this.insertJoinGateways();
1236
+ build(options) {
1237
+ const beforeCount = this.flowElements.length;
1238
+ insertJoinGateways(this.flowElements, this.sequenceFlows);
1239
+ if (options?.strict && this.flowElements.length > beforeCount) {
1240
+ const inserted = this.flowElements
1241
+ .slice(beforeCount)
1242
+ .map((e) => e.id)
1243
+ .join(", ");
1244
+ throw new Error(`auto-join gateways were inserted: ${inserted}. Use explicit .connectTo(joinId) to make gateway topology explicit, or remove { strict: true }.`);
1245
+ }
1246
+ this.validate();
1035
1247
  recomputeIncomingOutgoing(this.flowElements, this.sequenceFlows);
1036
1248
  const extensionElements = [];
1037
1249
  if (this._versionTag) {
@@ -1048,15 +1260,15 @@ export class ProcessBuilder {
1048
1260
  extensionElements,
1049
1261
  flowElements: this.flowElements,
1050
1262
  sequenceFlows: this.sequenceFlows,
1051
- textAnnotations: [],
1052
- associations: [],
1263
+ textAnnotations: this._textAnnotations,
1264
+ associations: this._associations,
1053
1265
  unknownAttributes: {},
1054
1266
  };
1055
- return {
1267
+ const defs = {
1056
1268
  id: "Definitions_1",
1057
1269
  targetNamespace: "http://bpmn.io/schema/bpmn",
1058
1270
  exporter: "@bpmnkit/core",
1059
- exporterVersion: "0.0.1",
1271
+ exporterVersion: EXPORTER_VERSION,
1060
1272
  namespaces: {
1061
1273
  bpmn: "http://www.omg.org/spec/BPMN/20100524/MODEL",
1062
1274
  bpmndi: "http://www.omg.org/spec/BPMN/20100524/DI",
@@ -1068,7 +1280,7 @@ export class ProcessBuilder {
1068
1280
  },
1069
1281
  unknownAttributes: {
1070
1282
  "modeler:executionPlatform": "Camunda Cloud",
1071
- "modeler:executionPlatformVersion": "8.6.0",
1283
+ "modeler:executionPlatformVersion": this._executionPlatformVersion,
1072
1284
  },
1073
1285
  errors: this.rootErrors,
1074
1286
  escalations: [],
@@ -1076,121 +1288,36 @@ export class ProcessBuilder {
1076
1288
  signals: [],
1077
1289
  collaborations: [],
1078
1290
  processes: [process],
1079
- diagrams: this._autoLayout ? [this.buildDiagram(process)] : [],
1291
+ // Seed diagram stub so applyAutoLayout preserves process-specific IDs.
1292
+ diagrams: this._autoLayout
1293
+ ? [
1294
+ {
1295
+ id: `${this.processId}_di`,
1296
+ plane: {
1297
+ id: `${this.processId}_di_plane`,
1298
+ bpmnElement: this.processId,
1299
+ shapes: [],
1300
+ edges: [],
1301
+ },
1302
+ },
1303
+ ]
1304
+ : [],
1080
1305
  };
1306
+ return this._autoLayout ? applyAutoLayout(defs) : defs;
1081
1307
  }
1082
- buildDiagram(process) {
1083
- const layoutResult = layoutProcess(process);
1084
- return layoutResultToDiagram(this.processId, layoutResult);
1085
- }
1086
- // ---- Internal ----
1087
- /**
1088
- * Insert matching join gateways where split-gateway branches converge
1089
- * on a non-gateway target. BPMN best practice: every split has a join.
1090
- */
1091
- insertJoinGateways() {
1092
- const GATEWAY_TYPES = new Set([
1093
- "exclusiveGateway",
1094
- "parallelGateway",
1095
- "inclusiveGateway",
1096
- "eventBasedGateway",
1097
- ]);
1098
- const elementTypes = new Map();
1099
- for (const el of this.flowElements) {
1100
- elementTypes.set(el.id, el.type);
1101
- }
1102
- // Find split gateways (2+ outgoing flows)
1103
- const outCount = new Map();
1104
- for (const flow of this.sequenceFlows) {
1105
- outCount.set(flow.sourceRef, (outCount.get(flow.sourceRef) ?? 0) + 1);
1106
- }
1107
- const splitGateways = new Set();
1108
- for (const [id, count] of outCount) {
1109
- const type = elementTypes.get(id);
1110
- if (type && GATEWAY_TYPES.has(type) && count >= 2) {
1111
- splitGateways.add(id);
1112
- }
1113
- }
1114
- if (splitGateways.size === 0)
1115
- return;
1116
- // Build incoming flow map
1117
- const incoming = new Map();
1308
+ validate() {
1309
+ const elementIds = new Set(this.flowElements.map((el) => el.id));
1118
1310
  for (const flow of this.sequenceFlows) {
1119
- const arr = incoming.get(flow.targetRef);
1120
- if (arr)
1121
- arr.push(flow);
1122
- else
1123
- incoming.set(flow.targetRef, [flow]);
1124
- }
1125
- // For each target with 2+ incoming flows, check if they trace back
1126
- // to the same split gateway → insert a join gateway if needed
1127
- for (const [targetId, inFlows] of incoming) {
1128
- if (inFlows.length < 2)
1129
- continue;
1130
- // Group incoming flows by originating split gateway
1131
- const splitToFlows = new Map();
1132
- for (const flow of inFlows) {
1133
- const split = this.traceBackToSplit(flow.sourceRef, splitGateways);
1134
- if (split) {
1135
- const arr = splitToFlows.get(split);
1136
- if (arr)
1137
- arr.push(flow);
1138
- else
1139
- splitToFlows.set(split, [flow]);
1140
- }
1311
+ if (!elementIds.has(flow.targetRef)) {
1312
+ throw new Error(`Sequence flow "${flow.id}" in process "${this.processId}" references unknown ` +
1313
+ `element "${flow.targetRef}". Check connectTo() calls — target must exist.`);
1141
1314
  }
1142
- for (const [splitId, convergingFlows] of splitToFlows) {
1143
- if (convergingFlows.length < 2)
1144
- continue;
1145
- const gwType = elementTypes.get(splitId);
1146
- if (!gwType)
1147
- continue;
1148
- // Don't insert if target is already a matching gateway type
1149
- const targetType = elementTypes.get(targetId);
1150
- if (targetType === gwType)
1151
- continue;
1152
- const joinId = `${splitId}_join`;
1153
- if (elementTypes.has(joinId))
1154
- continue;
1155
- const joinElement = makeFlowElement(joinId, gwType, {});
1156
- this.flowElements.push(joinElement);
1157
- elementTypes.set(joinId, gwType);
1158
- // Re-route converging flows to the join gateway
1159
- for (const flow of convergingFlows) {
1160
- flow.targetRef = joinId;
1161
- }
1162
- // Add flow from join to original target
1163
- this.sequenceFlows.push({
1164
- id: generateId("Flow"),
1165
- sourceRef: joinId,
1166
- targetRef: targetId,
1167
- extensionElements: [],
1168
- unknownAttributes: {},
1169
- });
1315
+ if (!elementIds.has(flow.sourceRef)) {
1316
+ throw new Error(`Sequence flow "${flow.id}" in process "${this.processId}" references unknown ` +
1317
+ `source element "${flow.sourceRef}".`);
1170
1318
  }
1171
1319
  }
1172
1320
  }
1173
- /** Trace backward from a node to find which split gateway it belongs to. */
1174
- traceBackToSplit(nodeId, splitGateways) {
1175
- const visited = new Set();
1176
- let current = nodeId;
1177
- while (current) {
1178
- if (visited.has(current))
1179
- return undefined;
1180
- visited.add(current);
1181
- if (splitGateways.has(current))
1182
- return current;
1183
- // Follow single incoming flow backward
1184
- const inFlows = this.sequenceFlows.filter((f) => f.targetRef === current);
1185
- if (inFlows.length !== 1)
1186
- return undefined;
1187
- const prev = inFlows[0];
1188
- if (!prev)
1189
- return undefined;
1190
- current = prev.sourceRef;
1191
- }
1192
- return undefined;
1193
- }
1194
1321
  addFlowElement(element) {
1195
1322
  if (this.flowElements.some((n) => n.id === element.id)) {
1196
1323
  throw new Error(`Duplicate element ID "${element.id}" in process "${this.processId}"`);
@@ -1221,4 +1348,63 @@ export class ProcessBuilder {
1221
1348
  this.lastNodeId = element.id;
1222
1349
  }
1223
1350
  }
1351
+ // ---------------------------------------------------------------------------
1352
+ // Diagram builder — multi-process support
1353
+ // ---------------------------------------------------------------------------
1354
+ /**
1355
+ * Builder for a complete BPMN definitions document containing one or more processes.
1356
+ * Use `Bpmn.createDiagram(id?)` to obtain an instance.
1357
+ */
1358
+ export class DiagramBuilder {
1359
+ _id;
1360
+ _processes = [];
1361
+ _errors = [];
1362
+ _messages = [];
1363
+ _executionPlatformVersion = "8.9.0";
1364
+ constructor(id) {
1365
+ this._id = id;
1366
+ }
1367
+ /** Set the Camunda execution platform version stamped into the BPMN definitions. Defaults to `"8.9.0"`. */
1368
+ executionPlatformVersion(version) {
1369
+ this._executionPlatformVersion = version;
1370
+ return this;
1371
+ }
1372
+ process(id, callback) {
1373
+ const builder = new ProcessBuilder(id);
1374
+ callback(builder);
1375
+ const defs = builder.build();
1376
+ this._processes.push(...defs.processes);
1377
+ this._errors.push(...defs.errors);
1378
+ this._messages.push(...defs.messages);
1379
+ return this;
1380
+ }
1381
+ build() {
1382
+ return {
1383
+ id: this._id,
1384
+ targetNamespace: "http://bpmn.io/schema/bpmn",
1385
+ exporter: "@bpmnkit/core",
1386
+ exporterVersion: EXPORTER_VERSION,
1387
+ namespaces: {
1388
+ bpmn: "http://www.omg.org/spec/BPMN/20100524/MODEL",
1389
+ bpmndi: "http://www.omg.org/spec/BPMN/20100524/DI",
1390
+ dc: "http://www.omg.org/spec/DD/20100524/DC",
1391
+ di: "http://www.omg.org/spec/DD/20100524/DI",
1392
+ zeebe: "http://camunda.org/schema/zeebe/1.0",
1393
+ modeler: "http://camunda.org/schema/modeler/1.0",
1394
+ xsi: "http://www.w3.org/2001/XMLSchema-instance",
1395
+ },
1396
+ unknownAttributes: {
1397
+ "modeler:executionPlatform": "Camunda Cloud",
1398
+ "modeler:executionPlatformVersion": this._executionPlatformVersion,
1399
+ },
1400
+ errors: this._errors,
1401
+ escalations: [],
1402
+ messages: this._messages,
1403
+ signals: [],
1404
+ collaborations: [],
1405
+ processes: this._processes,
1406
+ diagrams: [],
1407
+ };
1408
+ }
1409
+ }
1224
1410
  //# sourceMappingURL=bpmn-builder.js.map