@bpmnkit/core 0.0.21 → 0.0.23

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.
package/README.md CHANGED
@@ -186,6 +186,7 @@ const outXml = Bpmn.export(restored)
186
186
  | [`@bpmnkit/cli`](https://www.npmjs.com/package/@bpmnkit/cli) | Camunda 8 command-line interface (casen) |
187
187
  | [`@bpmnkit/proxy`](https://www.npmjs.com/package/@bpmnkit/proxy) | Local AI bridge and Camunda API proxy server |
188
188
  | [`@bpmnkit/patterns`](https://www.npmjs.com/package/@bpmnkit/patterns) | Domain process patterns for BPMNKit AIKit |
189
+ | [`@bpmnkit/reebe-wasm`](https://www.npmjs.com/package/@bpmnkit/reebe-wasm) | WebAssembly BPMN engine for browser simulation |
189
190
  | [`@bpmnkit/worker-client`](https://www.npmjs.com/package/@bpmnkit/worker-client) | Thin Zeebe REST client for standalone workers |
190
191
  | [`@bpmnkit/cli-sdk`](https://www.npmjs.com/package/@bpmnkit/cli-sdk) | Plugin authoring SDK for the casen CLI |
191
192
  | [`@bpmnkit/create-casen-plugin`](https://www.npmjs.com/package/@bpmnkit/create-casen-plugin) | Scaffold a new casen CLI plugin in seconds |
@@ -1,9 +1,140 @@
1
1
  import { layoutProcess } from "../layout/layout-engine.js";
2
+ import { resolveEdgeCrossings } from "../layout/routing.js";
2
3
  const POOL_HEADER = 30;
3
4
  const LANE_HEADER = 30;
4
5
  const PADDING = 20;
5
6
  const POOL_GAP = 30;
6
- function contentBbox(nodes) {
7
+ const CHAIN_GAP = 30;
8
+ const CHAIN_V_GAP = 20;
9
+ const ANN_H = 50;
10
+ const ANN_GAP = 60;
11
+ const ANN_PADDING = 20;
12
+ /**
13
+ * Reposition boundary events to the bottom edge of their host task, then walk
14
+ * each boundary event's exclusive downstream chain and place those nodes
15
+ * horizontally to the right of the host task. Re-routes all affected edges.
16
+ */
17
+ function repositionBoundaryEvents(flowElements, result) {
18
+ // Collect boundary events grouped by host task id
19
+ const boundaryMap = new Map();
20
+ for (const el of flowElements) {
21
+ if (el.type !== "boundaryEvent")
22
+ continue;
23
+ const list = boundaryMap.get(el.attachedToRef) ?? [];
24
+ list.push(el.id);
25
+ boundaryMap.set(el.attachedToRef, list);
26
+ }
27
+ if (boundaryMap.size === 0)
28
+ return;
29
+ const nodeById = new Map(result.nodes.map((n) => [n.id, n]));
30
+ // Build successor / predecessor maps from edges for chain walking
31
+ const succIds = new Map();
32
+ const predIds = new Map();
33
+ for (const edge of result.edges) {
34
+ const se = succIds.get(edge.sourceRef) ?? [];
35
+ se.push(edge.targetRef);
36
+ succIds.set(edge.sourceRef, se);
37
+ const ps = predIds.get(edge.targetRef) ?? new Set();
38
+ ps.add(edge.sourceRef);
39
+ predIds.set(edge.targetRef, ps);
40
+ }
41
+ for (const [hostId, beIds] of boundaryMap) {
42
+ const hostNode = nodeById.get(hostId);
43
+ if (!hostNode)
44
+ continue;
45
+ for (let i = 0; i < beIds.length; i++) {
46
+ const beId = beIds[i];
47
+ if (!beId)
48
+ continue;
49
+ const beNode = nodeById.get(beId);
50
+ if (!beNode)
51
+ continue;
52
+ const bW = beNode.bounds.width;
53
+ const bH = beNode.bounds.height;
54
+ // Place boundary event at bottom-right of host task, stacking leftward
55
+ const rightEdge = hostNode.bounds.x + hostNode.bounds.width;
56
+ beNode.bounds.x = Math.round(rightEdge - bW / 2 - i * (bW + 4));
57
+ beNode.bounds.y = Math.round(hostNode.bounds.y + hostNode.bounds.height - bH / 2);
58
+ if (beNode.labelBounds) {
59
+ beNode.labelBounds.x = beNode.bounds.x + Math.round(bW / 2 - beNode.labelBounds.width / 2);
60
+ beNode.labelBounds.y = beNode.bounds.y + bH + 4;
61
+ }
62
+ // Collect nodes exclusively reachable from this boundary event (in BFS order)
63
+ const chainSet = new Set([beId]);
64
+ const chainOrder = [];
65
+ const queue = [...(succIds.get(beId) ?? [])];
66
+ while (queue.length > 0) {
67
+ const id = queue.shift();
68
+ if (!id || chainSet.has(id))
69
+ continue;
70
+ // Include only if every predecessor is already in the chain
71
+ const preds = predIds.get(id) ?? new Set();
72
+ if ([...preds].every((p) => chainSet.has(p))) {
73
+ chainSet.add(id);
74
+ chainOrder.push(id);
75
+ queue.push(...(succIds.get(id) ?? []));
76
+ }
77
+ }
78
+ // Find tallest chain element to compute center Y below boundary event.
79
+ // Each boundary event's chain gets its own vertical lane to avoid overlaps.
80
+ let maxChainH = 0;
81
+ for (const id of chainOrder) {
82
+ const n = nodeById.get(id);
83
+ if (n)
84
+ maxChainH = Math.max(maxChainH, n.bounds.height);
85
+ }
86
+ const laneOffset = i * (maxChainH + CHAIN_V_GAP + 10);
87
+ const chainCenterY = Math.round(beNode.bounds.y + bH + CHAIN_V_GAP + maxChainH / 2 + laneOffset);
88
+ const chainStartX = Math.max(Math.round(beNode.bounds.x + bW / 2) + CHAIN_GAP, hostNode.bounds.x + hostNode.bounds.width + CHAIN_GAP);
89
+ let curX = chainStartX;
90
+ for (const id of chainOrder) {
91
+ const n = nodeById.get(id);
92
+ if (!n)
93
+ continue;
94
+ n.bounds.x = curX;
95
+ n.bounds.y = chainCenterY - Math.round(n.bounds.height / 2);
96
+ if (n.labelBounds) {
97
+ n.labelBounds.x = n.bounds.x + Math.round(n.bounds.width / 2 - n.labelBounds.width / 2);
98
+ n.labelBounds.y = n.bounds.y + n.bounds.height + 4;
99
+ }
100
+ curX += n.bounds.width + CHAIN_GAP;
101
+ }
102
+ // Re-route all edges touching the boundary event or its chain
103
+ for (const edge of result.edges) {
104
+ if (!chainSet.has(edge.sourceRef))
105
+ continue;
106
+ const src = nodeById.get(edge.sourceRef);
107
+ const tgt = nodeById.get(edge.targetRef);
108
+ if (!src || !tgt)
109
+ continue;
110
+ if (edge.sourceRef === beId) {
111
+ // Boundary event → first chain node: route down then right
112
+ const srcX = Math.round(src.bounds.x + bW / 2);
113
+ const srcY = Math.round(src.bounds.y + bH);
114
+ const tgtX = Math.round(tgt.bounds.x);
115
+ const tgtY = Math.round(tgt.bounds.y + tgt.bounds.height / 2);
116
+ edge.waypoints = [
117
+ { x: srcX, y: srcY },
118
+ { x: srcX, y: tgtY },
119
+ { x: tgtX, y: tgtY },
120
+ ];
121
+ }
122
+ else {
123
+ // Within chain: straight horizontal edge
124
+ const srcX = Math.round(src.bounds.x + src.bounds.width);
125
+ const srcY = Math.round(src.bounds.y + src.bounds.height / 2);
126
+ const tgtX = Math.round(tgt.bounds.x);
127
+ const tgtY = Math.round(tgt.bounds.y + tgt.bounds.height / 2);
128
+ edge.waypoints = [
129
+ { x: srcX, y: srcY },
130
+ { x: tgtX, y: tgtY },
131
+ ];
132
+ }
133
+ }
134
+ }
135
+ }
136
+ }
137
+ function contentBbox(nodes, extra) {
7
138
  let minX = Number.POSITIVE_INFINITY;
8
139
  let minY = Number.POSITIVE_INFINITY;
9
140
  let maxX = Number.NEGATIVE_INFINITY;
@@ -20,8 +151,107 @@ function contentBbox(nodes) {
20
151
  maxY = Math.max(maxY, n.labelBounds.y + n.labelBounds.height);
21
152
  }
22
153
  }
154
+ if (extra) {
155
+ for (const b of extra) {
156
+ minX = Math.min(minX, b.x);
157
+ minY = Math.min(minY, b.y);
158
+ maxX = Math.max(maxX, b.x + b.width);
159
+ maxY = Math.max(maxY, b.y + b.height);
160
+ }
161
+ }
23
162
  return { minX, minY, maxX, maxY };
24
163
  }
164
+ /** Pre-compute annotation positions in layout space (before dx/dy shift). */
165
+ function computeAnnotationLocalBounds(process, layoutNodes) {
166
+ const nodeById = new Map(layoutNodes.map((n) => [n.id, n]));
167
+ const placements = new Map();
168
+ // Occupied regions for overlap checks (node bounds + label bounds)
169
+ const occupied = [];
170
+ for (const n of layoutNodes) {
171
+ occupied.push({ ...n.bounds });
172
+ if (n.labelBounds)
173
+ occupied.push({ ...n.labelBounds });
174
+ }
175
+ // Static obstacles for crossing detection (nodes + labels only, not annotations)
176
+ const obstacles = [...occupied];
177
+ for (const ta of process.textAnnotations) {
178
+ const assoc = process.associations.find((a) => a.sourceRef === ta.id || a.targetRef === ta.id);
179
+ const connId = assoc
180
+ ? assoc.sourceRef === ta.id
181
+ ? assoc.targetRef
182
+ : assoc.sourceRef
183
+ : undefined;
184
+ const connNode = connId ? nodeById.get(connId) : undefined;
185
+ const annW = Math.min(200, Math.max(100, (ta.text?.length ?? 10) * 5));
186
+ if (!connNode) {
187
+ const candidate = { x: 0, y: 0, width: annW, height: ANN_H };
188
+ occupied.push({ ...candidate });
189
+ placements.set(ta.id, candidate);
190
+ continue;
191
+ }
192
+ const localX = connNode.bounds.x + connNode.bounds.width / 2 - annW / 2;
193
+ const anchorX = connNode.bounds.x + connNode.bounds.width / 2;
194
+ const pushStep = ANN_H + ANN_PADDING * 2 + 10;
195
+ // Try below: start below connected element, push down for overlaps
196
+ const belowY = connNode.bounds.y + connNode.bounds.height + ANN_GAP;
197
+ const below = { x: localX, y: belowY, width: annW, height: ANN_H };
198
+ for (let i = 0; i < 30 && hasOverlapPadded(below, occupied, ANN_PADDING); i++)
199
+ below.y += pushStep;
200
+ // Try above: gap scales with text length so longer annotations have more breathing room
201
+ const aboveGap = ANN_GAP + Math.round(annW * 0.2);
202
+ const aboveY = connNode.bounds.y - aboveGap - ANN_H;
203
+ const above = { x: localX, y: aboveY, width: annW, height: ANN_H };
204
+ for (let i = 0; i < 30 && hasOverlapPadded(above, occupied, ANN_PADDING); i++)
205
+ above.y -= pushStep;
206
+ // Count how many obstacles the association line would cross for each candidate
207
+ const belowCrossings = countLineCrossings(anchorX, connNode.bounds, below, obstacles);
208
+ const aboveCrossings = countLineCrossings(anchorX, connNode.bounds, above, obstacles);
209
+ const candidate = belowCrossings <= aboveCrossings ? below : above;
210
+ occupied.push({ ...candidate });
211
+ obstacles.push({ ...candidate });
212
+ placements.set(ta.id, candidate);
213
+ }
214
+ return placements;
215
+ }
216
+ /** Count how many obstacles the vertical association line from connNode to annotation crosses. */
217
+ function countLineCrossings(lineX, connBounds, annBounds, obstacles) {
218
+ const annCY = annBounds.y + annBounds.height / 2;
219
+ const connCY = connBounds.y + connBounds.height / 2;
220
+ const top = Math.min(annCY, connCY);
221
+ const bottom = Math.max(annCY, connCY);
222
+ const tolerance = 20;
223
+ let crossings = 0;
224
+ for (const b of obstacles) {
225
+ // Skip the connected element itself
226
+ if (b.x === connBounds.x && b.y === connBounds.y && b.width === connBounds.width)
227
+ continue;
228
+ // Obstacle must overlap with the line's X corridor
229
+ if (b.x + b.width < lineX - tolerance || b.x > lineX + tolerance)
230
+ continue;
231
+ // Obstacle must be between connNode and annotation vertically
232
+ if (b.y + b.height <= top || b.y >= bottom)
233
+ continue;
234
+ crossings++;
235
+ }
236
+ return crossings;
237
+ }
238
+ function hasOverlap(a, others) {
239
+ for (const b of others) {
240
+ if (a.x < b.x + b.width && a.x + a.width > b.x && a.y < b.y + b.height && a.y + a.height > b.y)
241
+ return true;
242
+ }
243
+ return false;
244
+ }
245
+ function hasOverlapPadded(a, others, padding) {
246
+ for (const b of others) {
247
+ if (a.x - padding < b.x + b.width &&
248
+ a.x + a.width + padding > b.x &&
249
+ a.y - padding < b.y + b.height &&
250
+ a.y + a.height + padding > b.y)
251
+ return true;
252
+ }
253
+ return false;
254
+ }
25
255
  function nodeToShape(node, dx, dy) {
26
256
  const shape = {
27
257
  id: `${node.id}_di`,
@@ -112,6 +342,70 @@ function buildLaneShapes(lanes, nodes, dx, dy, poolY, poolHeaderWidth, laneConte
112
342
  unknownAttributes: {},
113
343
  }));
114
344
  }
345
+ function addAnnotationShapes(process, layoutNodes, annLocalBounds, allShapes, allEdges, dx, dy) {
346
+ if (process.textAnnotations.length === 0 && process.associations.length === 0)
347
+ return;
348
+ const nodeById = new Map(layoutNodes.map((n) => [n.id, n]));
349
+ for (const ta of process.textAnnotations) {
350
+ const b = annLocalBounds.get(ta.id);
351
+ if (!b)
352
+ continue;
353
+ allShapes.push({
354
+ id: `${ta.id}_di`,
355
+ bpmnElement: ta.id,
356
+ bounds: {
357
+ x: Math.round(b.x + dx),
358
+ y: Math.round(b.y + dy),
359
+ width: b.width,
360
+ height: b.height,
361
+ },
362
+ unknownAttributes: {},
363
+ });
364
+ }
365
+ for (const assoc of process.associations) {
366
+ const annId = annLocalBounds.has(assoc.sourceRef)
367
+ ? assoc.sourceRef
368
+ : annLocalBounds.has(assoc.targetRef)
369
+ ? assoc.targetRef
370
+ : undefined;
371
+ const elId = annId === assoc.sourceRef ? assoc.targetRef : assoc.sourceRef;
372
+ const annB = annId ? annLocalBounds.get(annId) : undefined;
373
+ const elNode = nodeById.get(elId);
374
+ if (!annB || !elNode)
375
+ continue;
376
+ const elB = elNode.bounds;
377
+ const annCx = Math.round(annB.x + annB.width / 2 + dx);
378
+ const elCx = Math.round(elB.x + elB.width / 2 + dx);
379
+ let waypoints;
380
+ if (annB.y >= elB.y + elB.height) {
381
+ // annotation below: element bottom-center → annotation top-center
382
+ waypoints = [
383
+ { x: elCx, y: Math.round(elB.y + elB.height + dy) },
384
+ { x: annCx, y: Math.round(annB.y + dy) },
385
+ ];
386
+ }
387
+ else if (annB.y + annB.height <= elB.y) {
388
+ // annotation above: element top-center → annotation bottom-center
389
+ waypoints = [
390
+ { x: elCx, y: Math.round(elB.y + dy) },
391
+ { x: annCx, y: Math.round(annB.y + annB.height + dy) },
392
+ ];
393
+ }
394
+ else {
395
+ // side-by-side: center-to-center
396
+ waypoints = [
397
+ { x: Math.round(elB.x + elB.width / 2 + dx), y: Math.round(elB.y + elB.height / 2 + dy) },
398
+ { x: annCx, y: Math.round(annB.y + annB.height / 2 + dy) },
399
+ ];
400
+ }
401
+ allEdges.push({
402
+ id: `${assoc.id}_di`,
403
+ bpmnElement: assoc.id,
404
+ waypoints,
405
+ unknownAttributes: {},
406
+ });
407
+ }
408
+ }
115
409
  /**
116
410
  * Apply auto-layout to all processes in a BpmnDefinitions, replacing the
117
411
  * diagram interchange (BPMNDi) with freshly computed positions.
@@ -139,27 +433,41 @@ export function applyAutoLayout(defs) {
139
433
  const lanes = process.laneSet?.lanes ?? [];
140
434
  const hasLanes = lanes.length > 0;
141
435
  const result = layoutProcess(process);
436
+ // Post-process boundary events: reposition each boundary event to the bottom
437
+ // of its host task, then walk its exclusive downstream chain and reposition
438
+ // those nodes horizontally to the right of the host task.
439
+ repositionBoundaryEvents(process.flowElements, result);
440
+ // Re-resolve edge crossings after boundary events moved shapes
441
+ const nodeMap = new Map(result.nodes.map((n) => [n.id, n]));
442
+ resolveEdgeCrossings(result.edges, nodeMap);
142
443
  if (result.nodes.length === 0)
143
444
  continue;
144
- const { minX, minY, maxX, maxY } = contentBbox(result.nodes);
445
+ // Pre-compute annotation positions in layout space so they're included in the bbox
446
+ const annBounds = computeAnnotationLocalBounds(process, result.nodes);
447
+ const { minX, minY, maxX, maxY } = contentBbox(result.nodes, annBounds.values());
145
448
  const contentW = maxX - minX;
146
449
  const contentH = maxY - minY;
450
+ let dx;
451
+ let dy;
147
452
  if (participantId) {
148
- // Elements sit inside pool content area:
149
- // x starts at: POOL_HEADER + optional LANE_HEADER + PADDING
150
- // y starts at: poolY + PADDING
151
453
  const elemX = POOL_HEADER + (hasLanes ? LANE_HEADER : 0) + PADDING;
152
454
  const elemY = poolY + PADDING;
153
- const dx = elemX - minX;
154
- const dy = elemY - minY;
155
- for (const node of result.nodes)
156
- allShapes.push(nodeToShape(node, dx, dy));
157
- for (const edge of result.edges)
158
- allEdges.push(edgeToShape(edge, dx, dy));
455
+ dx = elemX - minX;
456
+ dy = elemY - minY;
457
+ }
458
+ else {
459
+ dx = PADDING - minX;
460
+ dy = PADDING - minY;
461
+ }
462
+ for (const node of result.nodes)
463
+ allShapes.push(nodeToShape(node, dx, dy));
464
+ for (const edge of result.edges)
465
+ allEdges.push(edgeToShape(edge, dx, dy));
466
+ addAnnotationShapes(process, result.nodes, annBounds, allShapes, allEdges, dx, dy);
467
+ if (participantId) {
159
468
  const innerW = (hasLanes ? LANE_HEADER : 0) + contentW + 2 * PADDING;
160
469
  const innerH = contentH + 2 * PADDING;
161
470
  const poolW = POOL_HEADER + innerW;
162
- // Pool (participant) shape
163
471
  allShapes.push({
164
472
  id: `${participantId}_di`,
165
473
  bpmnElement: participantId,
@@ -173,15 +481,6 @@ export function applyAutoLayout(defs) {
173
481
  }
174
482
  poolY += innerH + POOL_GAP;
175
483
  }
176
- else {
177
- // No collaboration — layout at (PADDING, PADDING)
178
- const dx = PADDING - minX;
179
- const dy = PADDING - minY;
180
- for (const node of result.nodes)
181
- allShapes.push(nodeToShape(node, dx, dy));
182
- for (const edge of result.edges)
183
- allEdges.push(edgeToShape(edge, dx, dy));
184
- }
185
484
  }
186
485
  const planeBpmnElement = collab?.id ?? defs.processes[0]?.id ?? "plane";
187
486
  const existingDiagram = defs.diagrams[0];
@@ -1073,6 +1073,7 @@ export class ProcessBuilder {
1073
1073
  errors: this.rootErrors,
1074
1074
  escalations: [],
1075
1075
  messages: this.rootMessages,
1076
+ signals: [],
1076
1077
  collaborations: [],
1077
1078
  processes: [process],
1078
1079
  diagrams: this._autoLayout ? [this.buildDiagram(process)] : [],
@@ -336,6 +336,11 @@ export interface BpmnMessage {
336
336
  name?: string;
337
337
  unknownAttributes: Record<string, string>;
338
338
  }
339
+ /** A root-level BPMN signal definition referenced by signal catch/throw events. */
340
+ export interface BpmnSignal {
341
+ id: string;
342
+ name?: string;
343
+ }
339
344
  /** Optional label positioning information for a BPMNDi shape or edge. */
340
345
  export interface BpmnDiLabel {
341
346
  bounds?: BpmnBounds;
@@ -397,6 +402,7 @@ export interface BpmnDefinitions {
397
402
  errors: BpmnError[];
398
403
  escalations: BpmnEscalation[];
399
404
  messages: BpmnMessage[];
405
+ signals: BpmnSignal[];
400
406
  collaborations: BpmnCollaboration[];
401
407
  processes: BpmnProcess[];
402
408
  diagrams: BpmnDiagram[];
@@ -505,6 +505,12 @@ function parseMessage(element) {
505
505
  unknownAttributes: unknownAttrs(element),
506
506
  };
507
507
  }
508
+ function parseSignal(element) {
509
+ return {
510
+ id: requiredAttr(element, "id"),
511
+ name: attr(element, "name"),
512
+ };
513
+ }
508
514
  // ---------------------------------------------------------------------------
509
515
  // Diagram interchange
510
516
  // ---------------------------------------------------------------------------
@@ -607,6 +613,7 @@ export function parseBpmn(xml) {
607
613
  const errors = [];
608
614
  const escalations = [];
609
615
  const messages = [];
616
+ const signals = [];
610
617
  const collaborations = [];
611
618
  const processes = [];
612
619
  const diagrams = [];
@@ -618,6 +625,8 @@ export function parseBpmn(xml) {
618
625
  escalations.push(parseEscalation(child));
619
626
  else if (ln === "message")
620
627
  messages.push(parseMessage(child));
628
+ else if (ln === "signal")
629
+ signals.push(parseSignal(child));
621
630
  else if (ln === "collaboration")
622
631
  collaborations.push(parseCollaboration(child));
623
632
  else if (ln === "process")
@@ -635,6 +644,7 @@ export function parseBpmn(xml) {
635
644
  errors,
636
645
  escalations,
637
646
  messages,
647
+ signals,
638
648
  collaborations,
639
649
  processes,
640
650
  diagrams,
@@ -387,6 +387,12 @@ function serializeMessage(m, bp) {
387
387
  attrs.name = m.name;
388
388
  return el(`${bp}:message`, attrs, []);
389
389
  }
390
+ function serializeSignal(s, bp) {
391
+ const attrs = { id: s.id };
392
+ if (s.name !== undefined)
393
+ attrs.name = s.name;
394
+ return el(`${bp}:signal`, attrs, []);
395
+ }
390
396
  // ---------------------------------------------------------------------------
391
397
  // Diagram interchange
392
398
  // ---------------------------------------------------------------------------
@@ -490,7 +496,7 @@ export function serializeBpmn(definitions) {
490
496
  attrs[key] = value;
491
497
  }
492
498
  const children = [];
493
- // Root elements: errors, escalations, messages first
499
+ // Root elements: errors, escalations, messages, signals first
494
500
  for (const e of definitions.escalations) {
495
501
  children.push(serializeEscalation(e, bp));
496
502
  }
@@ -500,6 +506,9 @@ export function serializeBpmn(definitions) {
500
506
  for (const m of definitions.messages) {
501
507
  children.push(serializeMessage(m, bp));
502
508
  }
509
+ for (const s of definitions.signals ?? []) {
510
+ children.push(serializeSignal(s, bp));
511
+ }
503
512
  // Collaborations
504
513
  for (const c of definitions.collaborations) {
505
514
  children.push(serializeCollaboration(c, ns));
@@ -380,6 +380,7 @@ export function expand(compact) {
380
380
  errors: [],
381
381
  escalations: [],
382
382
  messages: [],
383
+ signals: [],
383
384
  collaborations: [],
384
385
  processes,
385
386
  diagrams,
@@ -204,6 +204,7 @@ function buildExtractedDefs(representative, newProcessId) {
204
204
  errors: [],
205
205
  escalations: [],
206
206
  messages: [],
207
+ signals: [],
207
208
  collaborations: [],
208
209
  processes: [extractedProcess],
209
210
  diagrams: [diagram],
package/dist/index.d.ts CHANGED
@@ -5,7 +5,7 @@ export { findElement, findElementInProcess, findProcess, findSequenceFlow, getAl
5
5
  export { Bpmn, SAMPLE_BPMN_XML } from "./bpmn/index.js";
6
6
  export { applyAutoLayout } from "./bpmn/auto-layout.js";
7
7
  export type { ProcessBuilder, BranchBuilder, SubProcessContentBuilder, ServiceTaskOptions, ScriptTaskOptions, UserTaskOptions, CallActivityOptions, BusinessRuleTaskOptions, ElementOptions, GatewayOptions, MultiInstanceOptions, SubProcessOptions, StartEventOptions, IntermediateCatchEventOptions, IntermediateThrowEventOptions, BoundaryEventOptions, AdHocSubProcessOptions, } from "./bpmn/bpmn-builder.js";
8
- export type { BpmnDefinitions, BpmnProcess, BpmnFlowNode, BpmnFlowElement, BpmnSequenceFlow, BpmnBoundaryEvent, BpmnElementType, BpmnStartEvent, BpmnEndEvent, BpmnIntermediateCatchEvent, BpmnIntermediateThrowEvent, BpmnTask, BpmnServiceTask, BpmnScriptTask, BpmnUserTask, BpmnSendTask, BpmnReceiveTask, BpmnBusinessRuleTask, BpmnManualTask, BpmnCallActivity, BpmnSubProcess, BpmnAdHocSubProcess, BpmnEventSubProcess, BpmnTransaction, BpmnExclusiveGateway, BpmnParallelGateway, BpmnInclusiveGateway, BpmnEventBasedGateway, BpmnComplexGateway, BpmnCollaboration, BpmnParticipant, BpmnMessageFlow, BpmnLane, BpmnLaneSet, BpmnError, BpmnEscalation, BpmnMessage, BpmnTextAnnotation, BpmnAssociation, BpmnConditionExpression, BpmnEventDefinition, BpmnTimerEventDefinition, BpmnErrorEventDefinition, BpmnEscalationEventDefinition, BpmnMessageEventDefinition, BpmnSignalEventDefinition, BpmnConditionalEventDefinition, BpmnLinkEventDefinition, BpmnCancelEventDefinition, BpmnTerminateEventDefinition, BpmnCompensateEventDefinition, BpmnMultiInstanceLoopCharacteristics, BpmnDiagram, BpmnDiPlane, BpmnDiShape, BpmnDiEdge, BpmnDiLabel, BpmnBounds, BpmnWaypoint, } from "./bpmn/bpmn-model.js";
8
+ export type { BpmnDefinitions, BpmnProcess, BpmnFlowNode, BpmnFlowElement, BpmnSequenceFlow, BpmnBoundaryEvent, BpmnElementType, BpmnStartEvent, BpmnEndEvent, BpmnIntermediateCatchEvent, BpmnIntermediateThrowEvent, BpmnTask, BpmnServiceTask, BpmnScriptTask, BpmnUserTask, BpmnSendTask, BpmnReceiveTask, BpmnBusinessRuleTask, BpmnManualTask, BpmnCallActivity, BpmnSubProcess, BpmnAdHocSubProcess, BpmnEventSubProcess, BpmnTransaction, BpmnExclusiveGateway, BpmnParallelGateway, BpmnInclusiveGateway, BpmnEventBasedGateway, BpmnComplexGateway, BpmnCollaboration, BpmnParticipant, BpmnMessageFlow, BpmnLane, BpmnLaneSet, BpmnError, BpmnEscalation, BpmnMessage, BpmnSignal, BpmnTextAnnotation, BpmnAssociation, BpmnConditionExpression, BpmnEventDefinition, BpmnTimerEventDefinition, BpmnErrorEventDefinition, BpmnEscalationEventDefinition, BpmnMessageEventDefinition, BpmnSignalEventDefinition, BpmnConditionalEventDefinition, BpmnLinkEventDefinition, BpmnCancelEventDefinition, BpmnTerminateEventDefinition, BpmnCompensateEventDefinition, BpmnMultiInstanceLoopCharacteristics, BpmnDiagram, BpmnDiPlane, BpmnDiShape, BpmnDiEdge, BpmnDiLabel, BpmnBounds, BpmnWaypoint, } from "./bpmn/bpmn-model.js";
9
9
  export type { RestConnectorConfig, RestAuthentication, HttpMethod, } from "./bpmn/rest-connector.js";
10
10
  export type { ZeebeExtensions, ZeebeTaskDefinition, ZeebeIoMapping, ZeebeIoMappingEntry, ZeebeTaskHeaders, ZeebeTaskHeaderEntry, ZeebeProperties, ZeebePropertyEntry, ZeebeFormDefinition, ZeebeCalledDecision, } from "./bpmn/zeebe-extensions.js";
11
11
  export { zeebeExtensionsToXmlElements } from "./bpmn/zeebe-extensions.js";
@@ -32,7 +32,7 @@ export { layoutProcess, layoutFlowNodes } from "./layout/index.js";
32
32
  export { benchmarkLayout, compareLayouts, formatBenchmarkResult, generateAutoLayout, parseReferenceLayout, } from "./layout/index.js";
33
33
  export type { BenchmarkResult, BoundingBox, ElementComparison, ElementPosition, FlowOrderViolation, } from "./layout/index.js";
34
34
  export type { Bounds, LayoutEdge, LayoutNode, LayoutResult, Waypoint } from "./layout/index.js";
35
- export { ELEMENT_SIZES, GRID_CELL_HEIGHT } from "./layout/index.js";
35
+ export { ELEMENT_SIZES, GRID_CELL_HEIGHT, GRID_CELL_WIDTH } from "./layout/index.js";
36
36
  export { compactify, expand } from "./bpmn/compact.js";
37
37
  export { applyOperations } from "./bpmn/operations.js";
38
38
  export type { BpmnOperation } from "./bpmn/operations.js";
package/dist/index.js CHANGED
@@ -15,7 +15,7 @@ export { renderStoryHtml } from "./bpmn/story.js";
15
15
  export { analyzeVariableFlow, extractFeelIdentifiers } from "./bpmn/optimize/variable-flow.js";
16
16
  export { layoutProcess, layoutFlowNodes } from "./layout/index.js";
17
17
  export { benchmarkLayout, compareLayouts, formatBenchmarkResult, generateAutoLayout, parseReferenceLayout, } from "./layout/index.js";
18
- export { ELEMENT_SIZES, GRID_CELL_HEIGHT } from "./layout/index.js";
18
+ export { ELEMENT_SIZES, GRID_CELL_HEIGHT, GRID_CELL_WIDTH } from "./layout/index.js";
19
19
  export { compactify, expand } from "./bpmn/compact.js";
20
20
  export { applyOperations } from "./bpmn/operations.js";
21
21
  export { buildValidationDmn, findValidationStructure, getValidationInputNames, insertValidationStructure, removeValidationStructure, validationDecisionId, } from "./bpmn/input-validation.js";
@@ -0,0 +1,15 @@
1
+ import type { Bounds, Waypoint } from "./types.js";
2
+ /**
3
+ * Route a single edge using A* on a 10px grid.
4
+ * source/target are center points of source/target nodes.
5
+ * obstacles are node bounding boxes to avoid (inflated by 6px margin).
6
+ * Returns simplified orthogonal waypoints.
7
+ */
8
+ export declare function routeEdgeAstar(source: {
9
+ x: number;
10
+ y: number;
11
+ }, target: {
12
+ x: number;
13
+ y: number;
14
+ }, obstacles: Bounds[], canvasWidth: number, canvasHeight: number): Waypoint[];
15
+ //# sourceMappingURL=astar.d.ts.map