@aranzatech/diagrams-bpmn 0.1.3 → 0.2.0

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 (42) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +121 -0
  3. package/dist/{chunk-4AX573IV.js → chunk-5GRCJ5X6.js} +2 -2
  4. package/dist/{chunk-4AX573IV.js.map → chunk-5GRCJ5X6.js.map} +1 -1
  5. package/dist/chunk-G5S4ASP3.js +277 -0
  6. package/dist/chunk-G5S4ASP3.js.map +1 -0
  7. package/dist/{chunk-W3ROOC6E.js → chunk-MF2WE3OM.js} +145 -36
  8. package/dist/chunk-MF2WE3OM.js.map +1 -0
  9. package/dist/chunk-OZKTOILD.js +3 -0
  10. package/dist/chunk-OZKTOILD.js.map +1 -0
  11. package/dist/{chunk-NXMUX67A.js → chunk-S3GGEEA5.js} +31 -8
  12. package/dist/chunk-S3GGEEA5.js.map +1 -0
  13. package/dist/elements/index.d.cts +2 -2
  14. package/dist/elements/index.d.ts +2 -2
  15. package/dist/elements/index.js +2 -1
  16. package/dist/index.cjs +454 -66
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.cts +7 -62
  19. package/dist/index.d.ts +7 -62
  20. package/dist/index.js +6 -40
  21. package/dist/index.js.map +1 -1
  22. package/dist/modeling/index.cjs +894 -0
  23. package/dist/modeling/index.cjs.map +1 -0
  24. package/dist/modeling/index.d.cts +88 -0
  25. package/dist/modeling/index.d.ts +88 -0
  26. package/dist/modeling/index.js +5 -0
  27. package/dist/modeling/index.js.map +1 -0
  28. package/dist/nodes/index.cjs +29 -6
  29. package/dist/nodes/index.cjs.map +1 -1
  30. package/dist/nodes/index.js +1 -1
  31. package/dist/{types-C78d_Kdh.d.cts → types-BKA0GZz5.d.cts} +6 -18
  32. package/dist/{types-C78d_Kdh.d.ts → types-BKA0GZz5.d.ts} +6 -18
  33. package/dist/types-CCkHqtC_.d.cts +20 -0
  34. package/dist/types-hj621ZRJ.d.ts +20 -0
  35. package/dist/xml/index.cjs +143 -34
  36. package/dist/xml/index.cjs.map +1 -1
  37. package/dist/xml/index.d.cts +4 -19
  38. package/dist/xml/index.d.ts +4 -19
  39. package/dist/xml/index.js +1 -1
  40. package/package.json +10 -3
  41. package/dist/chunk-NXMUX67A.js.map +0 -1
  42. package/dist/chunk-W3ROOC6E.js.map +0 -1
@@ -1,4 +1,4 @@
1
- export { AnnotationNode, BPMN_NODE_TYPES, BoundaryEventNode, CallChoreographyNode, CallConversationNode, ChoreographyTaskNode, ConversationNode, DataInputNode, DataObjectNode, DataObjectReferenceNode, DataOutputNode, DataStoreNode, DataStoreReferenceNode, EndEventNode, GatewayNode, GroupNode, IntermediateCatchEventNode, IntermediateThrowEventNode, LaneNode, PoolNode, StartEventNode, SubChoreographyNode, SubConversationNode, SubProcessNode, TaskNode } from '../chunk-NXMUX67A.js';
1
+ export { AnnotationNode, BPMN_NODE_TYPES, BoundaryEventNode, CallChoreographyNode, CallConversationNode, ChoreographyTaskNode, ConversationNode, DataInputNode, DataObjectNode, DataObjectReferenceNode, DataOutputNode, DataStoreNode, DataStoreReferenceNode, EndEventNode, GatewayNode, GroupNode, IntermediateCatchEventNode, IntermediateThrowEventNode, LaneNode, PoolNode, StartEventNode, SubChoreographyNode, SubConversationNode, SubProcessNode, TaskNode } from '../chunk-S3GGEEA5.js';
2
2
  import '../chunk-23B2IGK5.js';
3
3
  //# sourceMappingURL=index.js.map
4
4
  //# sourceMappingURL=index.js.map
