@aranzatech/diagrams-bpmn 0.2.5 → 0.2.7

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 (44) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/{catalog-D2AcvrDO.d.cts → catalog-CjGdTFxc.d.cts} +1 -1
  3. package/dist/{catalog-CQtKEV7q.d.ts → catalog-DW0Hknp2.d.ts} +1 -1
  4. package/dist/{chunk-ASZ3TFNQ.js → chunk-KW2QVBOB.js} +149 -6
  5. package/dist/chunk-KW2QVBOB.js.map +1 -0
  6. package/dist/{chunk-QOGZITWB.js → chunk-M46UDUN3.js} +2 -2
  7. package/dist/{chunk-QOGZITWB.js.map → chunk-M46UDUN3.js.map} +1 -1
  8. package/dist/{chunk-7MKU37XQ.js → chunk-XTUYPA3E.js} +191 -15
  9. package/dist/chunk-XTUYPA3E.js.map +1 -0
  10. package/dist/elements/index.d.cts +3 -3
  11. package/dist/elements/index.d.ts +3 -3
  12. package/dist/index.cjs +336 -227
  13. package/dist/index.cjs.map +1 -1
  14. package/dist/index.d.cts +5 -5
  15. package/dist/index.d.ts +5 -5
  16. package/dist/index.js +3 -4
  17. package/dist/modeling/index.cjs +197 -10
  18. package/dist/modeling/index.cjs.map +1 -1
  19. package/dist/modeling/index.d.cts +103 -7
  20. package/dist/modeling/index.d.ts +103 -7
  21. package/dist/modeling/index.js +1 -1
  22. package/dist/simulation/index.cjs.map +1 -1
  23. package/dist/simulation/index.d.cts +36 -0
  24. package/dist/simulation/index.d.ts +36 -0
  25. package/dist/simulation/index.js +1 -1
  26. package/dist/{types-fDlPLIHd.d.cts → types-BjVERSZn.d.cts} +1 -1
  27. package/dist/{types-CIBColRi.d.ts → types-CBgWMl9p.d.ts} +1 -1
  28. package/dist/{types-rWbKYrHH.d.cts → types-wFn_tJLY.d.cts} +20 -0
  29. package/dist/{types-rWbKYrHH.d.ts → types-wFn_tJLY.d.ts} +20 -0
  30. package/dist/validation/index.cjs.map +1 -1
  31. package/dist/validation/index.d.cts +7 -2
  32. package/dist/validation/index.d.ts +7 -2
  33. package/dist/validation/index.js +224 -3
  34. package/dist/validation/index.js.map +1 -1
  35. package/dist/xml/index.cjs +146 -6
  36. package/dist/xml/index.cjs.map +1 -1
  37. package/dist/xml/index.d.cts +18 -3
  38. package/dist/xml/index.d.ts +18 -3
  39. package/dist/xml/index.js +1 -1
  40. package/package.json +2 -2
  41. package/dist/chunk-7MKU37XQ.js.map +0 -1
  42. package/dist/chunk-ASZ3TFNQ.js.map +0 -1
  43. package/dist/chunk-ZFGQVLHB.js +0 -226
  44. package/dist/chunk-ZFGQVLHB.js.map +0 -1
package/dist/index.cjs CHANGED
@@ -3,7 +3,6 @@
3
3
  var react = require('@xyflow/react');
4
4
  var jsxRuntime = require('react/jsx-runtime');
5
5
  var routing = require('@aranzatech/diagrams-core/routing');
6
- var bpmnModdle = require('bpmn-moddle');
7
6
  var diagramsCore = require('@aranzatech/diagrams-core');
8
7
  var serialization = require('@aranzatech/diagrams-core/serialization');
9
8
 
@@ -2493,6 +2492,37 @@ var BPMN_EDGE_TYPES = {
2493
2492
  conversationLink: ConversationLinkEdge
2494
2493
  };
2495
2494
 
2495
+ // src/xml/aranza-descriptor.ts
2496
+ var ARANZA_DESCRIPTOR = {
2497
+ name: "Aranza",
2498
+ uri: "http://aranzatech.io/schema/bpmn-extension/1.0",
2499
+ prefix: "aranza",
2500
+ xml: { tagAlias: "lowerCase" },
2501
+ types: [
2502
+ {
2503
+ name: "TaskConfig",
2504
+ superClass: ["Element"],
2505
+ properties: [
2506
+ { name: "priority", isAttr: true, type: "String" },
2507
+ { name: "owner", isAttr: true, type: "String" },
2508
+ { name: "sla", isAttr: true, type: "String" },
2509
+ // Aranza connector execution config (resolved at runtime by the Flowable delegate)
2510
+ { name: "connector", isAttr: true, type: "String" },
2511
+ { name: "action", isAttr: true, type: "String" },
2512
+ // Flowable implementation hints stored for round-trip fidelity
2513
+ { name: "flowableType", isAttr: true, type: "String" },
2514
+ { name: "flowableDelegateExpression", isAttr: true, type: "String" },
2515
+ // BusinessRuleTask: reference to a DMN decision table id
2516
+ { name: "decisionRef", isAttr: true, type: "String" },
2517
+ // UserTask: form key resolved to a FormDefinition name at runtime
2518
+ { name: "formKey", isAttr: true, type: "String" }
2519
+ ]
2520
+ }
2521
+ ],
2522
+ enumerations: [],
2523
+ associations: []
2524
+ };
2525
+
2496
2526
  // src/xml/mapper.ts
