@bpmnkit/core 0.1.1 → 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 (83) hide show
  1. package/README.md +32 -1
  2. package/dist/bpmn/agentic.d.ts +121 -0
  3. package/dist/bpmn/agentic.js +97 -0
  4. package/dist/bpmn/auto-layout.d.ts +5 -5
  5. package/dist/bpmn/auto-layout.js +592 -36
  6. package/dist/bpmn/bpmn-builder.d.ts +265 -3
  7. package/dist/bpmn/bpmn-builder.js +603 -197
  8. package/dist/bpmn/bpmn-model.d.ts +114 -0
  9. package/dist/bpmn/bpmn-parser.js +1414 -521
  10. package/dist/bpmn/bpmn-serializer.js +107 -19
  11. package/dist/bpmn/compact.d.ts +17 -2
  12. package/dist/bpmn/compact.js +3 -3
  13. package/dist/bpmn/full-operations.d.ts +89 -0
  14. package/dist/bpmn/full-operations.js +478 -0
  15. package/dist/bpmn/index.d.ts +19 -0
  16. package/dist/bpmn/index.js +21 -0
  17. package/dist/bpmn/optimize/agentic.d.ts +10 -0
  18. package/dist/bpmn/optimize/agentic.js +88 -0
  19. package/dist/bpmn/optimize/deploy.d.ts +16 -0
  20. package/dist/bpmn/optimize/deploy.js +143 -0
  21. package/dist/bpmn/optimize/feel-syntax.d.ts +12 -0
  22. package/dist/bpmn/optimize/feel-syntax.js +87 -0
  23. package/dist/bpmn/optimize/feel.js +7 -4
  24. package/dist/bpmn/optimize/flow.js +22 -2
  25. package/dist/bpmn/optimize/index.js +20 -9
  26. package/dist/bpmn/optimize/patterns.js +23 -16
  27. package/dist/bpmn/optimize/tasks.js +30 -7
  28. package/dist/bpmn/optimize/types.d.ts +10 -1
  29. package/dist/bpmn/optimize/utils.js +2 -4
  30. package/dist/bpmn/optimize/variable-flow.js +58 -67
  31. package/dist/bpmn/semantic-hash.d.ts +93 -0
  32. package/dist/bpmn/semantic-hash.js +155 -0
  33. package/dist/bpmn/sha256.d.ts +17 -0
  34. package/dist/bpmn/sha256.js +95 -0
  35. package/dist/bpmn/zeebe-extensions.d.ts +83 -0
  36. package/dist/bpmn/zeebe-extensions.js +117 -0
  37. package/dist/bpmn/zeebe-placement.d.ts +12 -0
  38. package/dist/bpmn/zeebe-placement.js +140 -0
  39. package/dist/errors.d.ts +40 -1
  40. package/dist/errors.js +41 -0
  41. package/dist/index.d.ts +16 -5
  42. package/dist/index.js +9 -3
  43. package/dist/layout/annotations.js +36 -1
  44. package/dist/layout/collaboration/alignment.d.ts +26 -0
  45. package/dist/layout/collaboration/alignment.js +66 -0
  46. package/dist/layout/collaboration/ordering.d.ts +21 -0
  47. package/dist/layout/collaboration/ordering.js +102 -0
  48. package/dist/layout/index.d.ts +1 -0
  49. package/dist/layout/layout-engine.d.ts +13 -3
  50. package/dist/layout/layout-engine.js +9 -4
  51. package/dist/layout/semantic/bands.d.ts +19 -0
  52. package/dist/layout/semantic/bands.js +324 -0
  53. package/dist/layout/semantic/graph.d.ts +37 -0
  54. package/dist/layout/semantic/graph.js +242 -0
  55. package/dist/layout/semantic/index.d.ts +13 -0
  56. package/dist/layout/semantic/index.js +181 -0
  57. package/dist/layout/semantic/place.d.ts +40 -0
  58. package/dist/layout/semantic/place.js +271 -0
  59. package/dist/layout/semantic/route.d.ts +14 -0
  60. package/dist/layout/semantic/route.js +514 -0
  61. package/dist/layout/types.d.ts +17 -0
  62. package/dist/node/index.d.ts +10 -0
  63. package/dist/node/index.js +9 -0
  64. package/dist/node/write.d.ts +81 -0
  65. package/dist/node/write.js +167 -0
  66. package/dist/plan/compile.d.ts +39 -0
  67. package/dist/plan/compile.js +380 -0
  68. package/dist/plan/extract.d.ts +31 -0
  69. package/dist/plan/extract.js +248 -0
  70. package/dist/plan/index.d.ts +6 -0
  71. package/dist/plan/index.js +5 -0
  72. package/dist/plan/merge.d.ts +13 -0
  73. package/dist/plan/merge.js +80 -0
  74. package/dist/plan/slug.d.ts +5 -0
  75. package/dist/plan/slug.js +22 -0
  76. package/dist/plan/types.d.ts +225 -0
  77. package/dist/plan/types.js +13 -0
  78. package/dist/types/id-generator.js +11 -3
  79. package/dist/xml/index.d.ts +3 -1
  80. package/dist/xml/index.js +2 -1
  81. package/dist/xml/xml-parser.d.ts +32 -0
  82. package/dist/xml/xml-parser.js +394 -143
  83. package/package.json +9 -2
