@bpmnkit/core 0.0.8

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 (104) hide show
  1. package/README.md +185 -0
  2. package/dist/bpmn/auto-layout.d.ts +10 -0
  3. package/dist/bpmn/auto-layout.js +203 -0
  4. package/dist/bpmn/bpmn-builder.d.ts +381 -0
  5. package/dist/bpmn/bpmn-builder.js +1223 -0
  6. package/dist/bpmn/bpmn-model.d.ts +403 -0
  7. package/dist/bpmn/bpmn-model.js +2 -0
  8. package/dist/bpmn/bpmn-parser.d.ts +4 -0
  9. package/dist/bpmn/bpmn-parser.js +642 -0
  10. package/dist/bpmn/bpmn-serializer.d.ts +4 -0
  11. package/dist/bpmn/bpmn-serializer.js +515 -0
  12. package/dist/bpmn/compact.d.ts +91 -0
  13. package/dist/bpmn/compact.js +349 -0
  14. package/dist/bpmn/di-color.d.ts +9 -0
  15. package/dist/bpmn/di-color.js +32 -0
  16. package/dist/bpmn/index.d.ts +105 -0
  17. package/dist/bpmn/index.js +176 -0
  18. package/dist/bpmn/optimize/feel.d.ts +4 -0
  19. package/dist/bpmn/optimize/feel.js +186 -0
  20. package/dist/bpmn/optimize/flow.d.ts +4 -0
  21. package/dist/bpmn/optimize/flow.js +323 -0
  22. package/dist/bpmn/optimize/index.d.ts +5 -0
  23. package/dist/bpmn/optimize/index.js +51 -0
  24. package/dist/bpmn/optimize/naming.d.ts +8 -0
  25. package/dist/bpmn/optimize/naming.js +145 -0
  26. package/dist/bpmn/optimize/tasks.d.ts +4 -0
  27. package/dist/bpmn/optimize/tasks.js +273 -0
  28. package/dist/bpmn/optimize/types.d.ts +44 -0
  29. package/dist/bpmn/optimize/types.js +2 -0
  30. package/dist/bpmn/optimize/utils.d.ts +23 -0
  31. package/dist/bpmn/optimize/utils.js +129 -0
  32. package/dist/bpmn/rest-connector.d.ts +48 -0
  33. package/dist/bpmn/rest-connector.js +69 -0
  34. package/dist/bpmn/svg.d.ts +35 -0
  35. package/dist/bpmn/svg.js +557 -0
  36. package/dist/bpmn/type-guards.d.ts +136 -0
  37. package/dist/bpmn/type-guards.js +211 -0
  38. package/dist/bpmn/utils.d.ts +88 -0
  39. package/dist/bpmn/utils.js +207 -0
  40. package/dist/bpmn/zeebe-extensions.d.ts +72 -0
  41. package/dist/bpmn/zeebe-extensions.js +96 -0
  42. package/dist/dmn/compact.d.ts +44 -0
  43. package/dist/dmn/compact.js +125 -0
  44. package/dist/dmn/dmn-builder.d.ts +59 -0
  45. package/dist/dmn/dmn-builder.js +144 -0
  46. package/dist/dmn/dmn-layout.d.ts +57 -0
  47. package/dist/dmn/dmn-layout.js +256 -0
  48. package/dist/dmn/dmn-model.d.ts +158 -0
  49. package/dist/dmn/dmn-model.js +2 -0
  50. package/dist/dmn/dmn-parser.d.ts +4 -0
  51. package/dist/dmn/dmn-parser.js +275 -0
  52. package/dist/dmn/dmn-serializer.d.ts +4 -0
  53. package/dist/dmn/dmn-serializer.js +296 -0
  54. package/dist/dmn/index.d.ts +28 -0
  55. package/dist/dmn/index.js +51 -0
  56. package/dist/errors.d.ts +77 -0
  57. package/dist/errors.js +66 -0
  58. package/dist/form/compact.d.ts +20 -0
  59. package/dist/form/compact.js +146 -0
  60. package/dist/form/form-builder.d.ts +111 -0
  61. package/dist/form/form-builder.js +347 -0
  62. package/dist/form/form-model.d.ts +221 -0
  63. package/dist/form/form-model.js +2 -0
  64. package/dist/form/form-parser.d.ts +4 -0
  65. package/dist/form/form-parser.js +514 -0
  66. package/dist/form/form-serializer.d.ts +4 -0
  67. package/dist/form/form-serializer.js +240 -0
  68. package/dist/form/index.d.ts +27 -0
  69. package/dist/form/index.js +43 -0
  70. package/dist/index.d.ts +37 -0
  71. package/dist/index.js +19 -0
  72. package/dist/layout/bench.d.ts +86 -0
  73. package/dist/layout/bench.js +225 -0
  74. package/dist/layout/coordinates.d.ts +62 -0
  75. package/dist/layout/coordinates.js +868 -0
  76. package/dist/layout/crossing.d.ts +8 -0
  77. package/dist/layout/crossing.js +60 -0
  78. package/dist/layout/graph.d.ts +28 -0
  79. package/dist/layout/graph.js +126 -0
  80. package/dist/layout/index.d.ts +7 -0
  81. package/dist/layout/index.js +5 -0
  82. package/dist/layout/layers.d.ts +13 -0
  83. package/dist/layout/layers.js +49 -0
  84. package/dist/layout/layout-engine.d.ts +21 -0
  85. package/dist/layout/layout-engine.js +191 -0
  86. package/dist/layout/overlap.d.ts +10 -0
  87. package/dist/layout/overlap.js +70 -0
  88. package/dist/layout/routing.d.ts +26 -0
  89. package/dist/layout/routing.js +439 -0
  90. package/dist/layout/subprocess.d.ts +14 -0
  91. package/dist/layout/subprocess.js +77 -0
  92. package/dist/layout/types.d.ts +72 -0
  93. package/dist/layout/types.js +37 -0
  94. package/dist/types/id-generator.d.ts +8 -0
  95. package/dist/types/id-generator.js +31 -0
  96. package/dist/types/index.d.ts +3 -0
  97. package/dist/types/index.js +2 -0
  98. package/dist/types/xml-element.d.ts +12 -0
  99. package/dist/types/xml-element.js +2 -0
  100. package/dist/xml/index.d.ts +2 -0
  101. package/dist/xml/index.js +2 -0
  102. package/dist/xml/xml-parser.d.ts +13 -0
  103. package/dist/xml/xml-parser.js +271 -0
  104. package/package.json +38 -0
