@aranzatech/diagrams-bpmn 0.2.15 → 0.3.1
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 +34 -4
- package/dist/{catalog-xOMF2ifW.d.cts → catalog-DAGDhO-D.d.cts} +1 -1
- package/dist/{catalog-CK3_4cOb.d.ts → catalog-Q1QmKLDD.d.ts} +1 -1
- package/dist/{chunk-YUE5EM3W.js → chunk-334WN4JZ.js} +276 -107
- package/dist/chunk-334WN4JZ.js.map +1 -0
- package/dist/chunk-77L6O76M.js +3 -0
- package/dist/chunk-77L6O76M.js.map +1 -0
- package/dist/{chunk-QSMP34CT.js → chunk-CPFUQM6H.js} +80 -44
- package/dist/chunk-CPFUQM6H.js.map +1 -0
- package/dist/{chunk-XMVV7FRZ.js → chunk-FFWJA5BV.js} +3 -3
- package/dist/{chunk-XMVV7FRZ.js.map → chunk-FFWJA5BV.js.map} +1 -1
- package/dist/{chunk-FBTGIYZS.js → chunk-JEGYVEJO.js} +80 -3
- package/dist/{chunk-FBTGIYZS.js.map → chunk-JEGYVEJO.js.map} +1 -1
- package/dist/chunk-TB6V4S5N.js +104 -0
- package/dist/chunk-TB6V4S5N.js.map +1 -0
- package/dist/{chunk-HOWK3ZOO.js → chunk-YAYZW45I.js} +379 -16
- package/dist/chunk-YAYZW45I.js.map +1 -0
- package/dist/edges/index.cjs +78 -42
- package/dist/edges/index.cjs.map +1 -1
- package/dist/edges/index.js +1 -1
- package/dist/elements/index.cjs +78 -0
- package/dist/elements/index.cjs.map +1 -1
- package/dist/elements/index.d.cts +24 -5
- package/dist/elements/index.d.ts +24 -5
- package/dist/elements/index.js +1 -1
- package/dist/elk-QT7H4252.js +6 -0
- package/dist/elk-QT7H4252.js.map +1 -0
- package/dist/extensions/index.cjs +108 -0
- package/dist/extensions/index.cjs.map +1 -0
- package/dist/extensions/index.d.cts +145 -0
- package/dist/extensions/index.d.ts +145 -0
- package/dist/extensions/index.js +4 -0
- package/dist/extensions/index.js.map +1 -0
- package/dist/index.cjs +922 -160
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -5
- package/dist/index.d.ts +7 -5
- package/dist/index.js +6 -4
- package/dist/index.js.map +1 -1
- package/dist/layout/index.cjs +366 -90
- package/dist/layout/index.cjs.map +1 -1
- package/dist/layout/index.d.cts +4 -3
- package/dist/layout/index.d.ts +4 -3
- package/dist/layout/index.js +358 -92
- package/dist/layout/index.js.map +1 -1
- package/dist/modeling/index.cjs +387 -13
- package/dist/modeling/index.cjs.map +1 -1
- package/dist/modeling/index.d.cts +62 -4
- package/dist/modeling/index.d.ts +62 -4
- package/dist/modeling/index.js +1 -1
- package/dist/types-BX_o95GC.d.cts +40 -0
- package/dist/{types-y-ZbX-ff.d.ts → types-BYN4Zuee.d.cts} +15 -1
- package/dist/{types-y-ZbX-ff.d.cts → types-BYN4Zuee.d.ts} +15 -1
- package/dist/{types-jIDz306Y.d.cts → types-CggktCqr.d.cts} +4 -1
- package/dist/types-D7zel9dq.d.ts +40 -0
- package/dist/{types-DG5yPKld.d.ts → types-DmDODKlh.d.ts} +4 -1
- package/dist/validation/index.cjs +81 -125
- package/dist/validation/index.cjs.map +1 -1
- package/dist/validation/index.d.cts +22 -5
- package/dist/validation/index.d.ts +22 -5
- package/dist/validation/index.js +82 -126
- package/dist/validation/index.js.map +1 -1
- package/dist/xml/index.cjs +319 -49
- package/dist/xml/index.cjs.map +1 -1
- package/dist/xml/index.d.cts +5 -3
- package/dist/xml/index.d.ts +5 -3
- package/dist/xml/index.js +2 -1
- package/package.json +6 -1
- package/dist/chunk-HOWK3ZOO.js.map +0 -1
- package/dist/chunk-QSMP34CT.js.map +0 -1
- package/dist/chunk-YUE5EM3W.js.map +0 -1
- package/dist/elk-FSFIEL6O.js +0 -6
- package/dist/elk-FSFIEL6O.js.map +0 -1
- package/dist/guards-C70uIY_O.d.cts +0 -16
- package/dist/guards-foB6XIfZ.d.ts +0 -16
package/dist/validation/index.js
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
|
-
import { isDataType,
|
|
1
|
+
import { isDataType, isEventType, isGatewayType } from '../chunk-RLAJNRF2.js';
|
|
2
2
|
import { BPMN_ELEMENT_CATALOG } from '../chunk-L5Z22RLX.js';
|
|
3
3
|
|
|
4
4
|
// src/validation/index.ts
|
|
5
|
+
var hasWarnedAboutLegacyValidation = false;
|
|
6
|
+
function warnLegacyValidationOnce() {
|
|
7
|
+
if (hasWarnedAboutLegacyValidation) return;
|
|
8
|
+
hasWarnedAboutLegacyValidation = true;
|
|
9
|
+
console.warn(
|
|
10
|
+
"[@aranzatech/diagrams-bpmn/validation] validateBpmnDiagram is deprecated and now checks only structural editor invariants. Use @aranzatech/flowslint for full BPMN linting."
|
|
11
|
+
);
|
|
12
|
+
}
|
|
5
13
|
function isFlowNode(type) {
|
|
6
14
|
return isEventType(type) || isGatewayType(type) || type.includes("Task") || type === "CallActivity" || type === "SubProcess" || type === "Transaction" || type === "EventSubProcess" || type === "AdHocSubProcess" || type === "ChoreographyTask" || type === "SubChoreography" || type === "CallChoreography";
|
|
7
15
|
}
|
|
8
|
-
function isProcessNode(type) {
|
|
9
|
-
return isFlowNode(type) && type !== "BoundaryEvent";
|
|
10
|
-
}
|
|
11
|
-
function isSubProcess(type) {
|
|
12
|
-
return type === "SubProcess" || type === "Transaction" || type === "EventSubProcess" || type === "AdHocSubProcess";
|
|
13
|
-
}
|
|
14
|
-
function isCatchTarget(type) {
|
|
15
|
-
return type === "IntermediateCatchEvent" || type === "ReceiveTask";
|
|
16
|
-
}
|
|
17
16
|
function poolAncestor(node, nodeById) {
|
|
18
17
|
let current = node;
|
|
19
18
|
const visited = /* @__PURE__ */ new Set();
|
|
@@ -25,18 +24,9 @@ function poolAncestor(node, nodeById) {
|
|
|
25
24
|
}
|
|
26
25
|
return void 0;
|
|
27
26
|
}
|
|
28
|
-
function countSequenceEdges(edges, nodeId, direction) {
|
|
29
|
-
return edges.filter((edge) => {
|
|
30
|
-
if (edge.data?.edgeType !== "sequenceFlow") return false;
|
|
31
|
-
return direction === "in" ? edge.target === nodeId : edge.source === nodeId;
|
|
32
|
-
}).length;
|
|
33
|
-
}
|
|
34
27
|
function sequenceEdges(edges) {
|
|
35
28
|
return edges.filter((edge) => (edge.data?.edgeType ?? edge.type) === "sequenceFlow");
|
|
36
29
|
}
|
|
37
|
-
function sequenceOut(edges, nodeId) {
|
|
38
|
-
return sequenceEdges(edges).filter((edge) => edge.source === nodeId);
|
|
39
|
-
}
|
|
40
30
|
function sequenceIn(edges, nodeId) {
|
|
41
31
|
return sequenceEdges(edges).filter((edge) => edge.target === nodeId);
|
|
42
32
|
}
|
|
@@ -50,23 +40,10 @@ function issue(code, severity, message, elementId, relatedElementIds) {
|
|
|
50
40
|
...relatedElementIds ? { relatedElementIds } : {}
|
|
51
41
|
};
|
|
52
42
|
}
|
|
53
|
-
function validateBpmnDiagram(nodes, edges,
|
|
54
|
-
|
|
55
|
-
requireStartEvent: true,
|
|
56
|
-
requireEndEvent: true,
|
|
57
|
-
strictNames: false,
|
|
58
|
-
...options
|
|
59
|
-
};
|
|
43
|
+
function validateBpmnDiagram(nodes, edges, _options = {}) {
|
|
44
|
+
warnLegacyValidationOnce();
|
|
60
45
|
const issues = [];
|
|
61
46
|
const nodeById = new Map(nodes.map((node) => [node.id, node]));
|
|
62
|
-
const seqEdges = sequenceEdges(edges);
|
|
63
|
-
const processNodes = nodes.filter((node) => isProcessNode(node.data.elementType));
|
|
64
|
-
if (opts.requireStartEvent && !processNodes.some((node) => node.data.elementType === "StartEvent")) {
|
|
65
|
-
issues.push(issue("bpmn/start-event-required", "error", "The diagram must contain at least one start event."));
|
|
66
|
-
}
|
|
67
|
-
if (opts.requireEndEvent && !processNodes.some((node) => node.data.elementType === "EndEvent")) {
|
|
68
|
-
issues.push(issue("bpmn/end-event-required", "error", "The diagram must contain at least one end event."));
|
|
69
|
-
}
|
|
70
47
|
for (const edge of edges) {
|
|
71
48
|
const edgeType = edge.data?.edgeType ?? edge.type;
|
|
72
49
|
const source = nodeById.get(edge.source);
|
|
@@ -82,130 +59,109 @@ function validateBpmnDiagram(nodes, edges, options = {}) {
|
|
|
82
59
|
continue;
|
|
83
60
|
}
|
|
84
61
|
if (edge.source === edge.target) {
|
|
85
|
-
issues.push(
|
|
62
|
+
issues.push(
|
|
63
|
+
issue(
|
|
64
|
+
"bpmn/no-self-loop",
|
|
65
|
+
"error",
|
|
66
|
+
"BPMN edges cannot connect an element to itself.",
|
|
67
|
+
edge.id,
|
|
68
|
+
[edge.source]
|
|
69
|
+
)
|
|
70
|
+
);
|
|
86
71
|
}
|
|
87
72
|
if (edgeType === "sequenceFlow") {
|
|
88
73
|
if (!isFlowNode(source.data.elementType) || !isFlowNode(target.data.elementType) || isDataType(source.data.elementType) || isDataType(target.data.elementType)) {
|
|
89
|
-
issues.push(
|
|
74
|
+
issues.push(
|
|
75
|
+
issue(
|
|
76
|
+
"bpmn/sequence-flow-valid-endpoints",
|
|
77
|
+
"error",
|
|
78
|
+
"Sequence flows must connect BPMN flow nodes.",
|
|
79
|
+
edge.id,
|
|
80
|
+
[source.id, target.id]
|
|
81
|
+
)
|
|
82
|
+
);
|
|
90
83
|
}
|
|
91
84
|
const sourcePool = poolAncestor(source, nodeById);
|
|
92
85
|
const targetPool = poolAncestor(target, nodeById);
|
|
93
86
|
if (sourcePool && targetPool && sourcePool !== targetPool) {
|
|
94
|
-
issues.push(
|
|
87
|
+
issues.push(
|
|
88
|
+
issue(
|
|
89
|
+
"bpmn/sequence-flow-no-cross-pool",
|
|
90
|
+
"error",
|
|
91
|
+
"Sequence flows cannot cross pools. Use message flow between participants.",
|
|
92
|
+
edge.id,
|
|
93
|
+
[source.id, target.id]
|
|
94
|
+
)
|
|
95
|
+
);
|
|
95
96
|
}
|
|
96
97
|
}
|
|
97
98
|
if (edgeType === "messageFlow") {
|
|
98
99
|
const sourcePool = poolAncestor(source, nodeById);
|
|
99
100
|
const targetPool = poolAncestor(target, nodeById);
|
|
100
101
|
if (!sourcePool || !targetPool || sourcePool === targetPool) {
|
|
101
|
-
issues.push(
|
|
102
|
+
issues.push(
|
|
103
|
+
issue(
|
|
104
|
+
"bpmn/message-flow-valid-endpoints",
|
|
105
|
+
"error",
|
|
106
|
+
"Message flows must connect flow nodes in different pools.",
|
|
107
|
+
edge.id,
|
|
108
|
+
[source.id, target.id]
|
|
109
|
+
)
|
|
110
|
+
);
|
|
102
111
|
}
|
|
103
112
|
if (!isFlowNode(source.data.elementType) || !isFlowNode(target.data.elementType)) {
|
|
104
|
-
issues.push(
|
|
113
|
+
issues.push(
|
|
114
|
+
issue(
|
|
115
|
+
"bpmn/message-flow-valid-endpoints",
|
|
116
|
+
"error",
|
|
117
|
+
"Message flows must connect BPMN flow nodes, not containers.",
|
|
118
|
+
edge.id,
|
|
119
|
+
[source.id, target.id]
|
|
120
|
+
)
|
|
121
|
+
);
|
|
105
122
|
}
|
|
106
123
|
}
|
|
107
124
|
if (edgeType === "dataAssociation") {
|
|
108
125
|
const hasDataEndpoint = isDataType(source.data.elementType) || isDataType(target.data.elementType);
|
|
109
126
|
const hasFlowEndpoint = isFlowNode(source.data.elementType) || isFlowNode(target.data.elementType);
|
|
110
127
|
if (!hasDataEndpoint || !hasFlowEndpoint) {
|
|
111
|
-
issues.push(
|
|
128
|
+
issues.push(
|
|
129
|
+
issue(
|
|
130
|
+
"bpmn/data-association-valid-endpoints",
|
|
131
|
+
"error",
|
|
132
|
+
"Data associations must connect data elements with flow nodes.",
|
|
133
|
+
edge.id,
|
|
134
|
+
[source.id, target.id]
|
|
135
|
+
)
|
|
136
|
+
);
|
|
112
137
|
}
|
|
113
138
|
}
|
|
114
139
|
}
|
|
115
|
-
const duplicateSequenceKeys = /* @__PURE__ */ new Set();
|
|
116
|
-
const reportedDuplicateKeys = /* @__PURE__ */ new Set();
|
|
117
|
-
for (const edge of seqEdges) {
|
|
118
|
-
const key = `${edge.source}->${edge.target}`;
|
|
119
|
-
if (duplicateSequenceKeys.has(key) && !reportedDuplicateKeys.has(key)) {
|
|
120
|
-
reportedDuplicateKeys.add(key);
|
|
121
|
-
issues.push(issue("bpmn/no-duplicate-sequence-flow", "error", "Only one sequence flow is allowed between the same source and target.", edge.id, [edge.source, edge.target]));
|
|
122
|
-
}
|
|
123
|
-
duplicateSequenceKeys.add(key);
|
|
124
|
-
}
|
|
125
140
|
for (const node of nodes) {
|
|
126
141
|
const type = node.data.elementType;
|
|
127
|
-
const incoming = countSequenceEdges(edges, node.id, "in");
|
|
128
|
-
const outgoing = countSequenceEdges(edges, node.id, "out");
|
|
129
|
-
const meta = BPMN_ELEMENT_CATALOG[type];
|
|
130
|
-
if (type === "StartEvent" && incoming > 0) {
|
|
131
|
-
issues.push(issue("bpmn/start-event-no-incoming", "error", "Start events cannot have incoming sequence flows.", node.id));
|
|
132
|
-
}
|
|
133
|
-
if (type === "EndEvent") {
|
|
134
|
-
if (outgoing > 0) issues.push(issue("bpmn/no-outgoing-from-end-event", "error", "End events cannot have outgoing sequence flows.", node.id));
|
|
135
|
-
if (incoming === 0) issues.push(issue("bpmn/end-event-has-incoming", "error", "End events should have at least one incoming sequence flow.", node.id));
|
|
136
|
-
}
|
|
137
|
-
if ((type === "IntermediateCatchEvent" || type === "IntermediateThrowEvent") && (incoming === 0 || outgoing === 0)) {
|
|
138
|
-
issues.push(issue("bpmn/intermediate-event-both-flows", "error", "Intermediate events should have both incoming and outgoing sequence flows.", node.id));
|
|
139
|
-
}
|
|
140
142
|
if (type === "BoundaryEvent") {
|
|
141
143
|
const hostId = node.data.attachedToRef ?? node.parentId;
|
|
142
144
|
const host = hostId ? nodeById.get(hostId) : void 0;
|
|
143
145
|
if (!host || !BPMN_ELEMENT_CATALOG[host.data.elementType]?.acceptsBoundaryEvents) {
|
|
144
|
-
issues.push(
|
|
146
|
+
issues.push(
|
|
147
|
+
issue(
|
|
148
|
+
"bpmn/boundary-event-attached",
|
|
149
|
+
"error",
|
|
150
|
+
"Boundary events must be attached to an activity or subprocess.",
|
|
151
|
+
node.id,
|
|
152
|
+
hostId ? [hostId] : void 0
|
|
153
|
+
)
|
|
154
|
+
);
|
|
145
155
|
}
|
|
146
156
|
if (sequenceIn(edges, node.id).length > 0) {
|
|
147
|
-
issues.push(
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
if (outgoing === 0) issues.push(issue("bpmn/gateway-has-outgoing", "error", "Gateways should have at least one outgoing sequence flow.", node.id));
|
|
156
|
-
}
|
|
157
|
-
if (type === "ExclusiveGateway" || type === "InclusiveGateway" || type === "ComplexGateway") {
|
|
158
|
-
const outgoingEdges = sequenceOut(edges, node.id);
|
|
159
|
-
const defaults = outgoingEdges.filter((edge) => edge.data?.isDefault);
|
|
160
|
-
if (defaults.length > 1) {
|
|
161
|
-
issues.push(issue("bpmn/gateway-single-default", "error", "Gateways can have at most one default sequence flow.", node.id, defaults.map((edge) => edge.id)));
|
|
162
|
-
}
|
|
163
|
-
if (outgoingEdges.length >= 2) {
|
|
164
|
-
for (const edge of outgoingEdges) {
|
|
165
|
-
if (!edge.data?.isDefault && !edge.data?.conditionExpression) {
|
|
166
|
-
issues.push(issue("bpmn/gateway-condition", "error", "Conditional gateway branches should have a condition or be marked as default.", edge.id, [node.id, edge.target]));
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
if (type === "EventBasedGateway") {
|
|
172
|
-
const outgoingEdges = edges.filter((edge) => edge.data?.edgeType === "sequenceFlow" && edge.source === node.id);
|
|
173
|
-
if (outgoingEdges.length < 2) {
|
|
174
|
-
issues.push(issue("bpmn/event-based-gateway-min-outgoing", "error", "Event-based gateways should have at least two outgoing sequence flows.", node.id));
|
|
175
|
-
}
|
|
176
|
-
for (const edge of outgoingEdges) {
|
|
177
|
-
const target = nodeById.get(edge.target);
|
|
178
|
-
if (target && !isCatchTarget(target.data.elementType)) {
|
|
179
|
-
issues.push(issue("bpmn/event-based-gateway-valid-targets", "error", "Event-based gateways must target catch events or receive tasks.", edge.id, [node.id, target.id]));
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
if (meta.maxIncoming !== void 0 && incoming > meta.maxIncoming) {
|
|
184
|
-
issues.push(issue("bpmn/max-incoming", "error", `${type} cannot have more than ${meta.maxIncoming} incoming sequence flow(s).`, node.id));
|
|
185
|
-
}
|
|
186
|
-
if (meta.maxOutgoing !== void 0 && outgoing > meta.maxOutgoing) {
|
|
187
|
-
issues.push(issue("bpmn/max-outgoing", "error", `${type} cannot have more than ${meta.maxOutgoing} outgoing sequence flow(s).`, node.id));
|
|
188
|
-
}
|
|
189
|
-
if (opts.strictNames && (type.includes("Task") || isGatewayType(type)) && !node.data.label) {
|
|
190
|
-
issues.push(issue("bpmn/name-required", "warning", `${type} should have a label.`, node.id));
|
|
191
|
-
}
|
|
192
|
-
if (isSubProcess(type)) {
|
|
193
|
-
const childNodes = nodes.filter((child) => child.parentId === node.id);
|
|
194
|
-
if (childNodes.length > 0) {
|
|
195
|
-
if (!childNodes.some((child) => child.data.elementType === "StartEvent")) {
|
|
196
|
-
issues.push(issue("bpmn/subprocess-has-start-end", "error", "Expanded subprocesses should contain a start event.", node.id));
|
|
197
|
-
}
|
|
198
|
-
if (!childNodes.some((child) => child.data.elementType === "EndEvent")) {
|
|
199
|
-
issues.push(issue("bpmn/subprocess-has-start-end", "error", "Expanded subprocesses should contain an end event.", node.id));
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
if (type === "EventSubProcess") {
|
|
203
|
-
const starts = childNodes.filter((child) => child.data.elementType === "StartEvent");
|
|
204
|
-
for (const start of starts) {
|
|
205
|
-
if (!start.data.trigger || start.data.trigger === "none") {
|
|
206
|
-
issues.push(issue("bpmn/event-subprocess-triggered-start", "error", "Event subprocess start events must define an event trigger.", start.id, [node.id]));
|
|
207
|
-
}
|
|
208
|
-
}
|
|
157
|
+
issues.push(
|
|
158
|
+
issue(
|
|
159
|
+
"bpmn/boundary-no-incoming",
|
|
160
|
+
"error",
|
|
161
|
+
"Boundary events cannot have incoming sequence flows.",
|
|
162
|
+
node.id
|
|
163
|
+
)
|
|
164
|
+
);
|
|
209
165
|
}
|
|
210
166
|
}
|
|
211
167
|
if (type === "Lane") {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/validation/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { BPMN_ELEMENT_CATALOG } from \"../elements/catalog\";\nimport {\n isDataType,\n isEventType,\n isGatewayType,\n} from \"../elements/guards\";\nimport type { BpmnElementType } from \"../elements/types\";\nimport type { BpmnRFEdge, BpmnRFNode } from \"../xml/types\";\n\nexport type BpmnValidationSeverity = \"error\" | \"warning\" | \"info\";\n\nexport interface BpmnValidationIssue {\n id: string;\n severity: BpmnValidationSeverity;\n code: string;\n message: string;\n elementId?: string;\n relatedElementIds?: string[];\n}\n\nexport interface BpmnValidationResult {\n valid: boolean;\n issues: BpmnValidationIssue[];\n}\n\nexport interface BpmnValidationOptions {\n requireStartEvent?: boolean;\n requireEndEvent?: boolean;\n strictNames?: boolean;\n}\n\nfunction isFlowNode(type: BpmnElementType): boolean {\n return (\n isEventType(type) ||\n isGatewayType(type) ||\n type.includes(\"Task\") ||\n type === \"CallActivity\" ||\n type === \"SubProcess\" ||\n type === \"Transaction\" ||\n type === \"EventSubProcess\" ||\n type === \"AdHocSubProcess\" ||\n type === \"ChoreographyTask\" ||\n type === \"SubChoreography\" ||\n type === \"CallChoreography\"\n );\n}\n\nfunction isProcessNode(type: BpmnElementType): boolean {\n return isFlowNode(type) && type !== \"BoundaryEvent\";\n}\n\nfunction isSubProcess(type: BpmnElementType): boolean {\n return (\n type === \"SubProcess\" ||\n type === \"Transaction\" ||\n type === \"EventSubProcess\" ||\n type === \"AdHocSubProcess\"\n );\n}\n\nfunction isCatchTarget(type: BpmnElementType): boolean {\n return type === \"IntermediateCatchEvent\" || type === \"ReceiveTask\";\n}\n\nfunction poolAncestor(\n node: BpmnRFNode | undefined,\n nodeById: Map<string, BpmnRFNode>,\n): string | undefined {\n let current = node;\n const visited = new Set<string>();\n while (current?.parentId && !visited.has(current.id)) {\n visited.add(current.id);\n const parent = nodeById.get(current.parentId);\n if (parent?.data.elementType === \"Pool\") return parent.id;\n current = parent;\n }\n return undefined;\n}\n\nfunction countSequenceEdges(edges: BpmnRFEdge[], nodeId: string, direction: \"in\" | \"out\"): number {\n return edges.filter((edge) => {\n if (edge.data?.edgeType !== \"sequenceFlow\") return false;\n return direction === \"in\" ? edge.target === nodeId : edge.source === nodeId;\n }).length;\n}\n\nfunction sequenceEdges(edges: BpmnRFEdge[]): BpmnRFEdge[] {\n return edges.filter((edge) => (edge.data?.edgeType ?? edge.type) === \"sequenceFlow\");\n}\n\nfunction sequenceOut(edges: BpmnRFEdge[], nodeId: string): BpmnRFEdge[] {\n return sequenceEdges(edges).filter((edge) => edge.source === nodeId);\n}\n\nfunction sequenceIn(edges: BpmnRFEdge[], nodeId: string): BpmnRFEdge[] {\n return sequenceEdges(edges).filter((edge) => edge.target === nodeId);\n}\n\nfunction issue(\n code: string,\n severity: BpmnValidationSeverity,\n message: string,\n elementId?: string,\n relatedElementIds?: string[],\n): BpmnValidationIssue {\n return {\n id: `${code}:${elementId ?? relatedElementIds?.join(\",\") ?? \"diagram\"}`,\n code,\n severity,\n message,\n ...(elementId ? { elementId } : {}),\n ...(relatedElementIds ? { relatedElementIds } : {}),\n };\n}\n\n/**\n * @deprecated Use `@aranzatech/flowslint` with `runBpmnLint` instead.\n * This function will be removed in v0.4.0.\n * Import it from the `/validation` subpath if you still need it temporarily.\n */\nexport function validateBpmnDiagram(\n nodes: BpmnRFNode[],\n edges: BpmnRFEdge[],\n options: BpmnValidationOptions = {},\n): BpmnValidationResult {\n const opts = {\n requireStartEvent: true,\n requireEndEvent: true,\n strictNames: false,\n ...options,\n };\n const issues: BpmnValidationIssue[] = [];\n const nodeById = new Map(nodes.map((node) => [node.id, node]));\n const seqEdges = sequenceEdges(edges);\n\n const processNodes = nodes.filter((node) => isProcessNode(node.data.elementType));\n if (opts.requireStartEvent && !processNodes.some((node) => node.data.elementType === \"StartEvent\")) {\n issues.push(issue(\"bpmn/start-event-required\", \"error\", \"The diagram must contain at least one start event.\"));\n }\n if (opts.requireEndEvent && !processNodes.some((node) => node.data.elementType === \"EndEvent\")) {\n issues.push(issue(\"bpmn/end-event-required\", \"error\", \"The diagram must contain at least one end event.\"));\n }\n\n for (const edge of edges) {\n const edgeType = edge.data?.edgeType ?? edge.type;\n const source = nodeById.get(edge.source);\n const target = nodeById.get(edge.target);\n\n if (!source || !target) {\n issues.push(issue(\n \"bpmn/no-orphan-edges\",\n \"error\",\n `Edge \"${edge.id}\" references a missing ${!source ? \"source\" : \"target\"} node.`,\n edge.id,\n [edge.source, edge.target],\n ));\n continue;\n }\n\n if (edge.source === edge.target) {\n issues.push(issue(\"bpmn/no-self-loop\", \"error\", \"BPMN edges cannot connect an element to itself.\", edge.id, [edge.source]));\n }\n\n if (edgeType === \"sequenceFlow\") {\n if (!isFlowNode(source.data.elementType) || !isFlowNode(target.data.elementType) || isDataType(source.data.elementType) || isDataType(target.data.elementType)) {\n issues.push(issue(\"bpmn/sequence-flow-valid-endpoints\", \"error\", \"Sequence flows must connect BPMN flow nodes.\", edge.id, [source.id, target.id]));\n }\n const sourcePool = poolAncestor(source, nodeById);\n const targetPool = poolAncestor(target, nodeById);\n if (sourcePool && targetPool && sourcePool !== targetPool) {\n issues.push(issue(\"bpmn/sequence-flow-no-cross-pool\", \"error\", \"Sequence flows cannot cross pools. Use message flow between participants.\", edge.id, [source.id, target.id]));\n }\n }\n\n if (edgeType === \"messageFlow\") {\n const sourcePool = poolAncestor(source, nodeById);\n const targetPool = poolAncestor(target, nodeById);\n if (!sourcePool || !targetPool || sourcePool === targetPool) {\n issues.push(issue(\"bpmn/message-flow-valid-endpoints\", \"error\", \"Message flows must connect flow nodes in different pools.\", edge.id, [source.id, target.id]));\n }\n if (!isFlowNode(source.data.elementType) || !isFlowNode(target.data.elementType)) {\n issues.push(issue(\"bpmn/message-flow-valid-endpoints\", \"error\", \"Message flows must connect BPMN flow nodes, not containers.\", edge.id, [source.id, target.id]));\n }\n }\n\n if (edgeType === \"dataAssociation\") {\n const hasDataEndpoint = isDataType(source.data.elementType) || isDataType(target.data.elementType);\n const hasFlowEndpoint = isFlowNode(source.data.elementType) || isFlowNode(target.data.elementType);\n if (!hasDataEndpoint || !hasFlowEndpoint) {\n issues.push(issue(\"bpmn/data-association-valid-endpoints\", \"error\", \"Data associations must connect data elements with flow nodes.\", edge.id, [source.id, target.id]));\n }\n }\n }\n\n const duplicateSequenceKeys = new Set<string>();\n const reportedDuplicateKeys = new Set<string>();\n for (const edge of seqEdges) {\n const key = `${edge.source}->${edge.target}`;\n if (duplicateSequenceKeys.has(key) && !reportedDuplicateKeys.has(key)) {\n reportedDuplicateKeys.add(key);\n issues.push(issue(\"bpmn/no-duplicate-sequence-flow\", \"error\", \"Only one sequence flow is allowed between the same source and target.\", edge.id, [edge.source, edge.target]));\n }\n duplicateSequenceKeys.add(key);\n }\n\n for (const node of nodes) {\n const type = node.data.elementType;\n const incoming = countSequenceEdges(edges, node.id, \"in\");\n const outgoing = countSequenceEdges(edges, node.id, \"out\");\n const meta = BPMN_ELEMENT_CATALOG[type];\n\n if (type === \"StartEvent\" && incoming > 0) {\n issues.push(issue(\"bpmn/start-event-no-incoming\", \"error\", \"Start events cannot have incoming sequence flows.\", node.id));\n }\n if (type === \"EndEvent\") {\n if (outgoing > 0) issues.push(issue(\"bpmn/no-outgoing-from-end-event\", \"error\", \"End events cannot have outgoing sequence flows.\", node.id));\n if (incoming === 0) issues.push(issue(\"bpmn/end-event-has-incoming\", \"error\", \"End events should have at least one incoming sequence flow.\", node.id));\n }\n if ((type === \"IntermediateCatchEvent\" || type === \"IntermediateThrowEvent\") && (incoming === 0 || outgoing === 0)) {\n issues.push(issue(\"bpmn/intermediate-event-both-flows\", \"error\", \"Intermediate events should have both incoming and outgoing sequence flows.\", node.id));\n }\n if (type === \"BoundaryEvent\") {\n const hostId = node.data.attachedToRef ?? node.parentId;\n const host = hostId ? nodeById.get(hostId) : undefined;\n if (!host || !BPMN_ELEMENT_CATALOG[host.data.elementType]?.acceptsBoundaryEvents) {\n issues.push(issue(\"bpmn/boundary-event-attached\", \"error\", \"Boundary events must be attached to an activity or subprocess.\", node.id, hostId ? [hostId] : undefined));\n }\n if (sequenceIn(edges, node.id).length > 0) {\n issues.push(issue(\"bpmn/boundary-no-incoming\", \"error\", \"Boundary events cannot have incoming sequence flows.\", node.id));\n }\n if (sequenceOut(edges, node.id).length === 0) {\n issues.push(issue(\"bpmn/boundary-has-outgoing\", \"warning\", \"Boundary events should define an outgoing exception path.\", node.id));\n }\n }\n if (isGatewayType(type)) {\n if (incoming === 0) issues.push(issue(\"bpmn/gateway-has-incoming\", \"error\", \"Gateways should have at least one incoming sequence flow.\", node.id));\n if (outgoing === 0) issues.push(issue(\"bpmn/gateway-has-outgoing\", \"error\", \"Gateways should have at least one outgoing sequence flow.\", node.id));\n }\n if (type === \"ExclusiveGateway\" || type === \"InclusiveGateway\" || type === \"ComplexGateway\") {\n const outgoingEdges = sequenceOut(edges, node.id);\n const defaults = outgoingEdges.filter((edge) => edge.data?.isDefault);\n if (defaults.length > 1) {\n issues.push(issue(\"bpmn/gateway-single-default\", \"error\", \"Gateways can have at most one default sequence flow.\", node.id, defaults.map((edge) => edge.id)));\n }\n if (outgoingEdges.length >= 2) {\n for (const edge of outgoingEdges) {\n if (!edge.data?.isDefault && !edge.data?.conditionExpression) {\n issues.push(issue(\"bpmn/gateway-condition\", \"error\", \"Conditional gateway branches should have a condition or be marked as default.\", edge.id, [node.id, edge.target]));\n }\n }\n }\n }\n if (type === \"EventBasedGateway\") {\n const outgoingEdges = edges.filter((edge) => edge.data?.edgeType === \"sequenceFlow\" && edge.source === node.id);\n if (outgoingEdges.length < 2) {\n issues.push(issue(\"bpmn/event-based-gateway-min-outgoing\", \"error\", \"Event-based gateways should have at least two outgoing sequence flows.\", node.id));\n }\n for (const edge of outgoingEdges) {\n const target = nodeById.get(edge.target);\n if (target && !isCatchTarget(target.data.elementType)) {\n issues.push(issue(\"bpmn/event-based-gateway-valid-targets\", \"error\", \"Event-based gateways must target catch events or receive tasks.\", edge.id, [node.id, target.id]));\n }\n }\n }\n if (meta.maxIncoming !== undefined && incoming > meta.maxIncoming) {\n issues.push(issue(\"bpmn/max-incoming\", \"error\", `${type} cannot have more than ${meta.maxIncoming} incoming sequence flow(s).`, node.id));\n }\n if (meta.maxOutgoing !== undefined && outgoing > meta.maxOutgoing) {\n issues.push(issue(\"bpmn/max-outgoing\", \"error\", `${type} cannot have more than ${meta.maxOutgoing} outgoing sequence flow(s).`, node.id));\n }\n if (opts.strictNames && (type.includes(\"Task\") || isGatewayType(type)) && !node.data.label) {\n issues.push(issue(\"bpmn/name-required\", \"warning\", `${type} should have a label.`, node.id));\n }\n if (isSubProcess(type)) {\n const childNodes = nodes.filter((child) => child.parentId === node.id);\n if (childNodes.length > 0) {\n if (!childNodes.some((child) => child.data.elementType === \"StartEvent\")) {\n issues.push(issue(\"bpmn/subprocess-has-start-end\", \"error\", \"Expanded subprocesses should contain a start event.\", node.id));\n }\n if (!childNodes.some((child) => child.data.elementType === \"EndEvent\")) {\n issues.push(issue(\"bpmn/subprocess-has-start-end\", \"error\", \"Expanded subprocesses should contain an end event.\", node.id));\n }\n }\n if (type === \"EventSubProcess\") {\n const starts = childNodes.filter((child) => child.data.elementType === \"StartEvent\");\n for (const start of starts) {\n if (!start.data.trigger || start.data.trigger === \"none\") {\n issues.push(issue(\"bpmn/event-subprocess-triggered-start\", \"error\", \"Event subprocess start events must define an event trigger.\", start.id, [node.id]));\n }\n }\n }\n }\n if (type === \"Lane\") {\n const parent = node.parentId ? nodeById.get(node.parentId) : undefined;\n if (parent?.data.elementType !== \"Pool\") {\n issues.push(issue(\"bpmn/lane-parent-pool\", \"error\", \"Lanes must be contained by a pool.\", node.id));\n }\n }\n }\n\n return {\n valid: issues.every((item) => item.severity !== \"error\"),\n issues,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/validation/index.ts"],"names":[],"mappings":";;;;AAiCA,IAAI,8BAAA,GAAiC,KAAA;AAErC,SAAS,wBAAA,GAAiC;AACxC,EAAA,IAAI,8BAAA,EAAgC;AACpC,EAAA,8BAAA,GAAiC,IAAA;AACjC,EAAA,OAAA,CAAQ,IAAA;AAAA,IACN;AAAA,GACF;AACF;AAEA,SAAS,WAAW,IAAA,EAAgC;AAClD,EAAA,OACE,WAAA,CAAY,IAAI,CAAA,IAChB,aAAA,CAAc,IAAI,KAClB,IAAA,CAAK,QAAA,CAAS,MAAM,CAAA,IACpB,IAAA,KAAS,cAAA,IACT,SAAS,YAAA,IACT,IAAA,KAAS,aAAA,IACT,IAAA,KAAS,iBAAA,IACT,IAAA,KAAS,qBACT,IAAA,KAAS,kBAAA,IACT,IAAA,KAAS,iBAAA,IACT,IAAA,KAAS,kBAAA;AAEb;AAEA,SAAS,YAAA,CACP,MACA,QAAA,EACoB;AACpB,EAAA,IAAI,OAAA,GAAU,IAAA;AACd,EAAA,MAAM,OAAA,uBAAc,GAAA,EAAY;AAChC,EAAA,OAAO,SAAS,QAAA,IAAY,CAAC,QAAQ,GAAA,CAAI,OAAA,CAAQ,EAAE,CAAA,EAAG;AACpD,IAAA,OAAA,CAAQ,GAAA,CAAI,QAAQ,EAAE,CAAA;AACtB,IAAA,MAAM,MAAA,GAAS,QAAA,CAAS,GAAA,CAAI,OAAA,CAAQ,QAAQ,CAAA;AAC5C,IAAA,IAAI,MAAA,EAAQ,IAAA,CAAK,WAAA,KAAgB,MAAA,SAAe,MAAA,CAAO,EAAA;AACvD,IAAA,OAAA,GAAU,MAAA;AAAA,EACZ;AACA,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,cAAc,KAAA,EAAmC;AACxD,EAAA,OAAO,KAAA,CAAM,OAAO,CAAC,IAAA,KAAA,CAAU,KAAK,IAAA,EAAM,QAAA,IAAY,IAAA,CAAK,IAAA,MAAU,cAAc,CAAA;AACrF;AAEA,SAAS,UAAA,CAAW,OAAqB,MAAA,EAA8B;AACrE,EAAA,OAAO,aAAA,CAAc,KAAK,CAAA,CAAE,MAAA,CAAO,CAAC,IAAA,KAAS,IAAA,CAAK,WAAW,MAAM,CAAA;AACrE;AAEA,SAAS,KAAA,CACP,IAAA,EACA,QAAA,EACA,OAAA,EACA,WACA,iBAAA,EACqB;AACrB,EAAA,OAAO;AAAA,IACL,EAAA,EAAI,GAAG,IAAI,CAAA,CAAA,EAAI,aAAa,iBAAA,EAAmB,IAAA,CAAK,GAAG,CAAA,IAAK,SAAS,CAAA,CAAA;AAAA,IACrE,IAAA;AAAA,IACA,QAAA;AAAA,IACA,OAAA;AAAA,IACA,GAAI,SAAA,GAAY,EAAE,SAAA,KAAc,EAAC;AAAA,IACjC,GAAI,iBAAA,GAAoB,EAAE,iBAAA,KAAsB;AAAC,GACnD;AACF;AAiBO,SAAS,mBAAA,CACd,KAAA,EACA,KAAA,EACA,QAAA,GAAkC,EAAC,EACb;AACtB,EAAA,wBAAA,EAAyB;AAEzB,EAAA,MAAM,SAAgC,EAAC;AACvC,EAAA,MAAM,QAAA,GAAW,IAAI,GAAA,CAAI,KAAA,CAAM,GAAA,CAAI,CAAC,IAAA,KAAS,CAAC,IAAA,CAAK,EAAA,EAAI,IAAI,CAAC,CAAC,CAAA;AAE7D,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,IAAA,EAAM,QAAA,IAAY,IAAA,CAAK,IAAA;AAC7C,IAAA,MAAM,MAAA,GAAS,QAAA,CAAS,GAAA,CAAI,IAAA,CAAK,MAAM,CAAA;AACvC,IAAA,MAAM,MAAA,GAAS,QAAA,CAAS,GAAA,CAAI,IAAA,CAAK,MAAM,CAAA;AAEvC,IAAA,IAAI,CAAC,MAAA,IAAU,CAAC,MAAA,EAAQ;AACtB,MAAA,MAAA,CAAO,IAAA,CAAK,KAAA;AAAA,QACV,sBAAA;AAAA,QACA,OAAA;AAAA,QACA,SAAS,IAAA,CAAK,EAAE,0BAA0B,CAAC,MAAA,GAAS,WAAW,QAAQ,CAAA,MAAA,CAAA;AAAA,QACvE,IAAA,CAAK,EAAA;AAAA,QACL,CAAC,IAAA,CAAK,MAAA,EAAQ,IAAA,CAAK,MAAM;AAAA,OAC1B,CAAA;AACD,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,IAAA,CAAK,MAAA,KAAW,IAAA,CAAK,MAAA,EAAQ;AAC/B,MAAA,MAAA,CAAO,IAAA;AAAA,QACL,KAAA;AAAA,UACE,mBAAA;AAAA,UACA,OAAA;AAAA,UACA,iDAAA;AAAA,UACA,IAAA,CAAK,EAAA;AAAA,UACL,CAAC,KAAK,MAAM;AAAA;AACd,OACF;AAAA,IACF;AAEA,IAAA,IAAI,aAAa,cAAA,EAAgB;AAC/B,MAAA,IACE,CAAC,WAAW,MAAA,CAAO,IAAA,CAAK,WAAW,CAAA,IACnC,CAAC,WAAW,MAAA,CAAO,IAAA,CAAK,WAAW,CAAA,IACnC,UAAA,CAAW,OAAO,IAAA,CAAK,WAAW,KAClC,UAAA,CAAW,MAAA,CAAO,IAAA,CAAK,WAAW,CAAA,EAClC;AACA,QAAA,MAAA,CAAO,IAAA;AAAA,UACL,KAAA;AAAA,YACE,oCAAA;AAAA,YACA,OAAA;AAAA,YACA,8CAAA;AAAA,YACA,IAAA,CAAK,EAAA;AAAA,YACL,CAAC,MAAA,CAAO,EAAA,EAAI,MAAA,CAAO,EAAE;AAAA;AACvB,SACF;AAAA,MACF;AAEA,MAAA,MAAM,UAAA,GAAa,YAAA,CAAa,MAAA,EAAQ,QAAQ,CAAA;AAChD,MAAA,MAAM,UAAA,GAAa,YAAA,CAAa,MAAA,EAAQ,QAAQ,CAAA;AAChD,MAAA,IAAI,UAAA,IAAc,UAAA,IAAc,UAAA,KAAe,UAAA,EAAY;AACzD,QAAA,MAAA,CAAO,IAAA;AAAA,UACL,KAAA;AAAA,YACE,kCAAA;AAAA,YACA,OAAA;AAAA,YACA,2EAAA;AAAA,YACA,IAAA,CAAK,EAAA;AAAA,YACL,CAAC,MAAA,CAAO,EAAA,EAAI,MAAA,CAAO,EAAE;AAAA;AACvB,SACF;AAAA,MACF;AAAA,IACF;AAEA,IAAA,IAAI,aAAa,aAAA,EAAe;AAC9B,MAAA,MAAM,UAAA,GAAa,YAAA,CAAa,MAAA,EAAQ,QAAQ,CAAA;AAChD,MAAA,MAAM,UAAA,GAAa,YAAA,CAAa,MAAA,EAAQ,QAAQ,CAAA;AAChD,MAAA,IAAI,CAAC,UAAA,IAAc,CAAC,UAAA,IAAc,eAAe,UAAA,EAAY;AAC3D,QAAA,MAAA,CAAO,IAAA;AAAA,UACL,KAAA;AAAA,YACE,mCAAA;AAAA,YACA,OAAA;AAAA,YACA,2DAAA;AAAA,YACA,IAAA,CAAK,EAAA;AAAA,YACL,CAAC,MAAA,CAAO,EAAA,EAAI,MAAA,CAAO,EAAE;AAAA;AACvB,SACF;AAAA,MACF;AACA,MAAA,IAAI,CAAC,UAAA,CAAW,MAAA,CAAO,IAAA,CAAK,WAAW,CAAA,IAAK,CAAC,UAAA,CAAW,MAAA,CAAO,IAAA,CAAK,WAAW,CAAA,EAAG;AAChF,QAAA,MAAA,CAAO,IAAA;AAAA,UACL,KAAA;AAAA,YACE,mCAAA;AAAA,YACA,OAAA;AAAA,YACA,6DAAA;AAAA,YACA,IAAA,CAAK,EAAA;AAAA,YACL,CAAC,MAAA,CAAO,EAAA,EAAI,MAAA,CAAO,EAAE;AAAA;AACvB,SACF;AAAA,MACF;AAAA,IACF;AAEA,IAAA,IAAI,aAAa,iBAAA,EAAmB;AAClC,MAAA,MAAM,eAAA,GAAkB,WAAW,MAAA,CAAO,IAAA,CAAK,WAAW,CAAA,IAAK,UAAA,CAAW,MAAA,CAAO,IAAA,CAAK,WAAW,CAAA;AACjG,MAAA,MAAM,eAAA,GAAkB,WAAW,MAAA,CAAO,IAAA,CAAK,WAAW,CAAA,IAAK,UAAA,CAAW,MAAA,CAAO,IAAA,CAAK,WAAW,CAAA;AACjG,MAAA,IAAI,CAAC,eAAA,IAAmB,CAAC,eAAA,EAAiB;AACxC,QAAA,MAAA,CAAO,IAAA;AAAA,UACL,KAAA;AAAA,YACE,uCAAA;AAAA,YACA,OAAA;AAAA,YACA,+DAAA;AAAA,YACA,IAAA,CAAK,EAAA;AAAA,YACL,CAAC,MAAA,CAAO,EAAA,EAAI,MAAA,CAAO,EAAE;AAAA;AACvB,SACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,IAAA,MAAM,IAAA,GAAO,KAAK,IAAA,CAAK,WAAA;AAEvB,IAAA,IAAI,SAAS,eAAA,EAAiB;AAC5B,MAAA,MAAM,MAAA,GAAS,IAAA,CAAK,IAAA,CAAK,aAAA,IAAiB,IAAA,CAAK,QAAA;AAC/C,MAAA,MAAM,IAAA,GAAO,MAAA,GAAS,QAAA,CAAS,GAAA,CAAI,MAAM,CAAA,GAAI,MAAA;AAC7C,MAAA,IAAI,CAAC,QAAQ,CAAC,oBAAA,CAAqB,KAAK,IAAA,CAAK,WAAW,GAAG,qBAAA,EAAuB;AAChF,QAAA,MAAA,CAAO,IAAA;AAAA,UACL,KAAA;AAAA,YACE,8BAAA;AAAA,YACA,OAAA;AAAA,YACA,gEAAA;AAAA,YACA,IAAA,CAAK,EAAA;AAAA,YACL,MAAA,GAAS,CAAC,MAAM,CAAA,GAAI;AAAA;AACtB,SACF;AAAA,MACF;AACA,MAAA,IAAI,WAAW,KAAA,EAAO,IAAA,CAAK,EAAE,CAAA,CAAE,SAAS,CAAA,EAAG;AACzC,QAAA,MAAA,CAAO,IAAA;AAAA,UACL,KAAA;AAAA,YACE,2BAAA;AAAA,YACA,OAAA;AAAA,YACA,sDAAA;AAAA,YACA,IAAA,CAAK;AAAA;AACP,SACF;AAAA,MACF;AAAA,IACF;AAEA,IAAA,IAAI,SAAS,MAAA,EAAQ;AACnB,MAAA,MAAM,SAAS,IAAA,CAAK,QAAA,GAAW,SAAS,GAAA,CAAI,IAAA,CAAK,QAAQ,CAAA,GAAI,MAAA;AAC7D,MAAA,IAAI,MAAA,EAAQ,IAAA,CAAK,WAAA,KAAgB,MAAA,EAAQ;AACvC,QAAA,MAAA,CAAO,KAAK,KAAA,CAAM,uBAAA,EAAyB,SAAS,oCAAA,EAAsC,IAAA,CAAK,EAAE,CAAC,CAAA;AAAA,MACpG;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,OAAO,MAAA,CAAO,KAAA,CAAM,CAAC,IAAA,KAAS,IAAA,CAAK,aAAa,OAAO,CAAA;AAAA,IACvD;AAAA,GACF;AACF","file":"index.js","sourcesContent":["import { BPMN_ELEMENT_CATALOG } from \"../elements/catalog\";\nimport { isDataType, isEventType, isGatewayType } from \"../elements/guards\";\nimport type { BpmnElementType } from \"../elements/types\";\nimport type { BpmnRFEdge, BpmnRFNode } from \"../xml/types\";\n\nexport type BpmnValidationSeverity = \"error\" | \"warning\" | \"info\";\n\nexport interface BpmnValidationIssue {\n id: string;\n severity: BpmnValidationSeverity;\n code: string;\n message: string;\n elementId?: string;\n relatedElementIds?: string[];\n}\n\nexport interface BpmnValidationResult {\n valid: boolean;\n issues: BpmnValidationIssue[];\n}\n\n/**\n * @deprecated Legacy compatibility options.\n * `validateBpmnDiagram` now enforces only editor-safe structural invariants.\n * Use `@aranzatech/flowslint` for semantic BPMN rules such as start/end events,\n * gateway branching, reachability and naming conventions.\n */\nexport interface BpmnValidationOptions {\n requireStartEvent?: boolean;\n requireEndEvent?: boolean;\n strictNames?: boolean;\n}\n\nlet hasWarnedAboutLegacyValidation = false;\n\nfunction warnLegacyValidationOnce(): void {\n if (hasWarnedAboutLegacyValidation) return;\n hasWarnedAboutLegacyValidation = true;\n console.warn(\n \"[@aranzatech/diagrams-bpmn/validation] validateBpmnDiagram is deprecated and now checks only structural editor invariants. Use @aranzatech/flowslint for full BPMN linting.\",\n );\n}\n\nfunction isFlowNode(type: BpmnElementType): boolean {\n return (\n isEventType(type) ||\n isGatewayType(type) ||\n type.includes(\"Task\") ||\n type === \"CallActivity\" ||\n type === \"SubProcess\" ||\n type === \"Transaction\" ||\n type === \"EventSubProcess\" ||\n type === \"AdHocSubProcess\" ||\n type === \"ChoreographyTask\" ||\n type === \"SubChoreography\" ||\n type === \"CallChoreography\"\n );\n}\n\nfunction poolAncestor(\n node: BpmnRFNode | undefined,\n nodeById: Map<string, BpmnRFNode>,\n): string | undefined {\n let current = node;\n const visited = new Set<string>();\n while (current?.parentId && !visited.has(current.id)) {\n visited.add(current.id);\n const parent = nodeById.get(current.parentId);\n if (parent?.data.elementType === \"Pool\") return parent.id;\n current = parent;\n }\n return undefined;\n}\n\nfunction sequenceEdges(edges: BpmnRFEdge[]): BpmnRFEdge[] {\n return edges.filter((edge) => (edge.data?.edgeType ?? edge.type) === \"sequenceFlow\");\n}\n\nfunction sequenceIn(edges: BpmnRFEdge[], nodeId: string): BpmnRFEdge[] {\n return sequenceEdges(edges).filter((edge) => edge.target === nodeId);\n}\n\nfunction issue(\n code: string,\n severity: BpmnValidationSeverity,\n message: string,\n elementId?: string,\n relatedElementIds?: string[],\n): BpmnValidationIssue {\n return {\n id: `${code}:${elementId ?? relatedElementIds?.join(\",\") ?? \"diagram\"}`,\n code,\n severity,\n message,\n ...(elementId ? { elementId } : {}),\n ...(relatedElementIds ? { relatedElementIds } : {}),\n };\n}\n\n/**\n * @deprecated Use `@aranzatech/flowslint` with `runBpmnLint` instead.\n *\n * This compatibility validator intentionally covers only structural invariants\n * required for safe BPMN editing:\n * - edges must reference existing nodes\n * - edges cannot self-loop\n * - sequence/message/data associations must use structurally valid endpoints\n * - sequence flows cannot cross pools\n * - boundary events must be attached to a valid host and cannot have incoming sequence flows\n * - lanes must belong to pools\n *\n * It no longer duplicates semantic BPMN linting such as required start/end\n * events, gateway branching quality, reachability or naming conventions.\n */\nexport function validateBpmnDiagram(\n nodes: BpmnRFNode[],\n edges: BpmnRFEdge[],\n _options: BpmnValidationOptions = {},\n): BpmnValidationResult {\n warnLegacyValidationOnce();\n\n const issues: BpmnValidationIssue[] = [];\n const nodeById = new Map(nodes.map((node) => [node.id, node]));\n\n for (const edge of edges) {\n const edgeType = edge.data?.edgeType ?? edge.type;\n const source = nodeById.get(edge.source);\n const target = nodeById.get(edge.target);\n\n if (!source || !target) {\n issues.push(issue(\n \"bpmn/no-orphan-edges\",\n \"error\",\n `Edge \"${edge.id}\" references a missing ${!source ? \"source\" : \"target\"} node.`,\n edge.id,\n [edge.source, edge.target],\n ));\n continue;\n }\n\n if (edge.source === edge.target) {\n issues.push(\n issue(\n \"bpmn/no-self-loop\",\n \"error\",\n \"BPMN edges cannot connect an element to itself.\",\n edge.id,\n [edge.source],\n ),\n );\n }\n\n if (edgeType === \"sequenceFlow\") {\n if (\n !isFlowNode(source.data.elementType) ||\n !isFlowNode(target.data.elementType) ||\n isDataType(source.data.elementType) ||\n isDataType(target.data.elementType)\n ) {\n issues.push(\n issue(\n \"bpmn/sequence-flow-valid-endpoints\",\n \"error\",\n \"Sequence flows must connect BPMN flow nodes.\",\n edge.id,\n [source.id, target.id],\n ),\n );\n }\n\n const sourcePool = poolAncestor(source, nodeById);\n const targetPool = poolAncestor(target, nodeById);\n if (sourcePool && targetPool && sourcePool !== targetPool) {\n issues.push(\n issue(\n \"bpmn/sequence-flow-no-cross-pool\",\n \"error\",\n \"Sequence flows cannot cross pools. Use message flow between participants.\",\n edge.id,\n [source.id, target.id],\n ),\n );\n }\n }\n\n if (edgeType === \"messageFlow\") {\n const sourcePool = poolAncestor(source, nodeById);\n const targetPool = poolAncestor(target, nodeById);\n if (!sourcePool || !targetPool || sourcePool === targetPool) {\n issues.push(\n issue(\n \"bpmn/message-flow-valid-endpoints\",\n \"error\",\n \"Message flows must connect flow nodes in different pools.\",\n edge.id,\n [source.id, target.id],\n ),\n );\n }\n if (!isFlowNode(source.data.elementType) || !isFlowNode(target.data.elementType)) {\n issues.push(\n issue(\n \"bpmn/message-flow-valid-endpoints\",\n \"error\",\n \"Message flows must connect BPMN flow nodes, not containers.\",\n edge.id,\n [source.id, target.id],\n ),\n );\n }\n }\n\n if (edgeType === \"dataAssociation\") {\n const hasDataEndpoint = isDataType(source.data.elementType) || isDataType(target.data.elementType);\n const hasFlowEndpoint = isFlowNode(source.data.elementType) || isFlowNode(target.data.elementType);\n if (!hasDataEndpoint || !hasFlowEndpoint) {\n issues.push(\n issue(\n \"bpmn/data-association-valid-endpoints\",\n \"error\",\n \"Data associations must connect data elements with flow nodes.\",\n edge.id,\n [source.id, target.id],\n ),\n );\n }\n }\n }\n\n for (const node of nodes) {\n const type = node.data.elementType;\n\n if (type === \"BoundaryEvent\") {\n const hostId = node.data.attachedToRef ?? node.parentId;\n const host = hostId ? nodeById.get(hostId) : undefined;\n if (!host || !BPMN_ELEMENT_CATALOG[host.data.elementType]?.acceptsBoundaryEvents) {\n issues.push(\n issue(\n \"bpmn/boundary-event-attached\",\n \"error\",\n \"Boundary events must be attached to an activity or subprocess.\",\n node.id,\n hostId ? [hostId] : undefined,\n ),\n );\n }\n if (sequenceIn(edges, node.id).length > 0) {\n issues.push(\n issue(\n \"bpmn/boundary-no-incoming\",\n \"error\",\n \"Boundary events cannot have incoming sequence flows.\",\n node.id,\n ),\n );\n }\n }\n\n if (type === \"Lane\") {\n const parent = node.parentId ? nodeById.get(node.parentId) : undefined;\n if (parent?.data.elementType !== \"Pool\") {\n issues.push(issue(\"bpmn/lane-parent-pool\", \"error\", \"Lanes must be contained by a pool.\", node.id));\n }\n }\n }\n\n return {\n valid: issues.every((item) => item.severity !== \"error\"),\n issues,\n };\n}\n"]}
|