@aranzatech/diagrams-bpmn 0.2.11 → 0.2.12

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,9 +1,97 @@
1
1
  import { getBpmnNodeSize } from '../chunk-UAWLUDKC.js';
2
2
  import '../chunk-RLAJNRF2.js';
3
3
  import '../chunk-L5Z22RLX.js';
4
- import { dagreLayout, applyLayoutResultToDiagram } from '@aranzatech/diagrams-core/layout';
4
+ import { elkLayout, dagreLayout, applyLayoutResultToDiagram } from '@aranzatech/diagrams-core/layout';
5
5
  export { applyLayoutResultToDiagram } from '@aranzatech/diagrams-core/layout';
6
6
 
7
+ var BPMN_CONTAINER_TYPES = /* @__PURE__ */ new Set([
8
+ "Pool",
9
+ "Lane",
10
+ "SubProcess",
11
+ "Transaction",
12
+ "EventSubProcess",
13
+ "AdHocSubProcess"
14
+ ]);
15
+ var CONTAINER_MIN_SIZE = {
16
+ Pool: { w: 560, h: 160 },
17
+ Lane: { w: 480, h: 100 },
18
+ SubProcess: { w: 200, h: 120 },
19
+ Transaction: { w: 200, h: 120 },
20
+ EventSubProcess: { w: 200, h: 120 },
21
+ AdHocSubProcess: { w: 200, h: 120 }
22
+ };
23
+ var CONTAINER_PADDING = {
24
+ Pool: "[top=20,left=30,bottom=20,right=20]",
25
+ Lane: "[top=20,left=50,bottom=20,right=50]",
26
+ SubProcess: "[top=20,left=30,bottom=20,right=30]",
27
+ Transaction: "[top=20,left=30,bottom=20,right=30]",
28
+ EventSubProcess: "[top=20,left=30,bottom=20,right=30]",
29
+ AdHocSubProcess: "[top=20,left=30,bottom=20,right=30]"
30
+ };
31
+ async function bpmnElkLayout(nodes, edges) {
32
+ const poolsWithLanes = /* @__PURE__ */ new Set();
33
+ for (const node of nodes) {
34
+ if (node.data.elementType === "Lane" && node.parentId) {
35
+ poolsWithLanes.add(node.parentId);
36
+ }
37
+ }
38
+ const result = await elkLayout(
39
+ nodes,
40
+ edges,
41
+ {
42
+ direction: "LR",
43
+ getNodeSize: (node) => {
44
+ const bNode = node;
45
+ if (BPMN_CONTAINER_TYPES.has(bNode.data.elementType)) return void 0;
46
+ return getBpmnNodeSize(bNode);
47
+ },
48
+ isContainerNode: (node) => BPMN_CONTAINER_TYPES.has(node.data.elementType),
49
+ getNodeLayoutOptions: (node) => {
50
+ const type = node.data.elementType;
51
+ if (!BPMN_CONTAINER_TYPES.has(type)) return void 0;
52
+ const min = CONTAINER_MIN_SIZE[type];
53
+ const dir = type === "Pool" && poolsWithLanes.has(node.id) ? "DOWN" : "RIGHT";
54
+ return {
55
+ "elk.direction": dir,
56
+ "elk.nodeSize.constraints": "MINIMUM_SIZE",
57
+ ...min ? { "elk.nodeSize.minimum": `[w=${min.w},h=${min.h}]` } : {},
58
+ ...CONTAINER_PADDING[type] ? { "elk.padding": CONTAINER_PADDING[type] } : {}
59
+ };
60
+ },
61
+ elk: {
62
+ "elk.algorithm": "layered",
63
+ "elk.direction": "RIGHT",
64
+ "elk.hierarchyHandling": "INCLUDE_CHILDREN",
65
+ "elk.edgeRouting": "ORTHOGONAL",
66
+ "elk.layered.spacing.nodeNodeBetweenLayers": "80",
67
+ "elk.layered.spacing.edgeNodeBetweenLayers": "20",
68
+ "elk.spacing.nodeNode": "40",
69
+ "elk.spacing.componentComponent": "60"
70
+ }
71
+ }
72
+ );
73
+ const nodeMap = new Map(result.nodes.map((n) => [n.id, n]));
74
+ const edgeMap = new Map(result.edges.map((e) => [e.id, e]));
75
+ const updatedNodes = nodes.map((node) => {
76
+ const laid = nodeMap.get(node.id);
77
+ if (!laid) return node;
78
+ return { ...node, position: laid.position, width: laid.width, height: laid.height };
79
+ });
80
+ const updatedEdges = edges.map((edge) => {
81
+ const laid = edgeMap.get(edge.id);
82
+ if (!laid) return edge;
83
+ const nextData = { ...edge.data };
84
+ if (laid.points && laid.points.length > 0) {
85
+ nextData.routingPoints = laid.points;
86
+ } else {
87
+ delete nextData.routingPoints;
88
+ }
89
+ return { ...edge, data: nextData };
90
+ });
91
+ return { nodes: updatedNodes, edges: updatedEdges };
92
+ }
93
+
94
+ // src/layout/index.ts
7
95
  async function bpmnDagreLayout(nodes, edges, options = {}) {
8
96
  return dagreLayout(nodes, edges, {
9
97
  ...options,
@@ -14,6 +102,6 @@ function applyBpmnLayoutResult(state, result) {
14
102
  return applyLayoutResultToDiagram(state, result);
15
103
  }
16
104
 
17
- export { applyBpmnLayoutResult, bpmnDagreLayout };
105
+ export { applyBpmnLayoutResult, bpmnDagreLayout, bpmnElkLayout };
18
106
  //# sourceMappingURL=index.js.map
19
107
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/layout/index.ts"],"names":[],"mappings":";;;;;;AAcA,eAAsB,eAAA,CACpB,KAAA,EACA,KAAA,EACA,OAAA,GAAyB,EAAC,EACH;AACvB,EAAA,OAAO,WAAA,CAAY,OAAwB,KAAA,EAAwB;AAAA,IACjE,GAAG,OAAA;AAAA,IACH,WAAA,EAAa,CAAC,IAAA,KAAS,eAAA,CAAgB,IAAkB;AAAA,GAC1D,CAAA;AACH;AAMO,SAAS,qBAAA,CACd,OACA,MAAA,EACkB;AAClB,EAAA,OAAO,0BAAA,CAA2B,OAAO,MAAM,CAAA;AACjD","file":"index.js","sourcesContent":["import type { DiagramEdge, LayoutOptions, LayoutResult } from \"@aranzatech/diagrams-core/types\";\nimport { dagreLayout, applyLayoutResultToDiagram } from \"@aranzatech/diagrams-core/layout\";\nimport type { DiagramNode } from \"@aranzatech/diagrams-core/types\";\nimport type { BpmnRFNode, BpmnRFEdge } from \"../xml/types\";\nimport { getBpmnNodeSize } from \"../modeling\";\nimport type { BpmnDiagramState } from \"../modeling\";\n\nexport { applyLayoutResultToDiagram };\n\n/**\n * Dagre layout pre-configured for BPMN diagrams.\n * Uses BPMN-specific node sizes (events 52×52, gateways 64×64, tasks 192×64, etc.)\n * instead of the generic fallback, which prevents overlaps and poor spacing.\n */\nexport async function bpmnDagreLayout(\n nodes: BpmnRFNode[],\n edges: BpmnRFEdge[],\n options: LayoutOptions = {},\n): Promise<LayoutResult> {\n return dagreLayout(nodes as DiagramNode[], edges as DiagramEdge[], {\n ...options,\n getNodeSize: (node) => getBpmnNodeSize(node as BpmnRFNode),\n });\n}\n\n/**\n * Applies a bpmn dagre layout result back to the diagram state.\n * Convenience wrapper so callers only need one import.\n */\nexport function applyBpmnLayoutResult(\n state: BpmnDiagramState,\n result: LayoutResult,\n): BpmnDiagramState {\n return applyLayoutResultToDiagram(state, result) as BpmnDiagramState;\n}\n"]}
1
+ {"version":3,"sources":["../../src/layout/elk.ts","../../src/layout/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { elkLayout } from \"@aranzatech/diagrams-core/layout\";\nimport type { DiagramNode, DiagramEdge } from \"@aranzatech/diagrams-core/types\";\nimport type { BpmnRFNode, BpmnRFEdge } from \"../xml/types\";\nimport type { BpmnElementType } from \"../elements/types\";\nimport { getBpmnNodeSize } from \"../modeling\";\n\n// Container types that ELK auto-sizes based on their children.\nconst BPMN_CONTAINER_TYPES = new Set<BpmnElementType>([\n \"Pool\",\n \"Lane\",\n \"SubProcess\",\n \"Transaction\",\n \"EventSubProcess\",\n \"AdHocSubProcess\",\n]);\n\nconst CONTAINER_MIN_SIZE: Partial<Record<BpmnElementType, { w: number; h: number }>> = {\n Pool: { w: 560, h: 160 },\n Lane: { w: 480, h: 100 },\n SubProcess: { w: 200, h: 120 },\n Transaction: { w: 200, h: 120 },\n EventSubProcess: { w: 200, h: 120 },\n AdHocSubProcess: { w: 200, h: 120 },\n};\n\n// Left padding includes the pool label strip (≈30 px).\nconst CONTAINER_PADDING: Partial<Record<BpmnElementType, string>> = {\n Pool: \"[top=20,left=30,bottom=20,right=20]\",\n Lane: \"[top=20,left=50,bottom=20,right=50]\",\n SubProcess: \"[top=20,left=30,bottom=20,right=30]\",\n Transaction: \"[top=20,left=30,bottom=20,right=30]\",\n EventSubProcess: \"[top=20,left=30,bottom=20,right=30]\",\n AdHocSubProcess: \"[top=20,left=30,bottom=20,right=30]\",\n};\n\n/**\n * ELK-based auto-layout for BPMN diagrams.\n *\n * Direction policy — always LEFT-TO-RIGHT to match screen anatomy:\n * - Root: RIGHT — free nodes and pools flow LR on the canvas.\n * - Pool that contains Lanes: DOWN internally so lanes stack top-to-bottom\n * (standard horizontal-pool anatomy); the pool itself is still placed LR.\n * - Pool without lanes, Lane, SubProcess, Transaction, AdHoc: RIGHT — content\n * flows left-to-right inside the container.\n * - All edges get ORTHOGONAL routing in a single INCLUDE_CHILDREN pass so\n * cross-pool and cross-lane edges are routed correctly.\n * - Containers auto-resize to fit their children.\n */\nexport async function bpmnElkLayout(\n nodes: BpmnRFNode[],\n edges: BpmnRFEdge[],\n): Promise<{ nodes: BpmnRFNode[]; edges: BpmnRFEdge[] }> {\n // Pools that contain at least one Lane child need DOWN internal direction so\n // the lanes stack vertically (standard horizontal BPMN pool).\n const poolsWithLanes = new Set<string>();\n for (const node of nodes) {\n if (node.data.elementType === \"Lane\" && node.parentId) {\n poolsWithLanes.add(node.parentId);\n }\n }\n\n const result = await elkLayout(\n nodes as unknown as DiagramNode[],\n edges as unknown as DiagramEdge[],\n {\n direction: \"LR\",\n getNodeSize: (node) => {\n const bNode = node as unknown as BpmnRFNode;\n if (BPMN_CONTAINER_TYPES.has(bNode.data.elementType)) return undefined;\n return getBpmnNodeSize(bNode);\n },\n isContainerNode: (node) =>\n BPMN_CONTAINER_TYPES.has((node as unknown as BpmnRFNode).data.elementType),\n getNodeLayoutOptions: (node) => {\n const type = (node as unknown as BpmnRFNode).data.elementType;\n if (!BPMN_CONTAINER_TYPES.has(type)) return undefined;\n const min = CONTAINER_MIN_SIZE[type];\n // Pool with Lanes: DOWN so lanes stack top-to-bottom inside the pool.\n // Everything else (Lane content, SubProcess, free tasks): RIGHT (LR).\n const dir = type === \"Pool\" && poolsWithLanes.has(node.id) ? \"DOWN\" : \"RIGHT\";\n return {\n \"elk.direction\": dir,\n \"elk.nodeSize.constraints\": \"MINIMUM_SIZE\",\n ...(min ? { \"elk.nodeSize.minimum\": `[w=${min.w},h=${min.h}]` } : {}),\n ...(CONTAINER_PADDING[type] ? { \"elk.padding\": CONTAINER_PADDING[type] } : {}),\n };\n },\n elk: {\n \"elk.algorithm\": \"layered\",\n \"elk.direction\": \"RIGHT\",\n \"elk.hierarchyHandling\": \"INCLUDE_CHILDREN\",\n \"elk.edgeRouting\": \"ORTHOGONAL\",\n \"elk.layered.spacing.nodeNodeBetweenLayers\": \"80\",\n \"elk.layered.spacing.edgeNodeBetweenLayers\": \"20\",\n \"elk.spacing.nodeNode\": \"40\",\n \"elk.spacing.componentComponent\": \"60\",\n },\n },\n );\n\n const nodeMap = new Map(result.nodes.map((n) => [n.id, n]));\n const edgeMap = new Map(result.edges.map((e) => [e.id, e]));\n\n const updatedNodes = nodes.map((node) => {\n const laid = nodeMap.get(node.id);\n if (!laid) return node;\n return { ...node, position: laid.position, width: laid.width, height: laid.height };\n });\n\n const updatedEdges = edges.map((edge) => {\n const laid = edgeMap.get(edge.id);\n if (!laid) return edge;\n const nextData = { ...edge.data };\n if (laid.points && laid.points.length > 0) {\n nextData.routingPoints = laid.points;\n } else {\n delete nextData.routingPoints;\n }\n return { ...edge, data: nextData };\n });\n\n return { nodes: updatedNodes, edges: updatedEdges as BpmnRFEdge[] };\n}\n","import type { DiagramEdge, LayoutOptions, LayoutResult } from \"@aranzatech/diagrams-core/types\";\nimport { dagreLayout, applyLayoutResultToDiagram } from \"@aranzatech/diagrams-core/layout\";\nimport type { DiagramNode } from \"@aranzatech/diagrams-core/types\";\nimport type { BpmnRFNode, BpmnRFEdge } from \"../xml/types\";\nimport { getBpmnNodeSize } from \"../modeling\";\nimport type { BpmnDiagramState } from \"../modeling\";\n\nexport { applyLayoutResultToDiagram };\nexport { bpmnElkLayout } from \"./elk\";\n\n/**\n * Dagre layout pre-configured for BPMN diagrams.\n * Uses BPMN-specific node sizes (events 52×52, gateways 64×64, tasks 192×64, etc.)\n * instead of the generic fallback, which prevents overlaps and poor spacing.\n */\nexport async function bpmnDagreLayout(\n nodes: BpmnRFNode[],\n edges: BpmnRFEdge[],\n options: LayoutOptions = {},\n): Promise<LayoutResult> {\n return dagreLayout(nodes as DiagramNode[], edges as DiagramEdge[], {\n ...options,\n getNodeSize: (node) => getBpmnNodeSize(node as BpmnRFNode),\n });\n}\n\n/**\n * Applies a bpmn dagre layout result back to the diagram state.\n * Convenience wrapper so callers only need one import.\n */\nexport function applyBpmnLayoutResult(\n state: BpmnDiagramState,\n result: LayoutResult,\n): BpmnDiagramState {\n return applyLayoutResultToDiagram(state, result) as BpmnDiagramState;\n}\n"]}
@@ -1,8 +1,8 @@
1
1
  import { ModelingRules, ClipboardState, DiagramSnapshot, DiagramState, DiagramEventBus, ResizeHandlePosition, DiagramCommand, ConnectionValidator, SmartGuideResult, SelectionState, LayoutCacheOptions, LayoutCache, EdgeLabelOffsetOptions, EdgeLabelLayout, CommandStackState, Viewport, LayoutFn } from '@aranzatech/diagrams-core';
2
2
  import { DiagramDocument, CreateDiagramDocumentOptions } from '@aranzatech/diagrams-core/serialization';
3
- import { c as BpmnEdgeType, b as BpmnEdgeData, f as BpmnElementType, m as BpmnNodeData } from '../types-BTuiBv7p.cjs';
4
- import { d as BpmnRFNode, c as BpmnRFEdge } from '../types-C7tONwP5.cjs';
5
- export { g as getBpmnElementSize, i as isBpmnElementResizable } from '../catalog-Ch3YT0-0.cjs';
3
+ import { c as BpmnEdgeType, b as BpmnEdgeData, f as BpmnElementType, m as BpmnNodeData } from '../types-hgmLfRA9.cjs';
4
+ import { d as BpmnRFNode, c as BpmnRFEdge } from '../types-44yNtMtO.cjs';
5
+ export { g as getBpmnElementSize, i as isBpmnElementResizable } from '../catalog-DUfPajtM.cjs';
6
6
  import '@xyflow/react';
7
7
 
8
8
  type BpmnDiagramState = DiagramState<BpmnRFNode, BpmnRFEdge>;
@@ -1,8 +1,8 @@
1
1
  import { ModelingRules, ClipboardState, DiagramSnapshot, DiagramState, DiagramEventBus, ResizeHandlePosition, DiagramCommand, ConnectionValidator, SmartGuideResult, SelectionState, LayoutCacheOptions, LayoutCache, EdgeLabelOffsetOptions, EdgeLabelLayout, CommandStackState, Viewport, LayoutFn } from '@aranzatech/diagrams-core';
2
2
  import { DiagramDocument, CreateDiagramDocumentOptions } from '@aranzatech/diagrams-core/serialization';
3
- import { c as BpmnEdgeType, b as BpmnEdgeData, f as BpmnElementType, m as BpmnNodeData } from '../types-BTuiBv7p.js';
4
- import { d as BpmnRFNode, c as BpmnRFEdge } from '../types-DSDMCAre.js';
5
- export { g as getBpmnElementSize, i as isBpmnElementResizable } from '../catalog-BOwJOaXV.js';
3
+ import { c as BpmnEdgeType, b as BpmnEdgeData, f as BpmnElementType, m as BpmnNodeData } from '../types-hgmLfRA9.js';
4
+ import { d as BpmnRFNode, c as BpmnRFEdge } from '../types-kI1SiQB4.js';
5
+ export { g as getBpmnElementSize, i as isBpmnElementResizable } from '../catalog-BKdtbOQT.js';
6
6
  import '@xyflow/react';
7
7
 
8
8
  type BpmnDiagramState = DiagramState<BpmnRFNode, BpmnRFEdge>;
@@ -1,5 +1,5 @@
1
1
  import { Node, Edge } from '@xyflow/react';
2
- import { m as BpmnNodeData, b as BpmnEdgeData, a as BpmnDefinitionsSet } from './types-BTuiBv7p.cjs';
2
+ import { m as BpmnNodeData, b as BpmnEdgeData, a as BpmnDefinitionsSet } from './types-hgmLfRA9.cjs';
3
3
 
4
4
  type BpmnRFNode = Node<BpmnNodeData>;
5
5
  type BpmnRFEdge = Edge<BpmnEdgeData>;
@@ -172,8 +172,24 @@ interface BpmnNodeData extends Record<string, unknown> {
172
172
  candidateUsers?: string;
173
173
  /** UserTask: comma-separated Flowable group ids that can claim this task. */
174
174
  candidateGroups?: string;
175
+ /** UserTask: ISO-8601 due date or FEEL expression evaluated at task creation. */
176
+ dueDate?: string;
177
+ /** UserTask: FEEL expression; when truthy the task is skipped. */
178
+ skipExpression?: string;
179
+ /** UserTask: name of the business calendar used to compute the due date. */
180
+ businessCalendarName?: string;
181
+ /** DataObjectReference: id of the backing bpmn:DataObject element. */
182
+ dataObjectRef?: string;
175
183
  /** AdHocSubProcess: FEEL expression that determines when the sub-process completes. */
176
184
  completionCondition?: string;
185
+ /** Loop / multi-instance type: none | loop | sequentialMultiple | parallelMultiple. */
186
+ loopType?: string;
187
+ /** StandardLoopCharacteristics: FEEL condition evaluated before each iteration. */
188
+ loopCondition?: string;
189
+ /** MultiInstanceLoopCharacteristics: number of instances as a FEEL expression. */
190
+ loopCardinality?: string;
191
+ /** MultiInstanceLoopCharacteristics: FEEL condition to stop before all instances finish. */
192
+ loopCompletionCondition?: string;
177
193
  }
178
194
  interface BpmnEdgeData extends Record<string, unknown> {
179
195
  label?: string;
@@ -172,8 +172,24 @@ interface BpmnNodeData extends Record<string, unknown> {
172
172
  candidateUsers?: string;
173
173
  /** UserTask: comma-separated Flowable group ids that can claim this task. */
174
174
  candidateGroups?: string;
175
+ /** UserTask: ISO-8601 due date or FEEL expression evaluated at task creation. */
176
+ dueDate?: string;
177
+ /** UserTask: FEEL expression; when truthy the task is skipped. */
178
+ skipExpression?: string;
179
+ /** UserTask: name of the business calendar used to compute the due date. */
180
+ businessCalendarName?: string;
181
+ /** DataObjectReference: id of the backing bpmn:DataObject element. */
182
+ dataObjectRef?: string;
175
183
  /** AdHocSubProcess: FEEL expression that determines when the sub-process completes. */
176
184
  completionCondition?: string;
185
+ /** Loop / multi-instance type: none | loop | sequentialMultiple | parallelMultiple. */
186
+ loopType?: string;
187
+ /** StandardLoopCharacteristics: FEEL condition evaluated before each iteration. */
188
+ loopCondition?: string;
189
+ /** MultiInstanceLoopCharacteristics: number of instances as a FEEL expression. */
190
+ loopCardinality?: string;
191
+ /** MultiInstanceLoopCharacteristics: FEEL condition to stop before all instances finish. */
192
+ loopCompletionCondition?: string;
177
193
  }
178
194
  interface BpmnEdgeData extends Record<string, unknown> {
179
195
  label?: string;
@@ -1,5 +1,5 @@
1
1
  import { Node, Edge } from '@xyflow/react';
2
- import { m as BpmnNodeData, b as BpmnEdgeData, a as BpmnDefinitionsSet } from './types-BTuiBv7p.js';
2
+ import { m as BpmnNodeData, b as BpmnEdgeData, a as BpmnDefinitionsSet } from './types-hgmLfRA9.js';
3
3
 
4
4
  type BpmnRFNode = Node<BpmnNodeData>;
5
5
  type BpmnRFEdge = Edge<BpmnEdgeData>;
@@ -1,6 +1,6 @@
1
- import { d as BpmnRFNode, c as BpmnRFEdge } from '../types-C7tONwP5.cjs';
1
+ import { d as BpmnRFNode, c as BpmnRFEdge } from '../types-44yNtMtO.cjs';
2
2
  import '@xyflow/react';
3
- import '../types-BTuiBv7p.cjs';
3
+ import '../types-hgmLfRA9.cjs';
4
4
 
5
5
  type BpmnValidationSeverity = "error" | "warning" | "info";
6
6
  interface BpmnValidationIssue {
@@ -1,6 +1,6 @@
1
- import { d as BpmnRFNode, c as BpmnRFEdge } from '../types-DSDMCAre.js';
1
+ import { d as BpmnRFNode, c as BpmnRFEdge } from '../types-kI1SiQB4.js';
2
2
  import '@xyflow/react';
3
- import '../types-BTuiBv7p.js';
3
+ import '../types-hgmLfRA9.js';
4
4
 
5
5
  type BpmnValidationSeverity = "error" | "warning" | "info";
6
6
  interface BpmnValidationIssue {
@@ -26,7 +26,11 @@ var ARANZA_DESCRIPTOR = {
26
26
  { name: "formKey", isAttr: true, type: "String" },
27
27
  // UserTask: Flowable task assignment — comma-separated ids
28
28
  { name: "candidateUsers", isAttr: true, type: "String" },
29
- { name: "candidateGroups", isAttr: true, type: "String" }
29
+ { name: "candidateGroups", isAttr: true, type: "String" },
30
+ // UserTask: scheduling + skip expression
31
+ { name: "dueDate", isAttr: true, type: "String" },
32
+ { name: "skipExpression", isAttr: true, type: "String" },
33
+ { name: "businessCalendarName", isAttr: true, type: "String" }
30
34
  ]
31
35
  }
32
36
  ],
@@ -933,6 +937,12 @@ function extractAranzaExtensions(el) {
933
937
  if (candidateUsers) result.candidateUsers = candidateUsers;
934
938
  const candidateGroups = asString(taskConfig.candidateGroups);
935
939
  if (candidateGroups) result.candidateGroups = candidateGroups;
940
+ const dueDate = asString(taskConfig.dueDate);
941
+ if (dueDate) result.dueDate = dueDate;
942
+ const skipExpression = asString(taskConfig.skipExpression);
943
+ if (skipExpression) result.skipExpression = skipExpression;
944
+ const businessCalendarName = asString(taskConfig.businessCalendarName);
945
+ if (businessCalendarName) result.businessCalendarName = businessCalendarName;
936
946
  return result;
937
947
  }
938
948
  function extractCompletionCondition(el) {
@@ -941,6 +951,25 @@ function extractCompletionCondition(el) {
941
951
  if (typeof cc === "string") return cc.trim() || void 0;
942
952
  return asString(cc.body);
943
953
  }
954
+ function extractLoopCharacteristics(el) {
955
+ const lc = el.loopCharacteristics;
956
+ if (!lc) return {};
957
+ if (lc.$type === "bpmn:StandardLoopCharacteristics") {
958
+ const loopCondition = asString(lc.loopCondition?.body);
959
+ return { loopType: "loop", ...loopCondition ? { loopCondition } : {} };
960
+ }
961
+ if (lc.$type === "bpmn:MultiInstanceLoopCharacteristics") {
962
+ const loopType = lc.isSequential === true ? "sequentialMultiple" : "parallelMultiple";
963
+ const loopCardinality = asString(lc.loopCardinality?.body);
964
+ const loopCompletionCondition = asString(lc.completionCondition?.body);
965
+ return {
966
+ loopType,
967
+ ...loopCardinality ? { loopCardinality } : {},
968
+ ...loopCompletionCondition ? { loopCompletionCondition } : {}
969
+ };
970
+ }
971
+ return {};
972
+ }
944
973
  function walkFlowElements(elements, parentId, ctx, nodes, edges) {
945
974
  for (const el of elements) {
946
975
  const { $type, id } = el;
@@ -958,7 +987,7 @@ function walkFlowElements(elements, parentId, ctx, nodes, edges) {
958
987
  }
959
988
  buildNode(el, elementType, parentId, ctx, nodes);
960
989
  if ($type === "bpmn:SubProcess" || $type === "bpmn:Transaction" || $type === "bpmn:AdHocSubProcess") {
961
- const children = asElements(el.flowElements);
990
+ const children = [...asElements(el.flowElements), ...asElements(el.artifacts)];
962
991
  const laneMembership = extractLaneMembership(el);
963
992
  walkFlowElements(children, id, { ...ctx, laneMembership }, nodes, edges);
964
993
  }
@@ -971,7 +1000,7 @@ function buildNode(el, elementType, parentId, ctx, nodes) {
971
1000
  const x = shape?.x ?? ctx.autoX.value;
972
1001
  const y = shape?.y ?? 100;
973
1002
  if (!shape) ctx.autoX.value += (meta?.defaultWidth ?? 120) + 20;
974
- const label = asString(el.name);
1003
+ const label = elementType === "Annotation" ? asString(el.text) ?? asString(el.name) : asString(el.name);
975
1004
  const documentation = extractDocumentation(el);
976
1005
  const trigger = extractTrigger(el);
977
1006
  const eventDefinition = extractEventDefinition(el);
@@ -982,6 +1011,8 @@ function buildNode(el, elementType, parentId, ctx, nodes) {
982
1011
  const scriptFormat = elementType === "ScriptTask" ? asString(el.scriptFormat) : void 0;
983
1012
  const script = elementType === "ScriptTask" ? asString(el.script) : void 0;
984
1013
  const completionCondition = elementType === "AdHocSubProcess" ? extractCompletionCondition(el) : void 0;
1014
+ const loopChars = extractLoopCharacteristics(el);
1015
+ const dataObjectRef = elementType === "DataObjectReference" ? asString(el.dataObjectRef?.id) : void 0;
985
1016
  const data = {
986
1017
  elementType,
987
1018
  ...label ? { label } : {},
@@ -1002,6 +1033,8 @@ function buildNode(el, elementType, parentId, ctx, nodes) {
1002
1033
  ...scriptFormat ? { scriptFormat } : {},
1003
1034
  ...script ? { script } : {},
1004
1035
  ...completionCondition ? { completionCondition } : {},
1036
+ ...dataObjectRef ? { dataObjectRef } : {},
1037
+ ...loopChars,
1005
1038
  ...aranzaExt
1006
1039
  };
1007
1040
  if (elementType === "SubProcess" || elementType === "Transaction" || elementType === "EventSubProcess" || elementType === "AdHocSubProcess") {
@@ -1034,11 +1067,14 @@ function buildEdge(el, edgeType, ctx, edges) {
1034
1067
  const label = asString(el.name);
1035
1068
  const documentation = extractDocumentation(el);
1036
1069
  const condExpr = el.conditionExpression;
1070
+ const rawDir = asString(el.associationDirection);
1071
+ const associationDirection = edgeType === "association" && rawDir ? rawDir.toLowerCase() : void 0;
1037
1072
  const data = {
1038
1073
  edgeType,
1039
1074
  ...label ? { label } : {},
1040
1075
  ...documentation ? { documentation } : {},
1041
- ...condExpr?.body ? { conditionExpression: condExpr.body } : {}
1076
+ ...condExpr?.body ? { conditionExpression: condExpr.body } : {},
1077
+ ...associationDirection ? { associationDirection } : {}
1042
1078
  };
1043
1079
  const waypoints = ctx.waypoints.get(id);
1044
1080
  if (waypoints?.length) data.routingPoints = waypoints;
@@ -1063,7 +1099,7 @@ function handleCollaboration(collaboration, ctx, nodes, edges) {
1063
1099
  if (processRef) {
1064
1100
  const laneMembership = extractLaneMembership(processRef);
1065
1101
  walkFlowElements(
1066
- asElements(processRef.flowElements),
1102
+ [...asElements(processRef.flowElements), ...asElements(processRef.artifacts)],
1067
1103
  id,
1068
1104
  { ...ctx, laneMembership },
1069
1105
  nodes,
@@ -1095,7 +1131,7 @@ function addLaneNodes(laneSet, poolId, ctx, nodes) {
1095
1131
  data: { elementType: "Lane", ...label ? { label } : {} },
1096
1132
  width: shape?.width ?? 570,
1097
1133
  height: shape?.height ?? 120,
1098
- parentId: poolId
1134
+ ...poolId ? { parentId: poolId } : {}
1099
1135
  });
1100
1136
  const child = lane.childLaneSet;
1101
1137
  if (child) addLaneNodes(child, poolId, ctx, nodes);
@@ -1129,9 +1165,9 @@ async function parseBpmnXml(xml) {
1129
1165
  } else if (rootEl.$type === "bpmn:Process") {
1130
1166
  const laneMembership = extractLaneMembership(rootEl);
1131
1167
  const laneSet = rootEl.laneSet;
1132
- if (laneSet) addLaneNodes(laneSet, "", ctx, nodes);
1168
+ if (laneSet) addLaneNodes(laneSet, void 0, ctx, nodes);
1133
1169
  walkFlowElements(
1134
- asElements(rootEl.flowElements),
1170
+ [...asElements(rootEl.flowElements), ...asElements(rootEl.artifacts)],
1135
1171
  void 0,
1136
1172
  { ...ctx, laneMembership },
1137
1173
  nodes,
@@ -1304,7 +1340,10 @@ function buildAranzaExtensionElements(moddle, node) {
1304
1340
  const formKey = typeof node.data.formKey === "string" ? node.data.formKey : void 0;
1305
1341
  const candidateUsers = typeof node.data.candidateUsers === "string" ? node.data.candidateUsers : void 0;
1306
1342
  const candidateGroups = typeof node.data.candidateGroups === "string" ? node.data.candidateGroups : void 0;
1307
- if (!priority && !owner && !sla && !connector && !action && !flowableType && !flowableDelegateExpression && !decisionRef && !formKey && !candidateUsers && !candidateGroups) {
1343
+ const dueDate = typeof node.data.dueDate === "string" ? node.data.dueDate : void 0;
1344
+ const skipExpression = typeof node.data.skipExpression === "string" ? node.data.skipExpression : void 0;
1345
+ const businessCalendarName = typeof node.data.businessCalendarName === "string" ? node.data.businessCalendarName : void 0;
1346
+ if (!priority && !owner && !sla && !connector && !action && !flowableType && !flowableDelegateExpression && !decisionRef && !formKey && !candidateUsers && !candidateGroups && !dueDate && !skipExpression && !businessCalendarName) {
1308
1347
  return null;
1309
1348
  }
1310
1349
  const configAttrs = {};
@@ -1319,9 +1358,13 @@ function buildAranzaExtensionElements(moddle, node) {
1319
1358
  if (formKey) configAttrs.formKey = formKey;
1320
1359
  if (candidateUsers) configAttrs.candidateUsers = candidateUsers;
1321
1360
  if (candidateGroups) configAttrs.candidateGroups = candidateGroups;
1361
+ if (dueDate) configAttrs.dueDate = dueDate;
1362
+ if (skipExpression) configAttrs.skipExpression = skipExpression;
1363
+ if (businessCalendarName) configAttrs.businessCalendarName = businessCalendarName;
1322
1364
  const taskConfig = moddle.create("aranza:TaskConfig", configAttrs);
1323
1365
  return moddle.create("bpmn:ExtensionElements", { values: [taskConfig] });
1324
1366
  }
1367
+ var ARTIFACT_ELEMENT_TYPES = /* @__PURE__ */ new Set(["Annotation", "Group"]);
1325
1368
  function buildSemanticModel(moddle, nodes, edges, opts) {
1326
1369
  const defId = opts.id ?? "Definitions_1";
1327
1370
  const defName = opts.name;
@@ -1417,10 +1460,31 @@ function buildProcess(moddle, allNodes, allEdges, poolId, laneNodes, processId,
1417
1460
  };
1418
1461
  const myNodes = (poolId ? allNodes.filter((n) => belongsToPool(n)) : allNodes.filter((n) => n.data.elementType !== "Pool" && n.data.elementType !== "Lane")).filter((n) => !isInsideSubProcess(n));
1419
1462
  const myLanes = laneNodes.filter((l) => poolId ? l.parentId === poolId : true);
1463
+ const presentDataObjectIds = new Set(
1464
+ myNodes.filter((n) => n.data.elementType === "DataObject").map((n) => n.id)
1465
+ );
1420
1466
  const flowElements = [];
1467
+ const artifacts = [];
1468
+ for (const node of myNodes) {
1469
+ if (node.data.elementType === "DataObjectReference") {
1470
+ const explicitRef = typeof node.data.dataObjectRef === "string" ? node.data.dataObjectRef : null;
1471
+ if (!explicitRef || !presentDataObjectIds.has(explicitRef)) {
1472
+ const syntheticId = `DataObject_${node.id}`;
1473
+ if (!presentDataObjectIds.has(syntheticId)) {
1474
+ flowElements.push(moddle.create("bpmn:DataObject", { id: syntheticId }));
1475
+ presentDataObjectIds.add(syntheticId);
1476
+ }
1477
+ }
1478
+ }
1479
+ }
1421
1480
  for (const node of myNodes) {
1422
1481
  const el = buildFlowElement(moddle, node, allNodes, allEdges);
1423
- if (el) flowElements.push(el);
1482
+ if (!el) continue;
1483
+ if (ARTIFACT_ELEMENT_TYPES.has(node.data.elementType)) {
1484
+ artifacts.push(el);
1485
+ } else {
1486
+ flowElements.push(el);
1487
+ }
1424
1488
  }
1425
1489
  const myNodeIds = new Set(myNodes.map((n) => n.id));
1426
1490
  const myEdges = allEdges.filter(
@@ -1428,7 +1492,12 @@ function buildProcess(moddle, allNodes, allEdges, poolId, laneNodes, processId,
1428
1492
  );
1429
1493
  for (const edge of myEdges) {
1430
1494
  const edgeMeta = buildEdgeElement(moddle, edge);
1431
- if (edgeMeta) flowElements.push(edgeMeta);
1495
+ if (!edgeMeta) continue;
1496
+ if (edge.data?.edgeType === "association") {
1497
+ artifacts.push(edgeMeta);
1498
+ } else {
1499
+ flowElements.push(edgeMeta);
1500
+ }
1432
1501
  }
1433
1502
  const elementById = new Map(
1434
1503
  flowElements.filter((element) => typeof element.id === "string").map((element) => [element.id, element])
@@ -1444,7 +1513,8 @@ function buildProcess(moddle, allNodes, allEdges, poolId, laneNodes, processId,
1444
1513
  const process = moddle.create("bpmn:Process", {
1445
1514
  id: processId,
1446
1515
  isExecutable: opts.process?.executable ?? true,
1447
- flowElements
1516
+ flowElements,
1517
+ ...artifacts.length > 0 ? { artifacts } : {}
1448
1518
  });
1449
1519
  if (opts.process?.documentation) {
1450
1520
  process.documentation = [
@@ -1476,6 +1546,10 @@ function buildFlowElement(moddle, node, allNodes, allEdges) {
1476
1546
  id: node.id,
1477
1547
  name: label ?? ""
1478
1548
  };
1549
+ if (elementType === "Annotation") {
1550
+ delete attrs.name;
1551
+ attrs.text = label ?? "";
1552
+ }
1479
1553
  if (node.data.documentation) {
1480
1554
  attrs.documentation = [
1481
1555
  moddle.create("bpmn:Documentation", { text: node.data.documentation })
@@ -1494,22 +1568,16 @@ function buildFlowElement(moddle, node, allNodes, allEdges) {
1494
1568
  if (elementType === "CallActivity" && node.data.calledElement) {
1495
1569
  attrs.calledElement = node.data.calledElement;
1496
1570
  }
1571
+ if (elementType === "DataObjectReference") {
1572
+ const refId = typeof node.data.dataObjectRef === "string" ? node.data.dataObjectRef : `DataObject_${node.id}`;
1573
+ attrs.dataObjectRef = { id: refId };
1574
+ }
1497
1575
  if (elementType === "ScriptTask") {
1498
1576
  const scriptFormat = typeof node.data.scriptFormat === "string" ? node.data.scriptFormat : void 0;
1499
1577
  const script = typeof node.data.script === "string" ? node.data.script : void 0;
1500
1578
  if (scriptFormat) attrs.scriptFormat = scriptFormat;
1501
1579
  if (script) attrs.script = script;
1502
1580
  }
1503
- if (elementType === "UserTask") {
1504
- const flowableAttrs = {};
1505
- const fk = typeof node.data.formKey === "string" ? node.data.formKey : void 0;
1506
- const cu = typeof node.data.candidateUsers === "string" ? node.data.candidateUsers : void 0;
1507
- const cg = typeof node.data.candidateGroups === "string" ? node.data.candidateGroups : void 0;
1508
- if (fk) flowableAttrs["flowable:formKey"] = fk;
1509
- if (cu) flowableAttrs["flowable:candidateUsers"] = cu;
1510
- if (cg) flowableAttrs["flowable:candidateGroups"] = cg;
1511
- if (Object.keys(flowableAttrs).length > 0) attrs.$attrs = flowableAttrs;
1512
- }
1513
1581
  if (elementType === "ServiceTask") {
1514
1582
  const flowableAttrs = {};
1515
1583
  const flowableType = typeof node.data.flowableType === "string" ? node.data.flowableType : void 0;
@@ -1526,7 +1594,9 @@ function buildFlowElement(moddle, node, allNodes, allEdges) {
1526
1594
  if (aranzaConfig) attrs.extensionElements = aranzaConfig;
1527
1595
  const isSubProcess = elementType === "SubProcess" || elementType === "Transaction" || elementType === "EventSubProcess" || elementType === "AdHocSubProcess";
1528
1596
  if (isSubProcess) {
1529
- attrs.flowElements = buildNestedFlowElements(moddle, node, allNodes, allEdges);
1597
+ const nested = buildNestedFlowElements(moddle, node, allNodes, allEdges);
1598
+ attrs.flowElements = nested.flowElements;
1599
+ if (nested.artifacts.length > 0) attrs.artifacts = nested.artifacts;
1530
1600
  if (elementType === "EventSubProcess" || node.data.subProcessVariant === "event") {
1531
1601
  attrs.triggeredByEvent = true;
1532
1602
  }
@@ -1536,6 +1606,29 @@ function buildFlowElement(moddle, node, allNodes, allEdges) {
1536
1606
  });
1537
1607
  }
1538
1608
  }
1609
+ const loopType = typeof node.data.loopType === "string" ? node.data.loopType : "none";
1610
+ if (loopType && loopType !== "none") {
1611
+ if (loopType === "loop") {
1612
+ const lcAttrs = { id: uid("LoopChar", node.id) };
1613
+ const loopCondition = typeof node.data.loopCondition === "string" ? node.data.loopCondition : void 0;
1614
+ if (loopCondition) {
1615
+ lcAttrs.loopCondition = moddle.create("bpmn:FormalExpression", { body: loopCondition });
1616
+ }
1617
+ attrs.loopCharacteristics = moddle.create("bpmn:StandardLoopCharacteristics", lcAttrs);
1618
+ } else {
1619
+ const isSequential = loopType === "sequentialMultiple";
1620
+ const lcAttrs = { id: uid("LoopChar", node.id), isSequential };
1621
+ const loopCardinality = typeof node.data.loopCardinality === "string" ? node.data.loopCardinality : void 0;
1622
+ const loopCompletionCondition = typeof node.data.loopCompletionCondition === "string" ? node.data.loopCompletionCondition : void 0;
1623
+ if (loopCardinality) {
1624
+ lcAttrs.loopCardinality = moddle.create("bpmn:FormalExpression", { body: loopCardinality });
1625
+ }
1626
+ if (loopCompletionCondition) {
1627
+ lcAttrs.completionCondition = moddle.create("bpmn:FormalExpression", { body: loopCompletionCondition });
1628
+ }
1629
+ attrs.loopCharacteristics = moddle.create("bpmn:MultiInstanceLoopCharacteristics", lcAttrs);
1630
+ }
1631
+ }
1539
1632
  const element = moddle.create(moddleType, attrs);
1540
1633
  return element;
1541
1634
  }
@@ -1543,16 +1636,42 @@ function buildNestedFlowElements(moddle, parent, allNodes, allEdges) {
1543
1636
  const childNodes = allNodes.filter((node) => node.parentId === parent.id);
1544
1637
  const childNodeIds = new Set(childNodes.map((node) => node.id));
1545
1638
  const flowElements = [];
1639
+ const artifacts = [];
1640
+ const presentDataObjectIds = new Set(
1641
+ childNodes.filter((n) => n.data.elementType === "DataObject").map((n) => n.id)
1642
+ );
1643
+ for (const node of childNodes) {
1644
+ if (node.data.elementType === "DataObjectReference") {
1645
+ const explicitRef = typeof node.data.dataObjectRef === "string" ? node.data.dataObjectRef : null;
1646
+ if (!explicitRef || !presentDataObjectIds.has(explicitRef)) {
1647
+ const syntheticId = `DataObject_${node.id}`;
1648
+ if (!presentDataObjectIds.has(syntheticId)) {
1649
+ flowElements.push(moddle.create("bpmn:DataObject", { id: syntheticId }));
1650
+ presentDataObjectIds.add(syntheticId);
1651
+ }
1652
+ }
1653
+ }
1654
+ }
1546
1655
  for (const child of childNodes) {
1547
1656
  const element = buildFlowElement(moddle, child, allNodes, allEdges);
1548
- if (element) flowElements.push(element);
1657
+ if (!element) continue;
1658
+ if (ARTIFACT_ELEMENT_TYPES.has(child.data.elementType)) {
1659
+ artifacts.push(element);
1660
+ } else {
1661
+ flowElements.push(element);
1662
+ }
1549
1663
  }
1550
1664
  for (const edge of allEdges) {
1551
1665
  if (!childNodeIds.has(edge.source) || !childNodeIds.has(edge.target)) continue;
1552
1666
  const element = buildEdgeElement(moddle, edge);
1553
- if (element) flowElements.push(element);
1667
+ if (!element) continue;
1668
+ if (edge.data?.edgeType === "association") {
1669
+ artifacts.push(element);
1670
+ } else {
1671
+ flowElements.push(element);
1672
+ }
1554
1673
  }
1555
- return flowElements;
1674
+ return { flowElements, artifacts };
1556
1675
  }
1557
1676
  function buildEdgeElement(moddle, edge) {
1558
1677
  if (!edge.data) return null;
@@ -1574,6 +1693,9 @@ function buildEdgeElement(moddle, edge) {
1574
1693
  body: edge.data.conditionExpression
1575
1694
  });
1576
1695
  }
1696
+ if (edge.data.edgeType === "association" && edge.data.associationDirection && edge.data.associationDirection !== "none") {
1697
+ attrs.associationDirection = edge.data.associationDirection === "both" ? "Both" : "One";
1698
+ }
1577
1699
  return moddle.create(moddleType, attrs);
1578
1700
  }
1579
1701
  function buildBpmnDI(moddle, definitions, nodes, edges) {