@@ -0,0 +1,145 @@
1
+ import { buildFlowIndex, isEndEvent, isStartEvent } from "./utils.js";
2
+ // ---------------------------------------------------------------------------
3
+ // Element type sets
4
+ // ---------------------------------------------------------------------------
5
+ const TASK_TYPES = new Set([
6
+ "serviceTask",
7
+ "userTask",
8
+ "businessRuleTask",
9
+ "scriptTask",
10
+ "sendTask",
11
+ "receiveTask",
12
+ "manualTask",
13
+ "callActivity",
14
+ ]);
15
+ const SUBPROCESS_TYPES = new Set([
16
+ "subProcess",
17
+ "adHocSubProcess",
18
+ "transaction",
19
+ ]);
20
+ const DECISION_GATEWAY_TYPES = new Set([
21
+ "exclusiveGateway",
22
+ "inclusiveGateway",
23
+ ]);
24
+ // ---------------------------------------------------------------------------
25
+ // Naming analyzer
26
+ // ---------------------------------------------------------------------------
27
+ /**
28
+ * Analyze BPMN naming conventions based on Camunda best practices:
29
+ * https://docs.camunda.io/docs/components/best-practices/modeling/naming-bpmnkit-elements/
30
+ */
31
+ export function analyzeNaming(p, _opts) {
32
+ const findings = [];
33
+ const processId = p.id;
34
+ const { bySource, byTarget } = buildFlowIndex(p);
35
+ for (const el of p.flowElements) {
36
+ // ── Tasks ────────────────────────────────────────────────────────────
37
+ if (TASK_TYPES.has(el.type)) {
38
+ if (!el.name) {
39
+ findings.push({
40
+ id: "naming/unlabeled-task",
41
+ category: "naming",
42
+ severity: "warning",
43
+ message: `Task "${el.id}" (${el.type}) has no name.`,
44
+ suggestion: 'Name tasks using "Verb Object" form, e.g. "Verify Invoice", "Send Notification", "Approve Request".',
45
+ processId,
46
+ elementIds: [el.id],
47
+ });
48
+ }
49
+ }
50
+ if (SUBPROCESS_TYPES.has(el.type) && !el.name) {
51
+ findings.push({
52
+ id: "naming/unlabeled-subprocess",
53
+ category: "naming",
54
+ severity: "info",
55
+ message: `Sub-process "${el.id}" (${el.type}) has no name.`,
56
+ suggestion: 'Name sub-processes using "Object + nominalized verb" form, e.g. "Invoice Processing", "Order Fulfillment".',
57
+ processId,
58
+ elementIds: [el.id],
59
+ });
60
+ }
61
+ // ── Events ───────────────────────────────────────────────────────────
62
+ if (isStartEvent(el.type) && !el.name) {
63
+ findings.push({
64
+ id: "naming/unlabeled-start-event",
65
+ category: "naming",
66
+ severity: "info",
67
+ message: `Start event "${el.id}" has no name.`,
68
+ suggestion: 'Name start events using "Object + past participle", e.g. "Order Received", "Payment Initiated".',
69
+ processId,
70
+ elementIds: [el.id],
71
+ });
72
+ }
73
+ if (isEndEvent(el.type) && !el.name) {
74
+ findings.push({
75
+ id: "naming/unlabeled-end-event",
76
+ category: "naming",
77
+ severity: "info",
78
+ message: `End event "${el.id}" has no name.`,
79
+ suggestion: 'Name end events using "Object + state", e.g. "Order Fulfilled", "Payment Failed", "Request Rejected".',
80
+ processId,
81
+ elementIds: [el.id],
82
+ });
83
+ }
84
+ // ── Decision gateways (XOR / inclusive) ──────────────────────────────
85
+ if (DECISION_GATEWAY_TYPES.has(el.type)) {
86
+ const outflows = bySource.get(el.id) ?? [];
87
+ const inflows = byTarget.get(el.id) ?? [];
88
+ const isSplit = outflows.length >= 2;
89
+ const isJoin = inflows.length >= 2;
90
+ if (isSplit) {
91
+ // Split gateway must be labeled
92
+ if (!el.name) {
93
+ findings.push({
94
+ id: "naming/split-gateway-no-label",
95
+ category: "naming",
96
+ severity: "warning",
97
+ message: `Gateway "${el.id}" (${el.type}, split) has no name.`,
98
+ suggestion: 'Label split gateways as a yes/no question, e.g. "Invoice valid?", "Order approved?".',
99
+ processId,
100
+ elementIds: [el.id],
101
+ });
102
+ }
103
+ else if (!el.name.trim().endsWith("?")) {
104
+ findings.push({
105
+ id: "naming/gateway-not-a-question",
106
+ category: "naming",
107
+ severity: "info",
108
+ message: `Gateway "${el.id}" is named "${el.name}" — split gateways should be phrased as questions.`,
109
+ suggestion: `Rephrase as a question, e.g. "${el.name.trim()}?"`,
110
+ processId,
111
+ elementIds: [el.id],
112
+ });
113
+ }
114
+ // Each outgoing flow must have a condition label
115
+ for (const flow of outflows) {
116
+ if (!flow.name) {
117
+ findings.push({
118
+ id: "naming/missing-flow-condition",
119
+ category: "naming",
120
+ severity: "warning",
121
+ message: `Sequence flow "${flow.id}" from split gateway "${el.id}" has no condition label.`,
122
+ suggestion: 'Label each outgoing flow with the condition answer, e.g. "Yes", "No", "Approved", "Rejected".',
123
+ processId,
124
+ elementIds: [el.id, flow.id],
125
+ });
126
+ }
127
+ }
128
+ }
129
+ // Join-only gateways should NOT be labeled
130
+ if (isJoin && !isSplit && el.name) {
131
+ findings.push({
132
+ id: "naming/join-gateway-labeled",
133
+ category: "naming",
134
+ severity: "info",
135
+ message: `Gateway "${el.id}" (join) is named "${el.name}" — join gateways should not have labels.`,
136
+ suggestion: "Remove the label from join-only gateways; their semantics are implicit.",
137
+ processId,
138
+ elementIds: [el.id],
139
+ });
140
+ }
141
+ }
142
+ }
143
+ return findings;
144
+ }
145
+ //# sourceMappingURL=naming.js.map
@@ -0,0 +1,4 @@
1
+ import type { BpmnProcess } from "../bpmn-model.js";
2
+ import type { OptimizationFinding, ResolvedOptions } from "./types.js";
3
+ export declare function analyzeTasks(p: BpmnProcess, opts: ResolvedOptions): OptimizationFinding[];
4
+ //# sourceMappingURL=tasks.d.ts.map
@@ -0,0 +1,273 @@
1
+ import { generateId } from "../../types/id-generator.js";
2
+ import { findProcess, readZeebeIoMapping, readZeebeTaskHeaders, readZeebeTaskType, } from "./utils.js";
3
+ // ---------------------------------------------------------------------------
4
+ // Similarity scoring
5
+ // ---------------------------------------------------------------------------
6
+ function sameHeaderKeys(a, b) {
7
+ const ha = readZeebeTaskHeaders(a.extensionElements);
8
+ const hb = readZeebeTaskHeaders(b.extensionElements);
9
+ const keysA = new Set((ha?.headers ?? []).map((h) => h.key));
10
+ const keysB = new Set((hb?.headers ?? []).map((h) => h.key));
11
+ if (keysA.size !== keysB.size)
12
+ return false;
13
+ for (const k of keysA) {
14
+ if (!keysB.has(k))
15
+ return false;
16
+ }
17
+ return true;
18
+ }
19
+ function sameIoInputs(a, b) {
20
+ const ia = readZeebeIoMapping(a.extensionElements);
21
+ const ib = readZeebeIoMapping(b.extensionElements);
22
+ const inputsA = ia?.inputs ?? [];
23
+ const inputsB = ib?.inputs ?? [];
24
+ if (inputsA.length !== inputsB.length)
25
+ return false;
26
+ const targetsA = inputsA.map((i) => i.target).sort();
27
+ const targetsB = inputsB.map((i) => i.target).sort();
28
+ return targetsA.every((t, idx) => t === targetsB[idx]);
29
+ }
30
+ function sameIoOutputs(a, b) {
31
+ const ia = readZeebeIoMapping(a.extensionElements);
32
+ const ib = readZeebeIoMapping(b.extensionElements);
33
+ const outputsA = ia?.outputs ?? [];
34
+ const outputsB = ib?.outputs ?? [];
35
+ if (outputsA.length !== outputsB.length)
36
+ return false;
37
+ const targetsA = outputsA.map((o) => o.target).sort();
38
+ const targetsB = outputsB.map((o) => o.target).sort();
39
+ return targetsA.every((t, idx) => t === targetsB[idx]);
40
+ }
41
+ /** Returns similarity score [0, 1] or null if taskTypes differ. */
42
+ function computeSimilarity(a, b) {
43
+ const typeA = readZeebeTaskType(a.extensionElements);
44
+ const typeB = readZeebeTaskType(b.extensionElements);
45
+ if (typeA === null || typeB === null || typeA !== typeB)
46
+ return null;
47
+ let score = 0.5; // Same taskType
48
+ if (sameHeaderKeys(a, b))
49
+ score += 0.2;
50
+ if (sameIoInputs(a, b))
51
+ score += 0.15;
52
+ if (sameIoOutputs(a, b))
53
+ score += 0.15;
54
+ return score;
55
+ }
56
+ /** Cluster service tasks into connected components above the similarity threshold. */
57
+ function cluster(tasks, threshold) {
58
+ const n = tasks.length;
59
+ const visited = new Array(n).fill(false);
60
+ const clusters = [];
61
+ for (let i = 0; i < n; i++) {
62
+ if (visited[i])
63
+ continue;
64
+ const group = [];
65
+ const queue = [i];
66
+ visited[i] = true;
67
+ while (queue.length > 0) {
68
+ const curr = queue.shift();
69
+ if (curr === undefined)
70
+ break;
71
+ const task = tasks[curr];
72
+ if (task === undefined)
73
+ break;
74
+ group.push(task);
75
+ for (let j = 0; j < n; j++) {
76
+ if (visited[j])
77
+ continue;
78
+ const other = tasks[j];
79
+ if (other === undefined)
80
+ continue;
81
+ const score = computeSimilarity(task, other);
82
+ if (score !== null && score >= threshold) {
83
+ visited[j] = true;
84
+ queue.push(j);
85
+ }
86
+ }
87
+ }
88
+ clusters.push(group);
89
+ }
90
+ return clusters;
91
+ }
92
+ // ---------------------------------------------------------------------------
93
+ // Build the extracted BpmnDefinitions
94
+ // ---------------------------------------------------------------------------
95
+ function buildExtractedDefs(representative, newProcessId) {
96
+ const startId = generateId("StartEvent");
97
+ const taskId = generateId("ServiceTask");
98
+ const endId = generateId("EndEvent");
99
+ const flow1Id = generateId("Flow");
100
+ const flow2Id = generateId("Flow");
101
+ const startEvent = {
102
+ type: "startEvent",
103
+ id: startId,
104
+ incoming: [],
105
+ outgoing: [flow1Id],
106
+ extensionElements: [],
107
+ unknownAttributes: {},
108
+ eventDefinitions: [],
109
+ };
110
+ const serviceTask = {
111
+ type: "serviceTask",
112
+ id: taskId,
113
+ name: representative.name,
114
+ incoming: [flow1Id],
115
+ outgoing: [flow2Id],
116
+ extensionElements: [...representative.extensionElements],
117
+ unknownAttributes: {},
118
+ };
119
+ const endEvent = {
120
+ type: "endEvent",
121
+ id: endId,
122
+ incoming: [flow2Id],
123
+ outgoing: [],
124
+ extensionElements: [],
125
+ unknownAttributes: {},
126
+ eventDefinitions: [],
127
+ };
128
+ const extractedProcess = {
129
+ id: newProcessId,
130
+ isExecutable: false,
131
+ extensionElements: [],
132
+ flowElements: [startEvent, serviceTask, endEvent],
133
+ sequenceFlows: [
134
+ {
135
+ id: flow1Id,
136
+ sourceRef: startId,
137
+ targetRef: taskId,
138
+ extensionElements: [],
139
+ unknownAttributes: {},
140
+ },
141
+ {
142
+ id: flow2Id,
143
+ sourceRef: taskId,
144
+ targetRef: endId,
145
+ extensionElements: [],
146
+ unknownAttributes: {},
147
+ },
148
+ ],
149
+ textAnnotations: [],
150
+ associations: [],
151
+ unknownAttributes: {},
152
+ };
153
+ // Layout: start @ x=152, task @ x=260, end @ x=432, all y=100
154
+ const startShape = {
155
+ id: `${startId}_di`,
156
+ bpmnElement: startId,
157
+ bounds: { x: 152, y: 100, width: 36, height: 36 },
158
+ unknownAttributes: {},
159
+ };
160
+ const taskShape = {
161
+ id: `${taskId}_di`,
162
+ bpmnElement: taskId,
163
+ bounds: { x: 260, y: 100, width: 100, height: 80 },
164
+ unknownAttributes: {},
165
+ };
166
+ const endShape = {
167
+ id: `${endId}_di`,
168
+ bpmnElement: endId,
169
+ bounds: { x: 432, y: 100, width: 36, height: 36 },
170
+ unknownAttributes: {},
171
+ };
172
+ const flow1Edge = {
173
+ id: `${flow1Id}_di`,
174
+ bpmnElement: flow1Id,
175
+ waypoints: [
176
+ { x: 188, y: 118 },
177
+ { x: 260, y: 118 },
178
+ ],
179
+ unknownAttributes: {},
180
+ };
181
+ const flow2Edge = {
182
+ id: `${flow2Id}_di`,
183
+ bpmnElement: flow2Id,
184
+ waypoints: [
185
+ { x: 360, y: 118 },
186
+ { x: 432, y: 118 },
187
+ ],
188
+ unknownAttributes: {},
189
+ };
190
+ const diagram = {
191
+ id: generateId("BPMNDiagram"),
192
+ plane: {
193
+ id: generateId("BPMNPlane"),
194
+ bpmnElement: newProcessId,
195
+ shapes: [startShape, taskShape, endShape],
196
+ edges: [flow1Edge, flow2Edge],
197
+ },
198
+ };
199
+ return {
200
+ id: generateId("Definitions"),
201
+ targetNamespace: "http://bpmn.io/schema/bpmn",
202
+ namespaces: {},
203
+ unknownAttributes: {},
204
+ errors: [],
205
+ escalations: [],
206
+ messages: [],
207
+ collaborations: [],
208
+ processes: [extractedProcess],
209
+ diagrams: [diagram],
210
+ };
211
+ }
212
+ // ---------------------------------------------------------------------------
213
+ // Task reuse analyzer
214
+ // ---------------------------------------------------------------------------
215
+ export function analyzeTasks(p, opts) {
216
+ const findings = [];
217
+ const processId = p.id;
218
+ const serviceTasks = p.flowElements.filter((el) => el.type === "serviceTask");
219
+ if (serviceTasks.length < 2)
220
+ return findings;
221
+ const groups = cluster(serviceTasks, 0.7).filter((g) => g.length >= opts.reuseThreshold);
222
+ for (const group of groups) {
223
+ const representative = group[0];
224
+ if (!representative)
225
+ continue;
226
+ const taskType = readZeebeTaskType(representative.extensionElements) ?? "Unknown";
227
+ const elementIds = group.map((t) => t.id);
228
+ findings.push({
229
+ id: "task/reusable-group",
230
+ category: "task-reuse",
231
+ severity: "warning",
232
+ message: `${group.length} service tasks share a similar configuration (taskType="${taskType}") and could be reused via a call activity.`,
233
+ suggestion: "Extract the repeated service task into a reusable sub-process and replace occurrences with call activities.",
234
+ processId,
235
+ elementIds,
236
+ applyFix: (defs) => {
237
+ const proc = findProcess(defs, processId);
238
+ if (!proc)
239
+ return { description: "Process not found" };
240
+ const newProcessId = `Reusable_${taskType}_${generateId("proc")}`;
241
+ const generated = buildExtractedDefs(representative, newProcessId);
242
+ // Replace each task in the group with a call activity
243
+ for (const taskId of elementIds) {
244
+ const orig = proc.flowElements.find((e) => e.id === taskId);
245
+ if (!orig || orig.type !== "serviceTask")
246
+ continue;
247
+ const callActivity = {
248
+ type: "callActivity",
249
+ id: orig.id,
250
+ name: orig.name,
251
+ incoming: [...orig.incoming],
252
+ outgoing: [...orig.outgoing],
253
+ extensionElements: [
254
+ {
255
+ name: "zeebe:calledElement",
256
+ attributes: { processId: newProcessId },
257
+ children: [],
258
+ },
259
+ ],
260
+ unknownAttributes: {},
261
+ };
262
+ proc.flowElements = proc.flowElements.map((e) => (e.id === taskId ? callActivity : e));
263
+ }
264
+ return {
265
+ description: `Extracted ${group.length} service tasks to call activity referencing "${newProcessId}"`,
266
+ generated,
267
+ };
268
+ },
269
+ });
270
+ }
271
+ return findings;
272
+ }
273
+ //# sourceMappingURL=tasks.js.map
@@ -0,0 +1,44 @@
1
+ import type { BpmnDefinitions } from "../bpmn-model.js";
2
+ export type OptimizationSeverity = "info" | "warning" | "error";
3
+ export type OptimizationCategory = "feel" | "flow" | "naming" | "task-reuse" | "extract";
4
+ export interface ApplyFixResult {
5
+ description: string;
6
+ /** New BpmnDefinitions generated by the fix (e.g. extracted reusable sub-process). */
7
+ generated?: BpmnDefinitions;
8
+ }
9
+ export interface OptimizationFinding {
10
+ id: string;
11
+ category: OptimizationCategory;
12
+ severity: OptimizationSeverity;
13
+ message: string;
14
+ suggestion: string;
15
+ processId: string;
16
+ elementIds: string[];
17
+ /** Mutates `defs` in-place. Returns what changed + any generated file. */
18
+ applyFix?: (defs: BpmnDefinitions) => ApplyFixResult;
19
+ }
20
+ export interface OptimizationReport {
21
+ findings: OptimizationFinding[];
22
+ summary: {
23
+ total: number;
24
+ byCategory: Record<OptimizationCategory, number>;
25
+ bySeverity: Record<OptimizationSeverity, number>;
26
+ };
27
+ }
28
+ export interface OptimizeOptions {
29
+ feelLengthThreshold?: number;
30
+ feelNestingThreshold?: number;
31
+ feelOperatorThreshold?: number;
32
+ feelVariableThreshold?: number;
33
+ reuseThreshold?: number;
34
+ categories?: OptimizationCategory[];
35
+ }
36
+ export interface ResolvedOptions {
37
+ feelLengthThreshold: number;
38
+ feelNestingThreshold: number;
39
+ feelOperatorThreshold: number;
40
+ feelVariableThreshold: number;
41
+ reuseThreshold: number;
42
+ categories: OptimizationCategory[];
43
+ }
44
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,23 @@
1
+ import type { XmlElement } from "../../types/xml-element.js";
2
+ import type { BpmnDefinitions, BpmnDiPlane, BpmnElementType, BpmnFlowElement, BpmnProcess, BpmnSequenceFlow } from "../bpmn-model.js";
3
+ import type { ZeebeIoMapping, ZeebeTaskHeaders } from "../zeebe-extensions.js";
4
+ export declare function readZeebeTaskType(ext: XmlElement[]): string | null;
5
+ export declare function readZeebeIoMapping(ext: XmlElement[]): ZeebeIoMapping | null;
6
+ export declare function readZeebeTaskHeaders(ext: XmlElement[]): ZeebeTaskHeaders | null;
7
+ export interface FlowIndex {
8
+ byId: Map<string, BpmnFlowElement>;
9
+ bySource: Map<string, BpmnSequenceFlow[]>;
10
+ byTarget: Map<string, BpmnSequenceFlow[]>;
11
+ }
12
+ export declare function buildFlowIndex(p: BpmnProcess): FlowIndex;
13
+ export declare function reachableFrom(startIds: string[], bySource: Map<string, BpmnSequenceFlow[]>): Set<string>;
14
+ export declare function isGateway(type: BpmnElementType): boolean;
15
+ export declare function isEndEvent(type: BpmnElementType): boolean;
16
+ export declare function isStartEvent(type: BpmnElementType): boolean;
17
+ export declare function insertElement(p: BpmnProcess, el: BpmnFlowElement): void;
18
+ export declare function removeElement(p: BpmnProcess, id: string): void;
19
+ export declare function insertFlow(p: BpmnProcess, flow: BpmnSequenceFlow): void;
20
+ export declare function removeFlow(p: BpmnProcess, id: string): void;
21
+ export declare function findProcess(defs: BpmnDefinitions, processId: string): BpmnProcess | null;
22
+ export declare function findDiPlane(defs: BpmnDefinitions, processId: string): BpmnDiPlane | null;
23
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1,129 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Extension readers
3
+ // ---------------------------------------------------------------------------
4
+ export function readZeebeTaskType(ext) {
5
+ for (const el of ext) {
6
+ if (el.name === "zeebe:taskDefinition") {
7
+ return el.attributes.type ?? null;
8
+ }
9
+ }
10
+ return null;
11
+ }
12
+ export function readZeebeIoMapping(ext) {
13
+ for (const el of ext) {
14
+ if (el.name === "zeebe:ioMapping") {
15
+ const inputs = [];
16
+ const outputs = [];
17
+ for (const child of el.children) {
18
+ if (child.name === "zeebe:input") {
19
+ inputs.push({
20
+ source: child.attributes.source ?? "",
21
+ target: child.attributes.target ?? "",
22
+ });
23
+ }
24
+ else if (child.name === "zeebe:output") {
25
+ outputs.push({
26
+ source: child.attributes.source ?? "",
27
+ target: child.attributes.target ?? "",
28
+ });
29
+ }
30
+ }
31
+ return { inputs, outputs };
32
+ }
33
+ }
34
+ return null;
35
+ }
36
+ export function readZeebeTaskHeaders(ext) {
37
+ for (const el of ext) {
38
+ if (el.name === "zeebe:taskHeaders") {
39
+ const headers = [];
40
+ for (const child of el.children) {
41
+ if (child.name === "zeebe:header") {
42
+ headers.push({
43
+ key: child.attributes.key ?? "",
44
+ value: child.attributes.value ?? "",
45
+ });
46
+ }
47
+ }
48
+ return { headers };
49
+ }
50
+ }
51
+ return null;
52
+ }
53
+ export function buildFlowIndex(p) {
54
+ const byId = new Map();
55
+ const bySource = new Map();
56
+ const byTarget = new Map();
57
+ for (const el of p.flowElements) {
58
+ byId.set(el.id, el);
59
+ }
60
+ for (const flow of p.sequenceFlows) {
61
+ const srcList = bySource.get(flow.sourceRef) ?? [];
62
+ srcList.push(flow);
63
+ bySource.set(flow.sourceRef, srcList);
64
+ const tgtList = byTarget.get(flow.targetRef) ?? [];
65
+ tgtList.push(flow);
66
+ byTarget.set(flow.targetRef, tgtList);
67
+ }
68
+ return { byId, bySource, byTarget };
69
+ }
70
+ export function reachableFrom(startIds, bySource) {
71
+ const visited = new Set(startIds);
72
+ const queue = [...startIds];
73
+ while (queue.length > 0) {
74
+ const current = queue.shift();
75
+ if (current === undefined)
76
+ break;
77
+ const outflows = bySource.get(current) ?? [];
78
+ for (const flow of outflows) {
79
+ if (!visited.has(flow.targetRef)) {
80
+ visited.add(flow.targetRef);
81
+ queue.push(flow.targetRef);
82
+ }
83
+ }
84
+ }
85
+ return visited;
86
+ }
87
+ export function isGateway(type) {
88
+ return (type === "exclusiveGateway" ||
89
+ type === "inclusiveGateway" ||
90
+ type === "complexGateway" ||
91
+ type === "parallelGateway" ||
92
+ type === "eventBasedGateway");
93
+ }
94
+ export function isEndEvent(type) {
95
+ return type === "endEvent";
96
+ }
97
+ export function isStartEvent(type) {
98
+ return type === "startEvent";
99
+ }
100
+ // ---------------------------------------------------------------------------
101
+ // Mutation helpers
102
+ // ---------------------------------------------------------------------------
103
+ export function insertElement(p, el) {
104
+ p.flowElements.push(el);
105
+ }
106
+ export function removeElement(p, id) {
107
+ p.flowElements = p.flowElements.filter((e) => e.id !== id);
108
+ }
109
+ export function insertFlow(p, flow) {
110
+ p.sequenceFlows.push(flow);
111
+ }
112
+ export function removeFlow(p, id) {
113
+ p.sequenceFlows = p.sequenceFlows.filter((f) => f.id !== id);
114
+ }
115
+ export function findProcess(defs, processId) {
116
+ for (const p of defs.processes) {
117
+ if (p.id === processId)
118
+ return p;
119
+ }
120
+ return null;
121
+ }
122
+ export function findDiPlane(defs, processId) {
123
+ for (const diagram of defs.diagrams) {
124
+ if (diagram.plane.bpmnElement === processId)
125
+ return diagram.plane;
126
+ }
127
+ return null;
128
+ }
129
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1,48 @@
1
+ import type { ZeebeIoMappingEntry, ZeebeTaskHeaderEntry } from "./zeebe-extensions.js";
2
+ /** HTTP methods supported by the Camunda REST connector. */
3
+ export type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
4
+ /** Authentication configuration for the REST connector. */
5
+ export type RestAuthentication = {
6
+ type: "noAuth";
7
+ } | {
8
+ type: "bearer";
9
+ token: string;
10
+ };
11
+ /** Configuration for the REST connector convenience builder. */
12
+ export interface RestConnectorConfig {
13
+ /** Display name for the task. */
14
+ name?: string;
15
+ /** HTTP method (GET, POST, PUT, PATCH, DELETE). */
16
+ method: HttpMethod;
17
+ /** Target URL — can be a literal string or a FEEL expression (prefix with `=`). */
18
+ url: string;
19
+ /** Authentication configuration. Defaults to `{ type: "noAuth" }`. */
20
+ authentication?: RestAuthentication;
21
+ /** HTTP headers as key-value pairs or a FEEL expression string. */
22
+ headers?: Record<string, string> | string;
23
+ /** Query parameters as a FEEL expression string or key-value pairs. */
24
+ queryParameters?: Record<string, string> | string;
25
+ /** Request body — a FEEL expression string or literal value. */
26
+ body?: string;
27
+ /** Connection timeout in seconds. Defaults to 20. */
28
+ connectionTimeoutInSeconds?: number;
29
+ /** Read timeout in seconds. Defaults to 20. */
30
+ readTimeoutInSeconds?: number;
31
+ /** Number of retries on failure. Defaults to "3". */
32
+ retries?: string;
33
+ /** Variable name to store the full response. */
34
+ resultVariable?: string;
35
+ /** FEEL expression to extract values from the response. */
36
+ resultExpression?: string;
37
+ /** Retry backoff duration (ISO 8601 duration, e.g. "PT0S"). */
38
+ retryBackoff?: string;
39
+ }
40
+ /** Convert a REST connector config into Zeebe IO mapping inputs. */
41
+ export declare function restConnectorToIoMappingInputs(config: RestConnectorConfig): ZeebeIoMappingEntry[];
42
+ /** Get the Zeebe task definition type for REST connectors. */
43
+ export declare function restConnectorTaskType(): string;
44
+ /** Get the default retries value for REST connectors. */
45
+ export declare function restConnectorRetries(config: RestConnectorConfig): string;
46
+ /** Convert a REST connector config into Zeebe task header entries. */
47
+ export declare function restConnectorToTaskHeaders(config: RestConnectorConfig): ZeebeTaskHeaderEntry[];
48
+ //# sourceMappingURL=rest-connector.d.ts.map