2497
2527
  var MODDLE_TO_ELEMENT_TYPE = {
2498
2528
  "bpmn:StartEvent": "StartEvent",
@@ -2759,6 +2789,49 @@ function extractSubProcessVariant(el) {
2759
2789
  if (el.triggeredByEvent === true) return "event";
2760
2790
  return "embedded";
2761
2791
  }
2792
+ function extractAranzaExtensions(el) {
2793
+ const result = {};
2794
+ const elAttrs = el.$attrs;
2795
+ if (elAttrs) {
2796
+ const ft = asString(elAttrs["flowable:type"]);
2797
+ if (ft) result.flowableType = ft;
2798
+ const fde = asString(elAttrs["flowable:delegateExpression"]);
2799
+ if (fde) result.flowableDelegateExpression = fde;
2800
+ const fk = asString(elAttrs["flowable:formKey"]);
2801
+ if (fk) result.formKey = fk;
2802
+ }
2803
+ const ext = el.extensionElements;
2804
+ if (!ext) return result;
2805
+ const taskConfig = asElements(ext.values).find((v) => v.$type === "aranza:TaskConfig");
2806
+ if (!taskConfig) return result;
2807
+ const priority = asString(taskConfig.priority);
2808
+ if (priority === "critical" || priority === "high" || priority === "medium" || priority === "low") {
2809
+ result.priority = priority;
2810
+ }
2811
+ const owner = asString(taskConfig.owner);
2812
+ if (owner) result.owner = owner;
2813
+ const sla = asString(taskConfig.sla);
2814
+ if (sla) result.sla = sla;
2815
+ const connector = asString(taskConfig.connector);
2816
+ if (connector) result.connector = connector;
2817
+ const action = asString(taskConfig.action);
2818
+ if (action) result.action = action;
2819
+ const flowableType = asString(taskConfig.flowableType);
2820
+ if (flowableType) result.flowableType = flowableType;
2821
+ const flowableDelegateExpression = asString(taskConfig.flowableDelegateExpression);
2822
+ if (flowableDelegateExpression) result.flowableDelegateExpression = flowableDelegateExpression;
2823
+ const decisionRef = asString(taskConfig.decisionRef);
2824
+ if (decisionRef) result.decisionRef = decisionRef;
2825
+ const formKey = asString(taskConfig.formKey);
2826
+ if (formKey) result.formKey = formKey;
2827
+ return result;
2828
+ }
2829
+ function extractCompletionCondition(el) {
2830
+ const cc = el.completionCondition;
2831
+ if (!cc) return void 0;
2832
+ if (typeof cc === "string") return cc.trim() || void 0;
2833
+ return asString(cc.body);
2834
+ }
2762
2835
  function walkFlowElements(elements, parentId, ctx, nodes, edges) {
2763
2836
  for (const el of elements) {
2764
2837
  const { $type, id } = el;
@@ -2795,6 +2868,11 @@ function buildNode(el, elementType, parentId, ctx, nodes) {
2795
2868
  const eventDefinition = extractEventDefinition(el);
2796
2869
  const isNonInterrupting = el.cancelActivity === false;
2797
2870
  const attachedToRef = el.attachedToRef?.id;
2871
+ const calledElement = elementType === "CallActivity" ? asString(el.calledElement) : void 0;
2872
+ const aranzaExt = extractAranzaExtensions(el);
2873
+ const scriptFormat = elementType === "ScriptTask" ? asString(el.scriptFormat) : void 0;
2874
+ const script = elementType === "ScriptTask" ? asString(el.script) : void 0;
2875
+ const completionCondition = elementType === "AdHocSubProcess" ? extractCompletionCondition(el) : void 0;
2798
2876
  const data = {
2799
2877
  elementType,
2800
2878
  ...label ? { label } : {},
@@ -2810,7 +2888,12 @@ function buildNode(el, elementType, parentId, ctx, nodes) {
2810
2888
  ...eventDefinition?.errorRef ? { errorRef: eventDefinition.errorRef } : {},
2811
2889
  ...eventDefinition?.escalationRef ? { escalationRef: eventDefinition.escalationRef } : {},
2812
2890
  ...eventDefinition?.conditionExpression ? { conditionExpression: eventDefinition.conditionExpression } : {},
2813
- ...eventDefinition?.linkName ? { linkName: eventDefinition.linkName } : {}
2891
+ ...eventDefinition?.linkName ? { linkName: eventDefinition.linkName } : {},
2892
+ ...calledElement ? { calledElement } : {},
2893
+ ...scriptFormat ? { scriptFormat } : {},
2894
+ ...script ? { script } : {},
2895
+ ...completionCondition ? { completionCondition } : {},
2896
+ ...aranzaExt
2814
2897
  };
2815
2898
  if (elementType === "SubProcess" || elementType === "Transaction" || elementType === "EventSubProcess" || elementType === "AdHocSubProcess") {
2816
2899
  const variant = extractSubProcessVariant(el);
@@ -2910,7 +2993,8 @@ function addLaneNodes(laneSet, poolId, ctx, nodes) {
2910
2993
  }
2911
2994
  }
2912
2995
  async function parseBpmnXml(xml) {
2913
- const moddle = new bpmnModdle.BpmnModdle();
2996
+ const { BpmnModdle } = await import('bpmn-moddle');
2997
+ const moddle = new BpmnModdle({ aranza: ARANZA_DESCRIPTOR });
2914
2998
  const warnings = [];
2915
2999
  let rootElement;
2916
3000
  try {
@@ -3000,6 +3084,8 @@ function normalizeChildPositions(nodes, nodeIds) {
3000
3084
  };
3001
3085
  });
3002
3086
  }
3087
+
3088
+ // src/xml/exporter.ts
3003
3089
  function uid(prefix, id) {
3004
3090
  return `${prefix}_${id}`;
3005
3091
  }
@@ -3099,6 +3185,30 @@ function buildEventDefinitions(moddle, node, eventDefinition) {
3099
3185
  }
3100
3186
  return [moddle.create(defType, attrs)];
3101
3187
  }
3188
+ function buildAranzaExtensionElements(moddle, node) {
3189
+ const { priority, owner, sla } = node.data;
3190
+ const connector = typeof node.data.connector === "string" ? node.data.connector : void 0;
3191
+ const action = typeof node.data.action === "string" ? node.data.action : void 0;
3192
+ const flowableType = typeof node.data.flowableType === "string" ? node.data.flowableType : void 0;
3193
+ const flowableDelegateExpression = typeof node.data.flowableDelegateExpression === "string" ? node.data.flowableDelegateExpression : void 0;
3194
+ const decisionRef = typeof node.data.decisionRef === "string" ? node.data.decisionRef : void 0;
3195
+ const formKey = typeof node.data.formKey === "string" ? node.data.formKey : void 0;
3196
+ if (!priority && !owner && !sla && !connector && !action && !flowableType && !flowableDelegateExpression && !decisionRef && !formKey) {
3197
+ return null;
3198
+ }
3199
+ const configAttrs = {};
3200
+ if (priority) configAttrs.priority = priority;
3201
+ if (owner) configAttrs.owner = owner;
3202
+ if (sla) configAttrs.sla = sla;
3203
+ if (connector) configAttrs.connector = connector;
3204
+ if (action) configAttrs.action = action;
3205
+ if (flowableType) configAttrs.flowableType = flowableType;
3206
+ if (flowableDelegateExpression) configAttrs.flowableDelegateExpression = flowableDelegateExpression;
3207
+ if (decisionRef) configAttrs.decisionRef = decisionRef;
3208
+ if (formKey) configAttrs.formKey = formKey;
3209
+ const taskConfig = moddle.create("aranza:TaskConfig", configAttrs);
3210
+ return moddle.create("bpmn:ExtensionElements", { values: [taskConfig] });
3211
+ }
3102
3212
  function buildSemanticModel(moddle, nodes, edges, opts) {
3103
3213
  const defId = opts.id ?? "Definitions_1";
3104
3214
  const defName = opts.name;
@@ -3268,12 +3378,44 @@ function buildFlowElement(moddle, node, allNodes, allEdges) {
3268
3378
  const interrupting = node.data.cancelActivity ?? !node.data.isNonInterrupting;
3269
3379
  attrs.cancelActivity = interrupting;
3270
3380
  }
3271
- const isSubProcess3 = elementType === "SubProcess" || elementType === "Transaction" || elementType === "EventSubProcess" || elementType === "AdHocSubProcess";
3272
- if (isSubProcess3) {
3381
+ if (elementType === "CallActivity" && node.data.calledElement) {
3382
+ attrs.calledElement = node.data.calledElement;
3383
+ }
3384
+ if (elementType === "ScriptTask") {
3385
+ const scriptFormat = typeof node.data.scriptFormat === "string" ? node.data.scriptFormat : void 0;
3386
+ const script = typeof node.data.script === "string" ? node.data.script : void 0;
3387
+ if (scriptFormat) attrs.scriptFormat = scriptFormat;
3388
+ if (script) attrs.script = script;
3389
+ }
3390
+ if (elementType === "UserTask") {
3391
+ const fk = typeof node.data.formKey === "string" ? node.data.formKey : void 0;
3392
+ if (fk) attrs.$attrs = { "flowable:formKey": fk };
3393
+ }
3394
+ if (elementType === "ServiceTask") {
3395
+ const flowableAttrs = {};
3396
+ const flowableType = typeof node.data.flowableType === "string" ? node.data.flowableType : void 0;
3397
+ const flowableDelegateExpression = typeof node.data.flowableDelegateExpression === "string" ? node.data.flowableDelegateExpression : void 0;
3398
+ const connector = typeof node.data.connector === "string" ? node.data.connector : void 0;
3399
+ if (connector) flowableAttrs["flowable:type"] = "http";
3400
+ if (flowableType) flowableAttrs["flowable:type"] = flowableType;
3401
+ if (flowableDelegateExpression) {
3402
+ flowableAttrs["flowable:delegateExpression"] = flowableDelegateExpression;
3403
+ }
3404
+ if (Object.keys(flowableAttrs).length > 0) attrs.$attrs = flowableAttrs;
3405
+ }
3406
+ const aranzaConfig = buildAranzaExtensionElements(moddle, node);
3407
+ if (aranzaConfig) attrs.extensionElements = aranzaConfig;
3408
+ const isSubProcess2 = elementType === "SubProcess" || elementType === "Transaction" || elementType === "EventSubProcess" || elementType === "AdHocSubProcess";
3409
+ if (isSubProcess2) {
3273
3410
  attrs.flowElements = buildNestedFlowElements(moddle, node, allNodes, allEdges);
3274
3411
  if (elementType === "EventSubProcess" || node.data.subProcessVariant === "event") {
3275
3412
  attrs.triggeredByEvent = true;
3276
3413
  }
3414
+ if (elementType === "AdHocSubProcess" && typeof node.data.completionCondition === "string" && node.data.completionCondition.trim()) {
3415
+ attrs.completionCondition = moddle.create("bpmn:FormalExpression", {
3416
+ body: node.data.completionCondition.trim()
3417
+ });
3418
+ }
3277
3419
  }
3278
3420
  const element = moddle.create(moddleType, attrs);
3279
3421
  return element;
@@ -3405,7 +3547,8 @@ function buildAbsolutePositionMap(nodes) {
3405
3547
  return absoluteById;
3406
3548
  }
3407
3549
  async function serializeBpmnXml(nodes, edges, opts = {}) {
3408
- const moddle = new bpmnModdle.BpmnModdle();
3550
+ const { BpmnModdle } = await import('bpmn-moddle');
3551
+ const moddle = new BpmnModdle({ aranza: ARANZA_DESCRIPTOR });
3409
3552
  const definitions = buildSemanticModel(moddle, nodes, edges, opts);
3410
3553
  buildBpmnDI(moddle, definitions, nodes, edges);
3411
3554
  const { xml } = await moddle.toXML(definitions, {
@@ -4436,6 +4579,41 @@ function reparentBpmnNodeAtPosition(state, options) {
4436
4579
  position: nextPosition
4437
4580
  });
4438
4581
  }
4582
+ var BE_HALF = 18;
4583
+ function clampBoundaryEventsAfterResize(state, hostId, oldW, oldH, newW, newH) {
4584
+ const boundaryEvents = state.nodes.filter(
4585
+ (n) => n.data.elementType === "BoundaryEvent" && n.parentId === hostId
4586
+ );
4587
+ let next = state;
4588
+ for (const be of boundaryEvents) {
4589
+ const px = be.position?.x ?? 0;
4590
+ const py = be.position?.y ?? 0;
4591
+ const cx = px + BE_HALF;
4592
+ const cy = py + BE_HALF;
4593
+ const distLeft = Math.abs(cx);
4594
+ const distRight = Math.abs(cx - oldW);
4595
+ const distTop = Math.abs(cy);
4596
+ const distBottom = Math.abs(cy - oldH);
4597
+ const minDist = Math.min(distLeft, distRight, distTop, distBottom);
4598
+ let newCx;
4599
+ let newCy;
4600
+ if (minDist === distBottom) {
4601
+ newCy = newH;
4602
+ newCx = Math.min(Math.max(cx, BE_HALF), newW - BE_HALF);
4603
+ } else if (minDist === distRight) {
4604
+ newCx = newW;
4605
+ newCy = Math.min(Math.max(cy, BE_HALF), newH - BE_HALF);
4606
+ } else if (minDist === distTop) {
4607
+ newCy = 0;
4608
+ newCx = Math.min(Math.max(cx, BE_HALF), newW - BE_HALF);
4609
+ } else {
4610
+ newCx = 0;
4611
+ newCy = Math.min(Math.max(cy, BE_HALF), newH - BE_HALF);
4612
+ }
4613
+ next = diagramsCore.moveNode(next, be.id, { x: newCx - BE_HALF, y: newCy - BE_HALF });
4614
+ }
4615
+ return next;
4616
+ }
4439
4617
  function resizeBpmnNodeCommand(options) {
4440
4618
  return {
4441
4619
  id: `bpmn.resize.${options.id}`,
@@ -4447,10 +4625,18 @@ function resizeBpmnNodeCommand(options) {
4447
4625
  if (!size.resizable) {
4448
4626
  throw new Error(`${node.data.elementType} is not resizable in BPMN.`);
4449
4627
  }
4450
- return diagramsCore.resizeNode(state, options.id, {
4451
- width: options.width === void 0 ? void 0 : Math.max(size.minWidth, options.width),
4452
- height: options.height === void 0 ? void 0 : Math.max(size.minHeight, options.height)
4628
+ const oldW = node.width ?? size.width;
4629
+ const oldH = node.height ?? size.height;
4630
+ const clampedW = options.width === void 0 ? void 0 : Math.max(size.minWidth, options.width);
4631
+ const clampedH = options.height === void 0 ? void 0 : Math.max(size.minHeight, options.height);
4632
+ const resized = diagramsCore.resizeNode(state, options.id, {
4633
+ width: clampedW,
4634
+ height: clampedH
4453
4635
  });
4636
+ const updatedNode = diagramsCore.getNode(resized, options.id);
4637
+ const newW = updatedNode?.width ?? clampedW ?? oldW;
4638
+ const newH = updatedNode?.height ?? clampedH ?? oldH;
4639
+ return clampBoundaryEventsAfterResize(resized, options.id, oldW, oldH, newW, newH);
4454
4640
  }
4455
4641
  };
4456
4642
  }
@@ -4530,10 +4716,15 @@ function createBpmnDiagramDocument(state, options = {}) {
4530
4716
  });
4531
4717
  }
4532
4718
  function serializeBpmnDiagram(state, options = {}) {
4533
- return serialization.serializeDiagram(diagramsCore.normalizeDiagramState(state), {
4534
- ...options,
4535
- diagramType: "bpmn"
4536
- });
4719
+ const { viewport, ...docOptions } = options;
4720
+ const normalized = diagramsCore.normalizeDiagramState(state);
4721
+ if (viewport) {
4722
+ return serialization.serializeDiagramSnapshot(
4723
+ { nodes: normalized.nodes, edges: normalized.edges, viewport },
4724
+ { ...docOptions, diagramType: "bpmn" }
4725
+ );
4726
+ }
4727
+ return serialization.serializeDiagram(normalized, { ...docOptions, diagramType: "bpmn" });
4537
4728
  }
4538
4729
  function parseBpmnDiagramDocument(json) {
4539
4730
  const document = serialization.parseDiagramDocument(json);
@@ -4546,232 +4737,140 @@ function deserializeBpmnDiagram(json) {
4546
4737
  const document = parseBpmnDiagramDocument(json);
4547
4738
  return serialization.deserializeDiagram(JSON.stringify(document));
4548
4739
  }
4549
- function runBpmnCommand(stack, command) {
4550
- return diagramsCore.executeCommand(stack, command);
4551
- }
4552
- function runBpmnCommands(stack, commands, options = {}) {
4553
- return diagramsCore.executeCommands(stack, commands, options);
4554
- }
4555
-
4556
- // src/validation/index.ts
4557
- function isFlowNode(type) {
4558
- return isEventType(type) || isGatewayType(type) || type.includes("Task") || type === "CallActivity" || type === "SubProcess" || type === "Transaction" || type === "EventSubProcess" || type === "AdHocSubProcess" || type === "ChoreographyTask" || type === "SubChoreography" || type === "CallChoreography";
4559
- }
4560
- function isProcessNode(type) {
4561
- return isFlowNode(type) && type !== "BoundaryEvent";
4562
- }
4563
- function isSubProcess2(type) {
4564
- return type === "SubProcess" || type === "Transaction" || type === "EventSubProcess" || type === "AdHocSubProcess";
4565
- }
4566
- function isCatchTarget(type) {
4567
- return type === "IntermediateCatchEvent" || type === "ReceiveTask";
4568
- }
4569
- function poolAncestor(node, nodeById2) {
4570
- let current = node;
4571
- const visited = /* @__PURE__ */ new Set();
4572
- while (current?.parentId && !visited.has(current.id)) {
4573
- visited.add(current.id);
4574
- const parent = nodeById2.get(current.parentId);
4575
- if (parent?.data.elementType === "Pool") return parent.id;
4576
- current = parent;
4577
- }
4578
- return void 0;
4740
+ function deserializeBpmnDiagramSnapshot(json) {
4741
+ const document = parseBpmnDiagramDocument(json);
4742
+ return serialization.deserializeDiagramSnapshot(JSON.stringify(document));
4579
4743
  }
4580
- function countSequenceEdges(edges, nodeId, direction) {
4581
- return edges.filter((edge) => {
4582
- if (edge.data?.edgeType !== "sequenceFlow") return false;
4583
- return direction === "in" ? edge.target === nodeId : edge.source === nodeId;
4584
- }).length;
4744
+ function createBpmnEventBus() {
4745
+ return diagramsCore.createDiagramEventBus();
4585
4746
  }
4586
- function sequenceEdges(edges) {
4587
- return edges.filter((edge) => (edge.data?.edgeType ?? edge.type) === "sequenceFlow");
4747
+ function runBpmnCommand(stack, command, bus) {
4748
+ const next = diagramsCore.executeCommand(stack, command);
4749
+ bus?.emit("command:executed", {
4750
+ commandId: command.id,
4751
+ ...command.label !== void 0 ? { label: command.label } : {},
4752
+ state: next.current
4753
+ });
4754
+ return next;
4588
4755
  }
4589
- function sequenceOut(edges, nodeId) {
4590
- return sequenceEdges(edges).filter((edge) => edge.source === nodeId);
4756
+ function runBpmnCommands(stack, commands, options = {}) {
4757
+ const { bus, ...execOptions } = options;
4758
+ const next = diagramsCore.executeCommands(stack, commands, execOptions);
4759
+ bus?.emit("command:executed", {
4760
+ commandId: execOptions.id ?? "bpmn.batch",
4761
+ ...execOptions.label !== void 0 ? { label: execOptions.label } : {},
4762
+ state: next.current
4763
+ });
4764
+ return next;
4591
4765
  }
4592
- function sequenceIn(edges, nodeId) {
4593
- return sequenceEdges(edges).filter((edge) => edge.target === nodeId);
4766
+ function persistBpmnHistory(stack, diagramId) {
4767
+ diagramsCore.persistCommandHistory(stack, `bpmn.history.${diagramId}`);
4768
+ }
4769
+ function restoreBpmnHistory(diagramId) {
4770
+ return diagramsCore.restoreCommandHistory(`bpmn.history.${diagramId}`);
4771
+ }
4772
+ function computeBpmnSmartGuides(movingNodes, state, poolId) {
4773
+ const movingIds = new Set(movingNodes.map((n) => n.id));
4774
+ const staticNodes = state.nodes.filter((n) => {
4775
+ if (movingIds.has(n.id)) return false;
4776
+ const et = n.data.elementType;
4777
+ if (et === "BoundaryEvent" || et === "Lane" || et === "Pool") return false;
4778
+ if (poolId) {
4779
+ const inPool = n.parentId === poolId || n.parentId !== void 0 && diagramsCore.getNode(state, n.parentId)?.parentId === poolId;
4780
+ if (!inPool) return false;
4781
+ }
4782
+ return true;
4783
+ });
4784
+ return diagramsCore.computeSmartGuides(movingNodes, staticNodes);
4594
4785
  }
4595
- function issue(code, severity, message, elementId, relatedElementIds) {
4786
+ function groupAsBpmnSubProcessCommand(options) {
4596
4787
  return {
4597
- id: `${code}:${elementId ?? relatedElementIds?.join(",") ?? "diagram"}`,
4598
- code,
4599
- severity,
4600
- message,
4601
- ...elementId ? { elementId } : {},
4602
- ...relatedElementIds ? { relatedElementIds } : {}
4603
- };
4604
- }
4605
- function validateBpmnDiagram(nodes, edges, options = {}) {
4606
- const opts = {
4607
- requireStartEvent: true,
4608
- requireEndEvent: true,
4609
- strictNames: false,
4610
- ...options
4611
- };
4612
- const issues = [];
4613
- const nodeById2 = new Map(nodes.map((node) => [node.id, node]));
4614
- const seqEdges = sequenceEdges(edges);
4615
- const processNodes = nodes.filter((node) => isProcessNode(node.data.elementType));
4616
- if (opts.requireStartEvent && !processNodes.some((node) => node.data.elementType === "StartEvent")) {
4617
- issues.push(issue("bpmn/start-event-required", "error", "The diagram must contain at least one start event."));
4618
- }
4619
- if (opts.requireEndEvent && !processNodes.some((node) => node.data.elementType === "EndEvent")) {
4620
- issues.push(issue("bpmn/end-event-required", "error", "The diagram must contain at least one end event."));
4621
- }
4622
- for (const edge of edges) {
4623
- const edgeType = edge.data?.edgeType ?? edge.type;
4624
- const source = nodeById2.get(edge.source);
4625
- const target = nodeById2.get(edge.target);
4626
- if (!source || !target) {
4627
- issues.push(issue(
4628
- "bpmn/no-orphan-edges",
4629
- "error",
4630
- `Edge "${edge.id}" references a missing ${!source ? "source" : "target"} node.`,
4631
- edge.id,
4632
- [edge.source, edge.target]
4633
- ));
4634
- continue;
4635
- }
4636
- if (edge.source === edge.target) {
4637
- issues.push(issue("bpmn/no-self-loop", "error", "BPMN edges cannot connect an element to itself.", edge.id, [edge.source]));
4638
- }
4639
- if (edgeType === "sequenceFlow") {
4640
- if (!isFlowNode(source.data.elementType) || !isFlowNode(target.data.elementType) || isDataType(source.data.elementType) || isDataType(target.data.elementType)) {
4641
- issues.push(issue("bpmn/sequence-flow-valid-endpoints", "error", "Sequence flows must connect BPMN flow nodes.", edge.id, [source.id, target.id]));
4642
- }
4643
- const sourcePool = poolAncestor(source, nodeById2);
4644
- const targetPool = poolAncestor(target, nodeById2);
4645
- if (sourcePool && targetPool && sourcePool !== targetPool) {
4646
- issues.push(issue("bpmn/sequence-flow-no-cross-pool", "error", "Sequence flows cannot cross pools. Use message flow between participants.", edge.id, [source.id, target.id]));
4647
- }
4648
- }
4649
- if (edgeType === "messageFlow") {
4650
- const sourcePool = poolAncestor(source, nodeById2);
4651
- const targetPool = poolAncestor(target, nodeById2);
4652
- if (!sourcePool || !targetPool || sourcePool === targetPool) {
4653
- issues.push(issue("bpmn/message-flow-valid-endpoints", "error", "Message flows must connect flow nodes in different pools.", edge.id, [source.id, target.id]));
4654
- }
4655
- if (!isFlowNode(source.data.elementType) || !isFlowNode(target.data.elementType)) {
4656
- issues.push(issue("bpmn/message-flow-valid-endpoints", "error", "Message flows must connect BPMN flow nodes, not containers.", edge.id, [source.id, target.id]));
4657
- }
4658
- }
4659
- if (edgeType === "dataAssociation") {
4660
- const hasDataEndpoint = isDataType(source.data.elementType) || isDataType(target.data.elementType);
4661
- const hasFlowEndpoint = isFlowNode(source.data.elementType) || isFlowNode(target.data.elementType);
4662
- if (!hasDataEndpoint || !hasFlowEndpoint) {
4663
- issues.push(issue("bpmn/data-association-valid-endpoints", "error", "Data associations must connect data elements with flow nodes.", edge.id, [source.id, target.id]));
4788
+ id: `bpmn.groupAsSubProcess.${options.groupId ?? options.nodeIds.join(".")}`,
4789
+ label: "Group as SubProcess",
4790
+ execute: (state) => {
4791
+ for (const nodeId of options.nodeIds) {
4792
+ const node = diagramsCore.getNode(state, nodeId);
4793
+ if (!node) continue;
4794
+ const result = canContainBpmnElement("SubProcess", node.data.elementType);
4795
+ if (result !== true) throw new Error(result);
4664
4796
  }
4797
+ const groupId = options.groupId ?? diagramsCore.createUniqueId("subprocess", state.nodes.map((n) => n.id));
4798
+ const groupNode = createBpmnNode({
4799
+ id: groupId,
4800
+ elementType: "SubProcess",
4801
+ position: { x: 0, y: 0 },
4802
+ ...options.label !== void 0 ? { label: options.label } : {},
4803
+ ...options.data !== void 0 ? { data: options.data } : {}
4804
+ });
4805
+ return diagramsCore.groupNodes(state, {
4806
+ groupNode,
4807
+ nodeIds: options.nodeIds,
4808
+ padding: options.padding ?? 20
4809
+ });
4665
4810
  }
4811
+ };
4812
+ }
4813
+ function getBpmnTabOrder(state, poolId) {
4814
+ if (!poolId) return diagramsCore.getNodeTabOrder(state);
4815
+ const pool = diagramsCore.getNode(state, poolId);
4816
+ if (!pool) return [];
4817
+ const scopeIds = state.nodes.filter((n) => {
4818
+ if (n.id === poolId) return false;
4819
+ if (n.parentId === poolId) return true;
4820
+ const parent = diagramsCore.getNode(state, n.parentId ?? "");
4821
+ return parent?.parentId === poolId;
4822
+ }).map((n) => n.id);
4823
+ return diagramsCore.getNodeTabOrder(state, scopeIds);
4824
+ }
4825
+ function getBpmnEdgeLabelLayout(edgeId, state, options) {
4826
+ const edge = state.edges.find((e) => e.id === edgeId);
4827
+ if (!edge) return null;
4828
+ const routingPoints = edge.data?.routingPoints ?? [];
4829
+ if (routingPoints.length >= 2) {
4830
+ return diagramsCore.getEdgeLabelLayout(routingPoints, options);
4666
4831
  }
4667
- const duplicateSequenceKeys = /* @__PURE__ */ new Set();
4668
- const reportedDuplicateKeys = /* @__PURE__ */ new Set();
4669
- for (const edge of seqEdges) {
4670
- const key = `${edge.source}->${edge.target}`;
4671
- if (duplicateSequenceKeys.has(key) && !reportedDuplicateKeys.has(key)) {
4672
- reportedDuplicateKeys.add(key);
4673
- issues.push(issue("bpmn/no-duplicate-sequence-flow", "error", "Only one sequence flow is allowed between the same source and target.", edge.id, [edge.source, edge.target]));
4674
- }
4675
- duplicateSequenceKeys.add(key);
4676
- }
4677
- for (const node of nodes) {
4678
- const type = node.data.elementType;
4679
- const incoming = countSequenceEdges(edges, node.id, "in");
4680
- const outgoing = countSequenceEdges(edges, node.id, "out");
4681
- const meta = BPMN_ELEMENT_CATALOG[type];
4682
- if (type === "StartEvent" && incoming > 0) {
4683
- issues.push(issue("bpmn/start-event-no-incoming", "error", "Start events cannot have incoming sequence flows.", node.id));
4684
- }
4685
- if (type === "EndEvent") {
4686
- if (outgoing > 0) issues.push(issue("bpmn/no-outgoing-from-end-event", "error", "End events cannot have outgoing sequence flows.", node.id));
4687
- if (incoming === 0) issues.push(issue("bpmn/end-event-has-incoming", "error", "End events should have at least one incoming sequence flow.", node.id));
4688
- }
4689
- if ((type === "IntermediateCatchEvent" || type === "IntermediateThrowEvent") && (incoming === 0 || outgoing === 0)) {
4690
- issues.push(issue("bpmn/intermediate-event-both-flows", "error", "Intermediate events should have both incoming and outgoing sequence flows.", node.id));
4691
- }
4692
- if (type === "BoundaryEvent") {
4693
- const hostId = node.data.attachedToRef ?? node.parentId;
4694
- const host = hostId ? nodeById2.get(hostId) : void 0;
4695
- if (!host || !BPMN_ELEMENT_CATALOG[host.data.elementType]?.acceptsBoundaryEvents) {
4696
- issues.push(issue("bpmn/boundary-event-attached", "error", "Boundary events must be attached to an activity or subprocess.", node.id, hostId ? [hostId] : void 0));
4697
- }
4698
- if (sequenceIn(edges, node.id).length > 0) {
4699
- issues.push(issue("bpmn/boundary-no-incoming", "error", "Boundary events cannot have incoming sequence flows.", node.id));
4700
- }
4701
- if (sequenceOut(edges, node.id).length === 0) {
4702
- issues.push(issue("bpmn/boundary-has-outgoing", "warning", "Boundary events should define an outgoing exception path.", node.id));
4703
- }
4704
- }
4705
- if (isGatewayType(type)) {
4706
- if (incoming === 0) issues.push(issue("bpmn/gateway-has-incoming", "error", "Gateways should have at least one incoming sequence flow.", node.id));
4707
- if (outgoing === 0) issues.push(issue("bpmn/gateway-has-outgoing", "error", "Gateways should have at least one outgoing sequence flow.", node.id));
4708
- }
4709
- if (type === "ExclusiveGateway" || type === "InclusiveGateway" || type === "ComplexGateway") {
4710
- const outgoingEdges = sequenceOut(edges, node.id);
4711
- const defaults = outgoingEdges.filter((edge) => edge.data?.isDefault);
4712
- if (defaults.length > 1) {
4713
- issues.push(issue("bpmn/gateway-single-default", "error", "Gateways can have at most one default sequence flow.", node.id, defaults.map((edge) => edge.id)));
4714
- }
4715
- if (outgoingEdges.length >= 2) {
4716
- for (const edge of outgoingEdges) {
4717
- if (!edge.data?.isDefault && !edge.data?.conditionExpression) {
4718
- issues.push(issue("bpmn/gateway-condition", "error", "Conditional gateway branches should have a condition or be marked as default.", edge.id, [node.id, edge.target]));
4719
- }
4720
- }
4721
- }
4722
- }
4723
- if (type === "EventBasedGateway") {
4724
- const outgoingEdges = edges.filter((edge) => edge.data?.edgeType === "sequenceFlow" && edge.source === node.id);
4725
- if (outgoingEdges.length < 2) {
4726
- issues.push(issue("bpmn/event-based-gateway-min-outgoing", "error", "Event-based gateways should have at least two outgoing sequence flows.", node.id));
4727
- }
4728
- for (const edge of outgoingEdges) {
4729
- const target = nodeById2.get(edge.target);
4730
- if (target && !isCatchTarget(target.data.elementType)) {
4731
- issues.push(issue("bpmn/event-based-gateway-valid-targets", "error", "Event-based gateways must target catch events or receive tasks.", edge.id, [node.id, target.id]));
4732
- }
4733
- }
4734
- }
4735
- if (meta.maxIncoming !== void 0 && incoming > meta.maxIncoming) {
4736
- issues.push(issue("bpmn/max-incoming", "error", `${type} cannot have more than ${meta.maxIncoming} incoming sequence flow(s).`, node.id));
4737
- }
4738
- if (meta.maxOutgoing !== void 0 && outgoing > meta.maxOutgoing) {
4739
- issues.push(issue("bpmn/max-outgoing", "error", `${type} cannot have more than ${meta.maxOutgoing} outgoing sequence flow(s).`, node.id));
4740
- }
4741
- if (opts.strictNames && (type.includes("Task") || isGatewayType(type)) && !node.data.label) {
4742
- issues.push(issue("bpmn/name-required", "warning", `${type} should have a label.`, node.id));
4743
- }
4744
- if (isSubProcess2(type)) {
4745
- const childNodes = nodes.filter((child) => child.parentId === node.id);
4746
- if (childNodes.length > 0) {
4747
- if (!childNodes.some((child) => child.data.elementType === "StartEvent")) {
4748
- issues.push(issue("bpmn/subprocess-has-start-end", "error", "Expanded subprocesses should contain a start event.", node.id));
4749
- }
4750
- if (!childNodes.some((child) => child.data.elementType === "EndEvent")) {
4751
- issues.push(issue("bpmn/subprocess-has-start-end", "error", "Expanded subprocesses should contain an end event.", node.id));
4752
- }
4753
- }
4754
- if (type === "EventSubProcess") {
4755
- const starts = childNodes.filter((child) => child.data.elementType === "StartEvent");
4756
- for (const start of starts) {
4757
- if (!start.data.trigger || start.data.trigger === "none") {
4758
- issues.push(issue("bpmn/event-subprocess-triggered-start", "error", "Event subprocess start events must define an event trigger.", start.id, [node.id]));
4759
- }
4760
- }
4761
- }
4762
- }
4763
- if (type === "Lane") {
4764
- const parent = node.parentId ? nodeById2.get(node.parentId) : void 0;
4765
- if (parent?.data.elementType !== "Pool") {
4766
- issues.push(issue("bpmn/lane-parent-pool", "error", "Lanes must be contained by a pool.", node.id));
4832
+ const sourceNode = diagramsCore.getNode(state, edge.source);
4833
+ const targetNode = diagramsCore.getNode(state, edge.target);
4834
+ if (!sourceNode || !targetNode) return null;
4835
+ const sourceAbsPos = getBpmnNodeAbsolutePosition(state, edge.source) ?? sourceNode.position;
4836
+ const targetAbsPos = getBpmnNodeAbsolutePosition(state, edge.target) ?? targetNode.position;
4837
+ const sourceCenter = diagramsCore.getNodeCenterPosition(sourceAbsPos, getBpmnNodeSize(sourceNode));
4838
+ const targetCenter = diagramsCore.getNodeCenterPosition(targetAbsPos, getBpmnNodeSize(targetNode));
4839
+ return diagramsCore.getEdgeLabelLayout([sourceCenter, targetCenter], options);
4840
+ }
4841
+ function resizeBpmnNodeByHandleCommand(options) {
4842
+ return {
4843
+ id: `bpmn.resizeByHandle.${options.id}`,
4844
+ label: "Resize BPMN element",
4845
+ execute: (state) => {
4846
+ const node = diagramsCore.getNode(state, options.id);
4847
+ if (!node) throw new Error(`Element "${options.id}" does not exist.`);
4848
+ const size = getBpmnElementSize(node.data.elementType);
4849
+ if (!size.resizable) {
4850
+ throw new Error(`${node.data.elementType} is not resizable in BPMN.`);
4767
4851
  }
4852
+ const oldW = node.width ?? size.width;
4853
+ const oldH = node.height ?? size.height;
4854
+ const resized = diagramsCore.resizeNodeByHandle(state, {
4855
+ id: options.id,
4856
+ handle: options.handle,
4857
+ dx: options.dx,
4858
+ dy: options.dy,
4859
+ constraints: { minWidth: size.minWidth, minHeight: size.minHeight }
4860
+ });
4861
+ const updatedNode = diagramsCore.getNode(resized, options.id);
4862
+ const newW = updatedNode?.width ?? oldW;
4863
+ const newH = updatedNode?.height ?? oldH;
4864
+ return clampBoundaryEventsAfterResize(resized, options.id, oldW, oldH, newW, newH);
4768
4865
  }
4769
- }
4770
- return {
4771
- valid: issues.every((item) => item.severity !== "error"),
4772
- issues
4773
4866
  };
4774
4867
  }
4868
+ function createBpmnLayoutCache(options) {
4869
+ return diagramsCore.createLayoutCache(options);
4870
+ }
4871
+ function withBpmnLayoutCache(layoutFn, cache) {
4872
+ return diagramsCore.withLayoutCache(layoutFn, cache ?? diagramsCore.createLayoutCache());
4873
+ }
4775
4874
 
4776
4875
  exports.AnnotationNode = AnnotationNode;
4777
4876
  exports.AssociationEdge = AssociationEdge;
@@ -4815,17 +4914,22 @@ exports.acceptsBoundaryEvents = acceptsBoundaryEvents;
4815
4914
  exports.attachBoundaryEventCommand = attachBoundaryEventCommand;
4816
4915
  exports.bpmnConnectionValidators = bpmnConnectionValidators;
4817
4916
  exports.canContainBpmnElement = canContainBpmnElement;
4917
+ exports.computeBpmnSmartGuides = computeBpmnSmartGuides;
4818
4918
  exports.connectBpmnCommand = connectBpmnCommand;
4819
4919
  exports.copyBpmnElements = copyBpmnElements;
4820
4920
  exports.createBpmnDiagramDocument = createBpmnDiagramDocument;
4921
+ exports.createBpmnEventBus = createBpmnEventBus;
4922
+ exports.createBpmnLayoutCache = createBpmnLayoutCache;
4821
4923
  exports.createBpmnNode = createBpmnNode;
4822
4924
  exports.createBpmnNodeCommand = createBpmnNodeCommand;
4823
4925
  exports.createSimulation = createSimulation;
4824
4926
  exports.deleteBpmnElementsCommand = deleteBpmnElementsCommand;
4825
4927
  exports.deserializeBpmnDiagram = deserializeBpmnDiagram;
4928
+ exports.deserializeBpmnDiagramSnapshot = deserializeBpmnDiagramSnapshot;
4826
4929
  exports.findBpmnContainerAt = findBpmnContainerAt;
4827
4930
  exports.fire = fire;
4828
4931
  exports.getBpmnDragHandleSelector = getBpmnDragHandleSelector;
4932
+ exports.getBpmnEdgeLabelLayout = getBpmnEdgeLabelLayout;
4829
4933
  exports.getBpmnElementSize = getBpmnElementSize;
4830
4934
  exports.getBpmnLaneIndexAtPosition = getBpmnLaneIndexAtPosition;
4831
4935
  exports.getBpmnNodeAbsolutePosition = getBpmnNodeAbsolutePosition;
@@ -4833,10 +4937,12 @@ exports.getBpmnNodeCenter = getBpmnNodeCenter;
4833
4937
  exports.getBpmnNodeSize = getBpmnNodeSize;
4834
4938
  exports.getBpmnNodeZIndex = getBpmnNodeZIndex;
4835
4939
  exports.getBpmnPoolLanes = getBpmnPoolLanes;
4940
+ exports.getBpmnTabOrder = getBpmnTabOrder;
4836
4941
  exports.getElementMeta = getElementMeta;
4837
4942
  exports.getFireable = getFireable;
4838
4943
  exports.getHandlePolicy = getHandlePolicy;
4839
4944
  exports.getOrientation = getOrientation;
4945
+ exports.groupAsBpmnSubProcessCommand = groupAsBpmnSubProcessCommand;
4840
4946
  exports.inferBpmnEdgeType = inferBpmnEdgeType;
4841
4947
  exports.isBpmnEdgeRoutingEditable = isBpmnEdgeRoutingEditable;
4842
4948
  exports.isBpmnElementResizable = isBpmnElementResizable;
@@ -4855,13 +4961,16 @@ exports.moveBpmnLaneCommand = moveBpmnLaneCommand;
4855
4961
  exports.parseBpmnDiagramDocument = parseBpmnDiagramDocument;
4856
4962
  exports.parseBpmnXml = parseBpmnXml;
4857
4963
  exports.pasteBpmnElementsCommand = pasteBpmnElementsCommand;
4964
+ exports.persistBpmnHistory = persistBpmnHistory;
4858
4965
  exports.reorderBpmnLane = reorderBpmnLane;
4859
4966
  exports.reorderBpmnLaneAfterDrop = reorderBpmnLaneAfterDrop;
4860
4967
  exports.reorderBpmnLaneCommand = reorderBpmnLaneCommand;
4861
4968
  exports.reparentBpmnNodeAtPosition = reparentBpmnNodeAtPosition;
4862
4969
  exports.reparentBpmnNodeCommand = reparentBpmnNodeCommand;
4863
4970
  exports.replaceBpmnNodeCommand = replaceBpmnNodeCommand;
4971
+ exports.resizeBpmnNodeByHandleCommand = resizeBpmnNodeByHandleCommand;
4864
4972
  exports.resizeBpmnNodeCommand = resizeBpmnNodeCommand;
4973
+ exports.restoreBpmnHistory = restoreBpmnHistory;
4865
4974
  exports.routeBpmnEdgeCommand = routeBpmnEdgeCommand;
4866
4975
  exports.runBpmnCommand = runBpmnCommand;
4867
4976
  exports.runBpmnCommands = runBpmnCommands;
@@ -4874,7 +4983,7 @@ exports.supportsMarkers = supportsMarkers;
4874
4983
  exports.tick = tick;
4875
4984
  exports.toBpmnRelativePosition = toBpmnRelativePosition;
4876
4985
  exports.validateBpmnConnectionForEdgeType = validateBpmnConnectionForEdgeType;
4877
- exports.validateBpmnDiagram = validateBpmnDiagram;
4986
+ exports.withBpmnLayoutCache = withBpmnLayoutCache;
4878
4987
  exports.withBpmnNodeZIndexes = withBpmnNodeZIndexes;
4879
4988
  //# sourceMappingURL=index.cjs.map
4880
4989
  //# sourceMappingURL=index.cjs.map