@@ -51,6 +51,10 @@ interface BpmnNodeData extends Record<string, unknown> {
51
51
  trigger?: EventTrigger;
52
52
  /** True for non-interrupting boundary events / event sub-process starts. */
53
53
  isNonInterrupting?: boolean;
54
+ /** BoundaryEvent only: BPMN element id this boundary event is attached to. */
55
+ attachedToRef?: string;
56
+ /** Raw BPMN documentation text. */
57
+ documentation?: string;
54
58
  /** Task instance markers shown at the bottom of the task box. */
55
59
  markers?: TaskMarker[];
56
60
  /** Sub-process structural variant (defaults to "embedded"). */
@@ -76,24 +80,6 @@ interface BpmnNodeData extends Record<string, unknown> {
76
80
  owner?: string;
77
81
  /** ISO 8601 duration, e.g. "PT4H". */
78
82
  sla?: string;
79
- /** flowable:assignee — UEL expression or static user id. */
80
- flowableAssignee?: string;
81
- /** flowable:candidateGroups — comma-separated group ids or UEL expression. */
82
- flowableCandidateGroups?: string;
83
- /** flowable:candidateUsers — comma-separated user ids or UEL expression. */
84
- flowableCandidateUsers?: string;
85
- /** flowable:formKey — form definition key (for UserTask / StartEvent). */
86
- flowableFormKey?: string;
87
- /** flowable:dueDate — UEL expression resolving to a Date. */
88
- flowableDueDate?: string;
89
- /** flowable:type — service task type: "http" | "mail" | "camel" | "mule". */
90
- flowableType?: string;
91
- /** flowable:expression — UEL expression for ServiceTask / SequenceFlow. */
92
- flowableExpression?: string;
93
- /** flowable:class — fully-qualified Java class name for ServiceTask. */
94
- flowableClass?: string;
95
- /** flowable:delegateExpression — UEL expression resolving to a JavaDelegate. */
96
- flowableDelegateExpression?: string;
97
83
  }
98
84
  interface BpmnEdgeData extends Record<string, unknown> {
99
85
  label?: string;
@@ -101,6 +87,8 @@ interface BpmnEdgeData extends Record<string, unknown> {
101
87
  conditionExpression?: string;
102
88
  /** Sequence flow marked as the default path of a gateway/activity. */
103
89
  isDefault?: boolean;
90
+ /** Raw BPMN documentation text. */
91
+ documentation?: string;
104
92
  /** Directionality for associations. */
105
93
  associationDirection?: "none" | "one" | "both";
106
94
  /** Routing points produced by ELK. */
@@ -51,6 +51,10 @@ interface BpmnNodeData extends Record<string, unknown> {
51
51
  trigger?: EventTrigger;
52
52
  /** True for non-interrupting boundary events / event sub-process starts. */
53
53
  isNonInterrupting?: boolean;
54
+ /** BoundaryEvent only: BPMN element id this boundary event is attached to. */
55
+ attachedToRef?: string;
56
+ /** Raw BPMN documentation text. */
57
+ documentation?: string;
54
58
  /** Task instance markers shown at the bottom of the task box. */
55
59
  markers?: TaskMarker[];
56
60
  /** Sub-process structural variant (defaults to "embedded"). */
@@ -76,24 +80,6 @@ interface BpmnNodeData extends Record<string, unknown> {
76
80
  owner?: string;
77
81
  /** ISO 8601 duration, e.g. "PT4H". */
78
82
  sla?: string;
79
- /** flowable:assignee — UEL expression or static user id. */
80
- flowableAssignee?: string;
81
- /** flowable:candidateGroups — comma-separated group ids or UEL expression. */
82
- flowableCandidateGroups?: string;
83
- /** flowable:candidateUsers — comma-separated user ids or UEL expression. */
84
- flowableCandidateUsers?: string;
85
- /** flowable:formKey — form definition key (for UserTask / StartEvent). */
86
- flowableFormKey?: string;
87
- /** flowable:dueDate — UEL expression resolving to a Date. */
88
- flowableDueDate?: string;
89
- /** flowable:type — service task type: "http" | "mail" | "camel" | "mule". */
90
- flowableType?: string;
91
- /** flowable:expression — UEL expression for ServiceTask / SequenceFlow. */
92
- flowableExpression?: string;
93
- /** flowable:class — fully-qualified Java class name for ServiceTask. */
94
- flowableClass?: string;
95
- /** flowable:delegateExpression — UEL expression resolving to a JavaDelegate. */
96
- flowableDelegateExpression?: string;
97
83
  }
98
84
  interface BpmnEdgeData extends Record<string, unknown> {
99
85
  label?: string;
@@ -101,6 +87,8 @@ interface BpmnEdgeData extends Record<string, unknown> {
101
87
  conditionExpression?: string;
102
88
  /** Sequence flow marked as the default path of a gateway/activity. */
103
89
  isDefault?: boolean;
90
+ /** Raw BPMN documentation text. */
91
+ documentation?: string;
104
92
  /** Directionality for associations. */
105
93
  associationDirection?: "none" | "one" | "both";
106
94
  /** Routing points produced by ELK. */
@@ -0,0 +1,20 @@
1
+ import { Node, Edge } from '@xyflow/react';
2
+ import { g as BpmnNodeData, a as BpmnEdgeData } from './types-BKA0GZz5.cjs';
3
+
4
+ type BpmnRFNode = Node<BpmnNodeData>;
5
+ type BpmnRFEdge = Edge<BpmnEdgeData>;
6
+ interface BpmnImportResult {
7
+ nodes: BpmnRFNode[];
8
+ edges: BpmnRFEdge[];
9
+ warnings: string[];
10
+ }
11
+ interface BpmnExportOptions {
12
+ /** Diagram name written into the XML. */
13
+ name?: string;
14
+ /** Definitions element id. Defaults to "Definitions_1". */
15
+ id?: string;
16
+ /** Pretty-print the XML output. Defaults to true. */
17
+ format?: boolean;
18
+ }
19
+
20
+ export type { BpmnExportOptions as B, BpmnImportResult as a, BpmnRFEdge as b, BpmnRFNode as c };
@@ -0,0 +1,20 @@
1
+ import { Node, Edge } from '@xyflow/react';
2
+ import { g as BpmnNodeData, a as BpmnEdgeData } from './types-BKA0GZz5.js';
3
+
4
+ type BpmnRFNode = Node<BpmnNodeData>;
5
+ type BpmnRFEdge = Edge<BpmnEdgeData>;
6
+ interface BpmnImportResult {
7
+ nodes: BpmnRFNode[];
8
+ edges: BpmnRFEdge[];
9
+ warnings: string[];
10
+ }
11
+ interface BpmnExportOptions {
12
+ /** Diagram name written into the XML. */
13
+ name?: string;
14
+ /** Definitions element id. Defaults to "Definitions_1". */
15
+ id?: string;
16
+ /** Pretty-print the XML output. Defaults to true. */
17
+ format?: boolean;
18
+ }
19
+
20
+ export type { BpmnExportOptions as B, BpmnImportResult as a, BpmnRFEdge as b, BpmnRFNode as c };
@@ -592,8 +592,8 @@ var MODDLE_TO_ELEMENT_TYPE = {
592
592
  "bpmn:EventBasedGateway": "EventBasedGateway",
593
593
  "bpmn:ComplexGateway": "ComplexGateway",
594
594
  "bpmn:SubProcess": "SubProcess",
595
- "bpmn:AdHocSubProcess": "SubProcess",
596
- "bpmn:Transaction": "SubProcess",
595
+ "bpmn:AdHocSubProcess": "AdHocSubProcess",
596
+ "bpmn:Transaction": "Transaction",
597
597
  "bpmn:TextAnnotation": "Annotation",
598
598
  "bpmn:Group": "Group",
599
599
  "bpmn:DataObject": "DataObject",
@@ -631,6 +631,9 @@ var ELEMENT_TYPE_TO_MODDLE = {
631
631
  EventBasedGateway: "bpmn:EventBasedGateway",
632
632
  ComplexGateway: "bpmn:ComplexGateway",
633
633
  SubProcess: "bpmn:SubProcess",
634
+ Transaction: "bpmn:Transaction",
635
+ EventSubProcess: "bpmn:SubProcess",
636
+ AdHocSubProcess: "bpmn:AdHocSubProcess",
634
637
  Pool: "bpmn:Participant",
635
638
  Lane: "bpmn:Lane",
636
639
  Annotation: "bpmn:TextAnnotation",
@@ -695,6 +698,10 @@ function asElements(v) {
695
698
  function asString(v) {
696
699
  return typeof v === "string" && v.trim() ? v.trim() : void 0;
697
700
  }
701
+ function extractDocumentation(el) {
702
+ const [doc] = asElements(el.documentation);
703
+ return asString(doc?.text);
704
+ }
698
705
  function extractDiagramInfo(definitions) {
699
706
  const shapes = /* @__PURE__ */ new Map();
700
707
  const waypoints = /* @__PURE__ */ new Map();
@@ -750,6 +757,7 @@ function extractTrigger(el) {
750
757
  function extractSubProcessVariant(el) {
751
758
  if (el.$type === "bpmn:Transaction") return "transaction";
752
759
  if (el.$type === "bpmn:AdHocSubProcess") return "adhoc";
760
+ if (el.$type === "bpmn:SubProcess" && el.triggeredByEvent === true) return "event";
753
761
  if (el.triggeredByEvent === true) return "event";
754
762
  return "embedded";
755
763
  }
@@ -763,7 +771,7 @@ function walkFlowElements(elements, parentId, ctx, nodes, edges) {
763
771
  continue;
764
772
  }
765
773
  if ($type === "bpmn:LaneSet") continue;
766
- const elementType = MODDLE_TO_ELEMENT_TYPE[$type];
774
+ const elementType = $type === "bpmn:SubProcess" && el.triggeredByEvent === true ? "EventSubProcess" : MODDLE_TO_ELEMENT_TYPE[$type];
767
775
  if (!elementType) {
768
776
  ctx.warnings.push(`Unknown element type "${$type}" (id=${id}) \u2014 skipped.`);
769
777
  continue;
@@ -784,22 +792,26 @@ function buildNode(el, elementType, parentId, ctx, nodes) {
784
792
  const y = shape?.y ?? 100;
785
793
  if (!shape) ctx.autoX.value += (meta?.defaultWidth ?? 120) + 20;
786
794
  const label = asString(el.name);
795
+ const documentation = extractDocumentation(el);
787
796
  const trigger = extractTrigger(el);
788
797
  const isNonInterrupting = el.cancelActivity === false;
798
+ const attachedToRef = el.attachedToRef?.id;
789
799
  const data = {
790
800
  elementType,
791
801
  ...label ? { label } : {},
802
+ ...documentation ? { documentation } : {},
792
803
  ...trigger ? { trigger } : {},
793
- ...isNonInterrupting ? { isNonInterrupting: true } : {}
804
+ ...isNonInterrupting ? { isNonInterrupting: true } : {},
805
+ ...attachedToRef ? { attachedToRef } : {}
794
806
  };
795
- if (elementType === "SubProcess") {
807
+ if (elementType === "SubProcess" || elementType === "Transaction" || elementType === "EventSubProcess" || elementType === "AdHocSubProcess") {
796
808
  const variant = extractSubProcessVariant(el);
797
809
  if (variant) data.subProcessVariant = variant;
798
810
  const isExpanded = shape?.isExpanded ?? true;
799
811
  data.isExpanded = isExpanded;
800
812
  }
801
813
  const laneId = ctx.laneMembership.get(id);
802
- const effectiveParentId = laneId ?? parentId;
814
+ const effectiveParentId = attachedToRef ?? laneId ?? parentId;
803
815
  const node = {
804
816
  id,
805
817
  type: elementType,
@@ -820,10 +832,12 @@ function buildEdge(el, edgeType, ctx, edges) {
820
832
  return;
821
833
  }
822
834
  const label = asString(el.name);
835
+ const documentation = extractDocumentation(el);
823
836
  const condExpr = el.conditionExpression;
824
837
  const data = {
825
838
  edgeType,
826
839
  ...label ? { label } : {},
840
+ ...documentation ? { documentation } : {},
827
841
  ...condExpr?.body ? { conditionExpression: condExpr.body } : {}
828
842
  };
829
843
  const waypoints = ctx.waypoints.get(id);
@@ -924,7 +938,46 @@ async function parseBpmnXml(xml) {
924
938
  );
925
939
  }
926
940
  }
927
- return { nodes, edges, warnings };
941
+ const defaultFlowById = /* @__PURE__ */ new Set();
942
+ const nodeIds = new Set(nodes.map((node) => node.id));
943
+ for (const rootEl of asElements(rootElement.rootElements)) {
944
+ collectDefaultFlows(rootEl, defaultFlowById);
945
+ }
946
+ const normalizedEdges = edges.map((edge) => {
947
+ if (!defaultFlowById.has(edge.id)) return edge;
948
+ const data = {
949
+ edgeType: edge.data?.edgeType ?? edge.type,
950
+ ...edge.data ?? {},
951
+ isDefault: true
952
+ };
953
+ return { ...edge, data };
954
+ });
955
+ return {
956
+ nodes: normalizeChildPositions(nodes, nodeIds),
957
+ edges: normalizedEdges,
958
+ warnings
959
+ };
960
+ }
961
+ function collectDefaultFlows(el, defaultFlowById) {
962
+ const defaultRef = el.default;
963
+ if (defaultRef?.id) defaultFlowById.add(defaultRef.id);
964
+ for (const child of asElements(el.rootElements)) collectDefaultFlows(child, defaultFlowById);
965
+ for (const child of asElements(el.flowElements)) collectDefaultFlows(child, defaultFlowById);
966
+ }
967
+ function normalizeChildPositions(nodes, nodeIds) {
968
+ const absoluteById = new Map(nodes.map((node) => [node.id, node.position]));
969
+ return nodes.map((node) => {
970
+ if (!node.parentId || !nodeIds.has(node.parentId)) return node;
971
+ const parentPosition = absoluteById.get(node.parentId);
972
+ if (!parentPosition) return node;
973
+ return {
974
+ ...node,
975
+ position: {
976
+ x: node.position.x - parentPosition.x,
977
+ y: node.position.y - parentPosition.y
978
+ }
979
+ };
980
+ });
928
981
  }
929
982
  function uid(prefix, id) {
930
983
  return `${prefix}_${id}`;
@@ -932,19 +985,6 @@ function uid(prefix, id) {
932
985
  function asNodes(nodes, types) {
933
986
  return nodes.filter((n) => types.includes(n.data.elementType));
934
987
  }
935
- function buildFlowableAttrs(data) {
936
- const attrs = {};
937
- if (data.flowableAssignee) attrs["flowable:assignee"] = data.flowableAssignee;
938
- if (data.flowableCandidateGroups) attrs["flowable:candidateGroups"] = data.flowableCandidateGroups;
939
- if (data.flowableCandidateUsers) attrs["flowable:candidateUsers"] = data.flowableCandidateUsers;
940
- if (data.flowableFormKey) attrs["flowable:formKey"] = data.flowableFormKey;
941
- if (data.flowableDueDate) attrs["flowable:dueDate"] = data.flowableDueDate;
942
- if (data.flowableType) attrs["flowable:type"] = data.flowableType;
943
- if (data.flowableExpression) attrs["flowable:expression"] = data.flowableExpression;
944
- if (data.flowableClass) attrs["flowable:class"] = data.flowableClass;
945
- if (data.flowableDelegateExpression) attrs["flowable:delegateExpression"] = data.flowableDelegateExpression;
946
- return attrs;
947
- }
948
988
  function buildSemanticModel(moddle, nodes, edges, opts) {
949
989
  const defId = opts.id ?? "Definitions_1";
950
990
  const defName = opts.name;
@@ -1003,13 +1043,26 @@ function buildSemanticModel(moddle, nodes, edges, opts) {
1003
1043
  return definitions;
1004
1044
  }
1005
1045
  function buildProcess(moddle, allNodes, allEdges, poolId, laneNodes, processId) {
1006
- const myNodes = poolId ? allNodes.filter(
1046
+ const subProcessIds = new Set(
1047
+ allNodes.filter(
1048
+ (n) => n.data.elementType === "SubProcess" || n.data.elementType === "Transaction" || n.data.elementType === "EventSubProcess" || n.data.elementType === "AdHocSubProcess"
1049
+ ).map((n) => n.id)
1050
+ );
1051
+ const isInsideSubProcess = (node) => {
1052
+ let parentId = node.parentId;
1053
+ while (parentId) {
1054
+ if (subProcessIds.has(parentId)) return true;
1055
+ parentId = allNodes.find((candidate) => candidate.id === parentId)?.parentId;
1056
+ }
1057
+ return false;
1058
+ };
1059
+ const myNodes = (poolId ? allNodes.filter(
1007
1060
  (n) => n.parentId === poolId || laneNodes.some((l) => l.id === n.parentId && l.parentId === poolId)
1008
- ) : allNodes.filter((n) => n.data.elementType !== "Pool" && n.data.elementType !== "Lane");
1061
+ ) : allNodes.filter((n) => n.data.elementType !== "Pool" && n.data.elementType !== "Lane")).filter((n) => !isInsideSubProcess(n));
1009
1062
  const myLanes = laneNodes.filter((l) => poolId ? l.parentId === poolId : true);
1010
1063
  const flowElements = [];
1011
1064
  for (const node of myNodes) {
1012
- const el = buildFlowElement(moddle, node);
1065
+ const el = buildFlowElement(moddle, node, allNodes, allEdges);
1013
1066
  if (el) flowElements.push(el);
1014
1067
  }
1015
1068
  const myNodeIds = new Set(myNodes.map((n) => n.id));
@@ -1020,6 +1073,17 @@ function buildProcess(moddle, allNodes, allEdges, poolId, laneNodes, processId)
1020
1073
  const edgeMeta = buildEdgeElement(moddle, edge);
1021
1074
  if (edgeMeta) flowElements.push(edgeMeta);
1022
1075
  }
1076
+ const elementById = new Map(
1077
+ flowElements.filter((element) => typeof element.id === "string").map((element) => [element.id, element])
1078
+ );
1079
+ for (const edge of myEdges) {
1080
+ if (!edge.data?.isDefault) continue;
1081
+ const sourceElement = elementById.get(edge.source);
1082
+ const edgeElement = elementById.get(edge.id);
1083
+ if (sourceElement && edgeElement) {
1084
+ sourceElement.default = edgeElement;
1085
+ }
1086
+ }
1023
1087
  const process = moddle.create("bpmn:Process", {
1024
1088
  id: processId,
1025
1089
  isExecutable: true,
@@ -1040,7 +1104,7 @@ function buildProcess(moddle, allNodes, allEdges, poolId, laneNodes, processId)
1040
1104
  }
1041
1105
  return process;
1042
1106
  }
1043
- function buildFlowElement(moddle, node, _allNodes, _allEdges) {
1107
+ function buildFlowElement(moddle, node, allNodes, allEdges) {
1044
1108
  const { elementType, label, trigger } = node.data;
1045
1109
  if (elementType === "Pool" || elementType === "Lane") return null;
1046
1110
  const moddleType = ELEMENT_TYPE_TO_MODDLE[elementType];
@@ -1049,25 +1113,46 @@ function buildFlowElement(moddle, node, _allNodes, _allEdges) {
1049
1113
  id: node.id,
1050
1114
  name: label ?? ""
1051
1115
  };
1116
+ if (node.data.documentation) {
1117
+ attrs.documentation = [
1118
+ moddle.create("bpmn:Documentation", { text: node.data.documentation })
1119
+ ];
1120
+ }
1052
1121
  if (trigger && trigger !== "none") {
1053
1122
  const defType = TRIGGER_TO_EVENT_DEF[trigger];
1054
1123
  if (defType) {
1055
1124
  attrs.eventDefinitions = [moddle.create(defType, { id: uid("EventDef", node.id) })];
1056
1125
  }
1057
1126
  }
1058
- if (elementType === "SubProcess" && node.data.subProcessVariant === "transaction") {
1059
- return moddle.create("bpmn:Transaction", attrs);
1127
+ if (elementType === "BoundaryEvent") {
1128
+ attrs.attachedToRef = { id: node.data.attachedToRef ?? node.parentId };
1129
+ attrs.cancelActivity = node.data.isNonInterrupting ? false : true;
1060
1130
  }
1061
- if (elementType === "SubProcess" && node.data.subProcessVariant === "adhoc") {
1062
- return moddle.create("bpmn:AdHocSubProcess", attrs);
1131
+ const isSubProcess = elementType === "SubProcess" || elementType === "Transaction" || elementType === "EventSubProcess" || elementType === "AdHocSubProcess";
1132
+ if (isSubProcess) {
1133
+ attrs.flowElements = buildNestedFlowElements(moddle, node, allNodes, allEdges);
1134
+ if (elementType === "EventSubProcess" || node.data.subProcessVariant === "event") {
1135
+ attrs.triggeredByEvent = true;
1136
+ }
1063
1137
  }
1064
1138
  const element = moddle.create(moddleType, attrs);
1065
- const flowableAttrs = buildFlowableAttrs(node.data);
1066
- if (Object.keys(flowableAttrs).length > 0) {
1067
- element.$attrs = flowableAttrs;
1068
- }
1069
1139
  return element;
1070
1140
  }
1141
+ function buildNestedFlowElements(moddle, parent, allNodes, allEdges) {
1142
+ const childNodes = allNodes.filter((node) => node.parentId === parent.id);
1143
+ const childNodeIds = new Set(childNodes.map((node) => node.id));
1144
+ const flowElements = [];
1145
+ for (const child of childNodes) {
1146
+ const element = buildFlowElement(moddle, child, allNodes, allEdges);
1147
+ if (element) flowElements.push(element);
1148
+ }
1149
+ for (const edge of allEdges) {
1150
+ if (!childNodeIds.has(edge.source) || !childNodeIds.has(edge.target)) continue;
1151
+ const element = buildEdgeElement(moddle, edge);
1152
+ if (element) flowElements.push(element);
1153
+ }
1154
+ return flowElements;
1155
+ }
1071
1156
  function buildEdgeElement(moddle, edge) {
1072
1157
  if (!edge.data) return null;
1073
1158
  const moddleType = EDGE_TYPE_TO_MODDLE[edge.data.edgeType];
@@ -1078,6 +1163,11 @@ function buildEdgeElement(moddle, edge) {
1078
1163
  sourceRef: { id: edge.source },
1079
1164
  targetRef: { id: edge.target }
1080
1165
  };
1166
+ if (edge.data.documentation) {
1167
+ attrs.documentation = [
1168
+ moddle.create("bpmn:Documentation", { text: edge.data.documentation })
1169
+ ];
1170
+ }
1081
1171
  if (edge.data.conditionExpression) {
1082
1172
  attrs.conditionExpression = moddle.create("bpmn:FormalExpression", {
1083
1173
  body: edge.data.conditionExpression
@@ -1088,13 +1178,14 @@ function buildEdgeElement(moddle, edge) {
1088
1178
  function buildBpmnDI(moddle, definitions, nodes, edges) {
1089
1179
  const shapes = [];
1090
1180
  const edgeShapes = [];
1181
+ const absolutePositionById = buildAbsolutePositionMap(nodes);
1091
1182
  for (const node of nodes) {
1092
1183
  const meta = BPMN_ELEMENT_CATALOG[node.data.elementType];
1093
1184
  const w = node.width ?? meta?.defaultWidth ?? 120;
1094
1185
  const h = node.height ?? meta?.defaultHeight ?? 60;
1095
1186
  const bounds = moddle.create("dc:Bounds", {
1096
- x: node.position.x,
1097
- y: node.position.y,
1187
+ x: absolutePositionById.get(node.id)?.x ?? node.position.x,
1188
+ y: absolutePositionById.get(node.id)?.y ?? node.position.y,
1098
1189
  width: w,
1099
1190
  height: h
1100
1191
  });
@@ -1133,6 +1224,24 @@ function buildBpmnDI(moddle, definitions, nodes, edges) {
1133
1224
  });
1134
1225
  definitions.diagrams = [diagram];
1135
1226
  }
1227
+ function buildAbsolutePositionMap(nodes) {
1228
+ const nodeById = new Map(nodes.map((node) => [node.id, node]));
1229
+ const absoluteById = /* @__PURE__ */ new Map();
1230
+ function resolve(node) {
1231
+ const cached = absoluteById.get(node.id);
1232
+ if (cached) return cached;
1233
+ const parent = node.parentId ? nodeById.get(node.parentId) : void 0;
1234
+ const parentPosition = parent ? resolve(parent) : { x: 0, y: 0 };
1235
+ const absolute = {
1236
+ x: parentPosition.x + node.position.x,
1237
+ y: parentPosition.y + node.position.y
1238
+ };
1239
+ absoluteById.set(node.id, absolute);
1240
+ return absolute;
1241
+ }
1242
+ for (const node of nodes) resolve(node);
1243
+ return absoluteById;
1244
+ }
1136
1245
  async function serializeBpmnXml(nodes, edges, opts = {}) {
1137
1246
  const moddle = new bpmnModdle.BpmnModdle();
1138
1247
  const definitions = buildSemanticModel(moddle, nodes, edges, opts);