@@ -0,0 +1,242 @@
1
+ /** Flow-node types that end a path — used to score candidate spine edges. */
2
+ const END_TYPES = new Set(["endEvent"]);
3
+ /**
4
+ * The node a flow leaves from for layout purposes. A flow out of a boundary
5
+ * event belongs to the host's position, not the event's.
6
+ */
7
+ function effectiveSource(flow, byId) {
8
+ const source = byId.get(flow.sourceRef);
9
+ if (source?.type === "boundaryEvent")
10
+ return source.attachedToRef;
11
+ return flow.sourceRef;
12
+ }
13
+ export function buildSemanticGraph(flowElements, sequenceFlows) {
14
+ const byId = new Map();
15
+ for (const el of flowElements)
16
+ byId.set(el.id, el);
17
+ const nodes = [];
18
+ const attachers = new Map();
19
+ for (const el of flowElements) {
20
+ if (el.type === "boundaryEvent") {
21
+ const be = el;
22
+ const list = attachers.get(be.attachedToRef);
23
+ if (list)
24
+ list.push(be);
25
+ else
26
+ attachers.set(be.attachedToRef, [be]);
27
+ }
28
+ else {
29
+ nodes.push(el);
30
+ }
31
+ }
32
+ const outgoing = new Map();
33
+ const incoming = new Map();
34
+ for (const flow of sequenceFlows) {
35
+ const from = effectiveSource(flow, byId);
36
+ if (!byId.has(from) || !byId.has(flow.targetRef))
37
+ continue;
38
+ const out = outgoing.get(from);
39
+ if (out)
40
+ out.push(flow);
41
+ else
42
+ outgoing.set(from, [flow]);
43
+ const inc = incoming.get(flow.targetRef);
44
+ if (inc)
45
+ inc.push(flow);
46
+ else
47
+ incoming.set(flow.targetRef, [flow]);
48
+ }
49
+ const graph = {
50
+ nodes,
51
+ byId,
52
+ outgoing,
53
+ incoming,
54
+ attachers,
55
+ backEdges: new Set(),
56
+ components: [],
57
+ starts: [],
58
+ ranks: new Map(),
59
+ };
60
+ findComponents(graph);
61
+ markBackEdges(graph);
62
+ assignRanks(graph);
63
+ return graph;
64
+ }
65
+ /** Weakly connected components, discovered in declaration order. */
66
+ function findComponents(graph) {
67
+ const seen = new Set();
68
+ for (const node of graph.nodes) {
69
+ if (seen.has(node.id))
70
+ continue;
71
+ const members = [];
72
+ const stack = [node.id];
73
+ while (stack.length > 0) {
74
+ const id = stack.pop();
75
+ if (id === undefined || seen.has(id))
76
+ continue;
77
+ seen.add(id);
78
+ members.push(id);
79
+ for (const f of graph.outgoing.get(id) ?? [])
80
+ stack.push(f.targetRef);
81
+ for (const f of graph.incoming.get(id) ?? [])
82
+ stack.push(effectiveSource(f, graph.byId));
83
+ }
84
+ // Declaration order within the component keeps ties deterministic.
85
+ const order = new Map(graph.nodes.map((n, i) => [n.id, i]));
86
+ members.sort((a, b) => (order.get(a) ?? 0) - (order.get(b) ?? 0));
87
+ graph.components.push(members);
88
+ graph.starts.push(pickStart(members, graph));
89
+ }
90
+ }
91
+ /**
92
+ * A component starts at its earliest declared start event, else its earliest
93
+ * node with no incoming flow, else its earliest declared node.
94
+ */
95
+ function pickStart(members, graph) {
96
+ const startEvent = members.find((id) => graph.byId.get(id)?.type === "startEvent");
97
+ if (startEvent)
98
+ return startEvent;
99
+ const source = members.find((id) => (graph.incoming.get(id) ?? []).length === 0);
100
+ return source ?? members[0] ?? "";
101
+ }
102
+ /**
103
+ * Depth-first from each semantic start; an edge onto a node already on the
104
+ * traversal stack closes a cycle and is excluded from ranking.
105
+ */
106
+ function markBackEdges(graph) {
107
+ const state = new Map();
108
+ const visit = (id) => {
109
+ state.set(id, "open");
110
+ for (const flow of graph.outgoing.get(id) ?? []) {
111
+ const target = flow.targetRef;
112
+ const targetState = state.get(target);
113
+ if (targetState === "open")
114
+ graph.backEdges.add(flow.id);
115
+ else if (targetState === undefined)
116
+ visit(target);
117
+ }
118
+ state.set(id, "done");
119
+ };
120
+ for (const start of graph.starts)
121
+ if (start && !state.has(start))
122
+ visit(start);
123
+ // Nodes only reachable through a cycle still need a traversal root.
124
+ for (const node of graph.nodes)
125
+ if (!state.has(node.id))
126
+ visit(node.id);
127
+ }
128
+ const GATEWAY_TYPES = new Set([
129
+ "exclusiveGateway",
130
+ "parallelGateway",
131
+ "inclusiveGateway",
132
+ "eventBasedGateway",
133
+ "complexGateway",
134
+ ]);
135
+ /** True when a node merges more than one path. */
136
+ function isJoin(graph, id) {
137
+ return (graph.incoming.get(id) ?? []).length > 1;
138
+ }
139
+ /**
140
+ * Nested joins of one gateway type may share a rank and connect vertically —
141
+ * closing an inner branch and the branch around it is one moment in the flow,
142
+ * not two. Joins of different types keep their forward step, because the change
143
+ * of gateway is itself part of the story.
144
+ */
145
+ function sharesRank(graph, flow) {
146
+ const source = graph.byId.get(flow.sourceRef);
147
+ const target = graph.byId.get(flow.targetRef);
148
+ if (!source || !target)
149
+ return false;
150
+ if (source.type !== target.type || !GATEWAY_TYPES.has(source.type))
151
+ return false;
152
+ return isJoin(graph, source.id) && isJoin(graph, target.id);
153
+ }
154
+ /**
155
+ * Longest-path ranks over the acyclic remainder, then a bounded fixed point so
156
+ * a boundary handler never precedes the activity it is attached to.
157
+ */
158
+ function assignRanks(graph) {
159
+ const { ranks } = graph;
160
+ for (const node of graph.nodes)
161
+ ranks.set(node.id, 0);
162
+ const forward = (id) => (graph.outgoing.get(id) ?? []).filter((f) => !graph.backEdges.has(f.id));
163
+ // Longest path: relax every edge until no rank grows. |V| passes suffice
164
+ // because the remaining graph is acyclic.
165
+ for (let pass = 0; pass < graph.nodes.length + 1; pass++) {
166
+ let changed = false;
167
+ for (const node of graph.nodes) {
168
+ const rank = ranks.get(node.id) ?? 0;
169
+ for (const flow of forward(node.id)) {
170
+ const step = sharesRank(graph, flow) ? 0 : 1;
171
+ const target = ranks.get(flow.targetRef) ?? 0;
172
+ if (target < rank + step) {
173
+ ranks.set(flow.targetRef, rank + step);
174
+ changed = true;
175
+ }
176
+ }
177
+ }
178
+ if (!changed)
179
+ break;
180
+ }
181
+ // Normalize each component so its start sits at rank 0.
182
+ for (let i = 0; i < graph.components.length; i++) {
183
+ const members = graph.components[i];
184
+ if (!members)
185
+ continue;
186
+ let min = Number.POSITIVE_INFINITY;
187
+ for (const id of members)
188
+ min = Math.min(min, ranks.get(id) ?? 0);
189
+ if (min === 0 || !Number.isFinite(min))
190
+ continue;
191
+ for (const id of members)
192
+ ranks.set(id, (ranks.get(id) ?? 0) - min);
193
+ }
194
+ }
195
+ /**
196
+ * True when an end event is reachable from `id` without traversing a back edge.
197
+ * A node other than `id` itself that has no outgoing flow also ends the path.
198
+ *
199
+ * The reverse reachability set is computed once per graph, so repeated calls
200
+ * from the spine tracer stay O(1) instead of re-walking the graph each time.
201
+ */
202
+ export function reachesEnd(graph, id) {
203
+ const node = graph.byId.get(id);
204
+ if (node && END_TYPES.has(node.type))
205
+ return true;
206
+ const endReach = graph.endReach ?? buildEndReach(graph);
207
+ for (const flow of graph.outgoing.get(id) ?? []) {
208
+ if (!graph.backEdges.has(flow.id) && endReach.has(flow.targetRef))
209
+ return true;
210
+ }
211
+ return false;
212
+ }
213
+ /**
214
+ * Every node from which a path along non-back edges reaches an end event or a
215
+ * node with no outgoing flow (both inclusive), found by one reverse walk.
216
+ */
217
+ function buildEndReach(graph) {
218
+ const reach = new Set();
219
+ const stack = [];
220
+ for (const node of graph.byId.values()) {
221
+ const out = graph.outgoing.get(node.id);
222
+ if (END_TYPES.has(node.type) || out === undefined || out.length === 0) {
223
+ reach.add(node.id);
224
+ stack.push(node.id);
225
+ }
226
+ }
227
+ while (stack.length > 0) {
228
+ const id = stack.pop();
229
+ for (const flow of graph.incoming.get(id) ?? []) {
230
+ if (graph.backEdges.has(flow.id))
231
+ continue;
232
+ const from = effectiveSource(flow, graph.byId);
233
+ if (!reach.has(from)) {
234
+ reach.add(from);
235
+ stack.push(from);
236
+ }
237
+ }
238
+ }
239
+ graph.endReach = reach;
240
+ return reach;
241
+ }
242
+ //# sourceMappingURL=graph.js.map
@@ -0,0 +1,13 @@
1
+ import type { BpmnFlowElement, BpmnLaneSet, BpmnProcess, BpmnSequenceFlow } from "../../bpmn/bpmn-model.js";
2
+ import type { LayoutResult } from "../types.js";
3
+ /**
4
+ * Lay out a process the way the BPMN reads: ranks carry the flow left to right,
5
+ * semantic bands carry branch meaning up and down, and lane membership wins over
6
+ * both.
7
+ */
8
+ export declare function semanticLayoutProcess(process: BpmnProcess, collapsed?: ReadonlySet<string>): LayoutResult;
9
+ export declare function semanticLayout(flowElements: BpmnFlowElement[], sequenceFlows: BpmnSequenceFlow[], laneSet?: BpmnLaneSet,
10
+ /** Sub-processes drawn collapsed: their contents go on a plane of their own. */
11
+ collapsed?: ReadonlySet<string>): LayoutResult;
12
+ export type { Placement } from "./place.js";
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,181 @@
1
+ import { placeEdgeLabels } from "../grid/edge-labels.js";
2
+ import { LABEL_CHAR_WIDTH, LABEL_HEIGHT, LABEL_MIN_WIDTH, SUBPROCESS_PADDING } from "../types.js";
3
+ import { assignBands } from "./bands.js";
4
+ import { buildSemanticGraph } from "./graph.js";
5
+ import { place, sizeOf } from "./place.js";
6
+ import { routeFlows } from "./route.js";
7
+ /** Padding between an expanded sub-process border and its children. */
8
+ const SUB_PADDING = SUBPROCESS_PADDING;
9
+ /** Extra top padding inside a named expanded sub-process, for its title. */
10
+ const TITLE_BAND = 28;
11
+ /** Gap between an event or gateway and its external label. */
12
+ const LABEL_OFFSET = 4;
13
+ const CONTAINER_TYPES = new Set(["subProcess", "adHocSubProcess", "eventSubProcess", "transaction"]);
14
+ const EXTERNAL_LABEL_TYPES = new Set([
15
+ "startEvent",
16
+ "endEvent",
17
+ "intermediateThrowEvent",
18
+ "intermediateCatchEvent",
19
+ "boundaryEvent",
20
+ "exclusiveGateway",
21
+ "parallelGateway",
22
+ "inclusiveGateway",
23
+ "eventBasedGateway",
24
+ "complexGateway",
25
+ ]);
26
+ /**
27
+ * Lay out a process the way the BPMN reads: ranks carry the flow left to right,
28
+ * semantic bands carry branch meaning up and down, and lane membership wins over
29
+ * both.
30
+ */
31
+ export function semanticLayoutProcess(process, collapsed) {
32
+ return semanticLayout(process.flowElements, process.sequenceFlows, process.laneSet, collapsed);
33
+ }
34
+ export function semanticLayout(flowElements, sequenceFlows, laneSet,
35
+ /** Sub-processes drawn collapsed: their contents go on a plane of their own. */
36
+ collapsed = new Set()) {
37
+ if (flowElements.length === 0)
38
+ return { nodes: [], edges: [] };
39
+ const graph = buildSemanticGraph(flowElements, sequenceFlows);
40
+ const bandLayout = assignBands(graph);
41
+ // Children first: an expanded sub-process is sized by what it contains, while
42
+ // a collapsed one stays activity-sized and its contents move to their own plane.
43
+ const childResults = new Map();
44
+ const planes = [];
45
+ const sizes = new Map();
46
+ for (const el of graph.nodes) {
47
+ const child = childLayoutOf(el, collapsed);
48
+ if (!child) {
49
+ sizes.set(el.id, sizeOf(el));
50
+ continue;
51
+ }
52
+ if (collapsed.has(el.id)) {
53
+ planes.push({ elementId: el.id, result: child.result });
54
+ planes.push(...(child.result.planes ?? []));
55
+ sizes.set(el.id, sizeOf(el));
56
+ }
57
+ else {
58
+ childResults.set(el.id, child.result);
59
+ planes.push(...(child.result.planes ?? []));
60
+ sizes.set(el.id, child.size);
61
+ }
62
+ }
63
+ const { bounds, lanes, gutterX } = place(graph, bandLayout, sizes, laneSet);
64
+ const nodes = [];
65
+ for (const el of flowElements) {
66
+ const b = bounds.get(el.id);
67
+ if (!b)
68
+ continue;
69
+ const node = {
70
+ id: el.id,
71
+ type: el.type,
72
+ bounds: b,
73
+ layer: graph.ranks.get(el.id) ?? 0,
74
+ position: bandLayout.bands.get(el.id) ?? 0,
75
+ gridRow: bandLayout.bands.get(el.id) ?? 0,
76
+ };
77
+ if (el.name) {
78
+ node.label = el.name;
79
+ const labelBounds = externalLabel(el.type, el.name, b);
80
+ if (labelBounds)
81
+ node.labelBounds = labelBounds;
82
+ }
83
+ if (childResults.has(el.id))
84
+ node.isExpanded = true;
85
+ else if (collapsed.has(el.id))
86
+ node.isExpanded = false;
87
+ nodes.push(node);
88
+ }
89
+ const edges = routeFlows(graph, sequenceFlows, bounds, bandLayout, gutterX);
90
+ // Drop the children in, translated into their parent's interior.
91
+ for (const [parentId, child] of childResults) {
92
+ const parent = bounds.get(parentId);
93
+ if (!parent)
94
+ continue;
95
+ const extent = extentOf(child);
96
+ if (!extent)
97
+ continue;
98
+ const named = graph.byId.get(parentId)?.name !== undefined;
99
+ const dx = parent.x + SUB_PADDING - extent.x;
100
+ const dy = parent.y + SUB_PADDING + (named ? TITLE_BAND : 0) - extent.y;
101
+ for (const node of child.nodes) {
102
+ node.bounds = shift(node.bounds, dx, dy);
103
+ if (node.labelBounds)
104
+ node.labelBounds = shift(node.labelBounds, dx, dy);
105
+ nodes.push(node);
106
+ }
107
+ for (const edge of child.edges) {
108
+ edge.waypoints = edge.waypoints.map((wp) => ({ x: wp.x + dx, y: wp.y + dy }));
109
+ if (edge.labelBounds)
110
+ edge.labelBounds = shift(edge.labelBounds, dx, dy);
111
+ edges.push(edge);
112
+ }
113
+ }
114
+ const result = { nodes, edges };
115
+ if (lanes.length > 0)
116
+ result.lanes = lanes;
117
+ if (planes.length > 0)
118
+ result.planes = planes;
119
+ placeEdgeLabels(edges, new Map(nodes.map((n) => [n.id, n])));
120
+ return result;
121
+ }
122
+ /** Lay out a container's children and report the size its border needs. */
123
+ function childLayoutOf(el, collapsed) {
124
+ if (!CONTAINER_TYPES.has(el.type))
125
+ return null;
126
+ const container = el;
127
+ if (!container.flowElements || container.flowElements.length === 0)
128
+ return null;
129
+ const result = semanticLayout(container.flowElements, container.sequenceFlows ?? [], container.laneSet, collapsed);
130
+ const extent = extentOf(result);
131
+ if (!extent)
132
+ return null;
133
+ const titleBand = el.name !== undefined ? TITLE_BAND : 0;
134
+ return {
135
+ result,
136
+ size: {
137
+ width: extent.width + 2 * SUB_PADDING,
138
+ height: extent.height + 2 * SUB_PADDING + titleBand,
139
+ },
140
+ };
141
+ }
142
+ function extentOf(result) {
143
+ let minX = Number.POSITIVE_INFINITY;
144
+ let minY = Number.POSITIVE_INFINITY;
145
+ let maxX = Number.NEGATIVE_INFINITY;
146
+ let maxY = Number.NEGATIVE_INFINITY;
147
+ const consider = (b) => {
148
+ minX = Math.min(minX, b.x);
149
+ minY = Math.min(minY, b.y);
150
+ maxX = Math.max(maxX, b.x + b.width);
151
+ maxY = Math.max(maxY, b.y + b.height);
152
+ };
153
+ for (const node of result.nodes) {
154
+ consider(node.bounds);
155
+ if (node.labelBounds)
156
+ consider(node.labelBounds);
157
+ }
158
+ for (const edge of result.edges) {
159
+ for (const wp of edge.waypoints)
160
+ consider({ x: wp.x, y: wp.y, width: 0, height: 0 });
161
+ }
162
+ if (!Number.isFinite(minX))
163
+ return null;
164
+ return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
165
+ }
166
+ function shift(b, dx, dy) {
167
+ return { x: b.x + dx, y: b.y + dy, width: b.width, height: b.height };
168
+ }
169
+ /** Events and gateways carry their name outside the shape; activities do not. */
170
+ function externalLabel(type, name, bounds) {
171
+ if (!EXTERNAL_LABEL_TYPES.has(type))
172
+ return undefined;
173
+ const width = Math.max(name.length * LABEL_CHAR_WIDTH, LABEL_MIN_WIDTH);
174
+ return {
175
+ x: bounds.x + bounds.width / 2 - width / 2,
176
+ y: bounds.y + bounds.height + LABEL_OFFSET,
177
+ width,
178
+ height: LABEL_HEIGHT,
179
+ };
180
+ }
181
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,40 @@
1
+ import type { BpmnFlowElement, BpmnLaneSet } from "../../bpmn/bpmn-model.js";
2
+ import type { Bounds } from "../types.js";
3
+ import type { BandLayout } from "./bands.js";
4
+ import type { SemanticGraph } from "./graph.js";
5
+ /** Geometry constants. Layout may add space beyond these; it never takes any back. */
6
+ export declare const H_GAP = 100;
7
+ export declare const V_GAP = 80;
8
+ export declare const COMPONENT_GAP = 80;
9
+ export declare const LANE_PADDING = 40;
10
+ export declare const BOUNDARY_SIZE = 36;
11
+ export interface Placement {
12
+ /** Absolute bounds per flow node, boundary events included. */
13
+ bounds: Map<string, Bounds>;
14
+ /** Lane bands in top-to-bottom order, empty when the scope has no lanes. */
15
+ lanes: Array<{
16
+ id: string;
17
+ bounds: Bounds;
18
+ }>;
19
+ /**
20
+ * Mid-x of the empty gutter in front of each rank. Vertical runs belong
21
+ * here: placement never puts a shape in a gutter, so these lines are clear.
22
+ */
23
+ gutterX: Map<number, number>;
24
+ }
25
+ export declare function sizeOf(el: BpmnFlowElement, childExtent?: Bounds): {
26
+ width: number;
27
+ height: number;
28
+ };
29
+ /**
30
+ * Turn ranks and bands into coordinates.
31
+ *
32
+ * Ranks become columns sized by their widest node, bands become rows sized by
33
+ * their tallest. Nodes are centred in both, so any two nodes sharing a band
34
+ * share a centre line and the spine routes as one straight segment.
35
+ */
36
+ export declare function place(graph: SemanticGraph, bandLayout: BandLayout, sizes: Map<string, {
37
+ width: number;
38
+ height: number;
39
+ }>, laneSet: BpmnLaneSet | undefined): Placement;
40
+ //# sourceMappingURL=place.d.ts.map