Skip to content

Commit

Permalink
feat: add ad-hoc-sub-process rule
Browse files Browse the repository at this point in the history
Verify that an ad-hoc sub-process only contains valid elements:

* Does not contain start or end events.
* Every intermediate event has an outgoing sequence flow.

Related to camunda/camunda-modeler#4811
  • Loading branch information
jarekdanielak committed Feb 14, 2025
1 parent a0cf881 commit 50bcc92
Show file tree
Hide file tree
Showing 14 changed files with 410 additions and 56 deletions.
1 change: 1 addition & 0 deletions config/all.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const allRules = [
'ad-hoc-sub-process',
'conditional-flows',
'end-event-required',
'event-sub-process-typed-start-event',
Expand Down
1 change: 1 addition & 0 deletions config/recommended.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module.exports = {
rules: {
'ad-hoc-sub-process': 'error',
'conditional-flows': 'error',
'end-event-required': 'error',
'event-sub-process-typed-start-event': 'error',
Expand Down
1 change: 1 addition & 0 deletions docs/rules/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

This library implements the following lint rules:

* [Ad-hoc Sub-Process](./ad-hoc-sub-process.md)
* [Conditional Flows](./conditional-flows.md)
* [End Event Required](./end-event-required.md)
* [Event Sub-Process Typed Start Event](./event-sub-process-typed-start-event.md)
Expand Down
20 changes: 20 additions & 0 deletions docs/rules/ad-hoc-sub-process.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Ad-hoc Sub-Process (ad-hoc-sub-process)

Ensure that an Ad-Hoc Sub-Process is valid according to the BPMN specification:

- Does not contain start or end events.
- Every intermediate event has an outgoing sequence flow.


Example of __incorrect__ usage for this rule:

![Incorrect usage example](./examples/ad-hoc-sub-process-incorrect.png)

Cf. [`ad-hoc-sub-process-incorrect.bpmn`](./examples/no-complex-gateway-incorrect.bpmn).


Example of __correct__ usage for this rule:

![Correct usage example](./examples/ad-hoc-sub-process-correct.png)

Cf. [`ad-hoc-sub-process-correct.bpmn`](./examples/no-complex-gateway-correct.bpmn).
62 changes: 62 additions & 0 deletions docs/rules/examples/ad-hoc-sub-process-correct.bpmn
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_1ntx4rf" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.32.0">
<bpmn:process id="Process_1" isExecutable="true">
<bpmn:adHocSubProcess id="SubProcess_0zz45ap" name="Ad-hoc subprocess">
<bpmn:intermediateCatchEvent id="Event_0fkph5i">
<bpmn:outgoing>Flow_0ki1200</bpmn:outgoing>
<bpmn:linkEventDefinition id="LinkEventDefinition_0o8x64t" name="" />
</bpmn:intermediateCatchEvent>
<bpmn:intermediateThrowEvent id="Event_16c5xe9">
<bpmn:outgoing>Flow_0togudw</bpmn:outgoing>
</bpmn:intermediateThrowEvent>
<bpmn:task id="Activity_0d8s2mi" />
<bpmn:task id="Activity_1dnnvam">
<bpmn:incoming>Flow_0togudw</bpmn:incoming>
</bpmn:task>
<bpmn:task id="Activity_1hpwxh3" />
<bpmn:task id="Activity_0ghtle5" />
<bpmn:task id="Activity_04q1i1s">
<bpmn:incoming>Flow_0ki1200</bpmn:incoming>
</bpmn:task>
<bpmn:sequenceFlow id="Flow_0ki1200" sourceRef="Event_0fkph5i" targetRef="Activity_04q1i1s" />
<bpmn:sequenceFlow id="Flow_0togudw" sourceRef="Event_16c5xe9" targetRef="Activity_1dnnvam" />
</bpmn:adHocSubProcess>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
<bpmndi:BPMNShape id="Activity_0h7j88j_di" bpmnElement="SubProcess_0zz45ap" isExpanded="true">
<dc:Bounds x="120" y="60" width="410" height="360" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0d8s2mi_di" bpmnElement="Activity_0d8s2mi">
<dc:Bounds x="248" y="110" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0fkph5i_di" bpmnElement="Event_0fkph5i">
<dc:Bounds x="150" y="232" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1dnnvam_di" bpmnElement="Activity_1dnnvam">
<dc:Bounds x="248" y="310" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BPMNShape_0z0sa2f" bpmnElement="Activity_1hpwxh3">
<dc:Bounds x="388" y="210" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BPMNShape_1e8yor2" bpmnElement="Activity_0ghtle5">
<dc:Bounds x="388" y="310" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_12ph7yu_di" bpmnElement="Activity_04q1i1s">
<dc:Bounds x="248" y="210" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_16c5xe9_di" bpmnElement="Event_16c5xe9">
<dc:Bounds x="150" y="332" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_0ki1200_di" bpmnElement="Flow_0ki1200">
<di:waypoint x="186" y="250" />
<di:waypoint x="248" y="250" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0togudw_di" bpmnElement="Flow_0togudw">
<di:waypoint x="186" y="350" />
<di:waypoint x="248" y="350" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
70 changes: 70 additions & 0 deletions docs/rules/examples/ad-hoc-sub-process-incorrect.bpmn
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_1ntx4rf" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.32.0">
<bpmn:process id="Process_1" isExecutable="true">
<bpmn:adHocSubProcess id="SubProcess_0zz45ap" name="Ad-hoc subprocess">
<bpmn:intermediateCatchEvent id="Event_0fkph5i">
<bpmn:linkEventDefinition id="LinkEventDefinition_0o8x64t" name="" />
</bpmn:intermediateCatchEvent>
<bpmn:intermediateThrowEvent id="Event_16c5xe9" />
<bpmn:task id="Activity_0d8s2mi">
<bpmn:incoming>Flow_0w1fi7u</bpmn:incoming>
<bpmn:outgoing>Flow_10hamq6</bpmn:outgoing>
</bpmn:task>
<bpmn:startEvent id="Event_0fvpyx9">
<bpmn:outgoing>Flow_0w1fi7u</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_0w1fi7u" sourceRef="Event_0fvpyx9" targetRef="Activity_0d8s2mi" />
<bpmn:endEvent id="Event_1ma75bn">
<bpmn:incoming>Flow_10hamq6</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_10hamq6" sourceRef="Activity_0d8s2mi" targetRef="Event_1ma75bn" />
<bpmn:task id="Activity_1dnnvam" />
<bpmn:task id="Activity_1hpwxh3" />
<bpmn:task id="Activity_0ghtle5" />
<bpmn:task id="Activity_04q1i1s" />
</bpmn:adHocSubProcess>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
<bpmndi:BPMNShape id="Activity_0h7j88j_di" bpmnElement="SubProcess_0zz45ap" isExpanded="true">
<dc:Bounds x="120" y="60" width="410" height="360" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0d8s2mi_di" bpmnElement="Activity_0d8s2mi">
<dc:Bounds x="248" y="110" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0fvpyx9_di" bpmnElement="Event_0fvpyx9">
<dc:Bounds x="150" y="132" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_1ma75bn_di" bpmnElement="Event_1ma75bn">
<dc:Bounds x="420" y="132" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0fkph5i_di" bpmnElement="Event_0fkph5i">
<dc:Bounds x="150" y="232" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1dnnvam_di" bpmnElement="Activity_1dnnvam">
<dc:Bounds x="248" y="310" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BPMNShape_0z0sa2f" bpmnElement="Activity_1hpwxh3">
<dc:Bounds x="388" y="210" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="BPMNShape_1e8yor2" bpmnElement="Activity_0ghtle5">
<dc:Bounds x="388" y="310" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_12ph7yu_di" bpmnElement="Activity_04q1i1s">
<dc:Bounds x="248" y="210" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_16c5xe9_di" bpmnElement="Event_16c5xe9">
<dc:Bounds x="150" y="332" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_0w1fi7u_di" bpmnElement="Flow_0w1fi7u">
<di:waypoint x="186" y="150" />
<di:waypoint x="248" y="150" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_10hamq6_di" bpmnElement="Flow_10hamq6">
<di:waypoint x="348" y="150" />
<di:waypoint x="420" y="150" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
45 changes: 45 additions & 0 deletions rules/ad-hoc-sub-process.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
const {
is,
isAny
} = require('bpmnlint-utils');

/**
* A rule that ensures that an Ad Hoc Sub Process is valid according to the BPMN spec:
*
* - No start or end events
* - Every intermediate event has an outgoing sequence flow
*/
module.exports = function() {

function check(node, reporter) {

if (!is(node, 'bpmn:AdHocSubProcess')) {
return;
}

const flowElements = node.flowElements || [];

flowElements.forEach(function(flowElement) {

if (is(flowElement, 'bpmn:StartEvent')) {
reporter.report(flowElement.id, 'A <Start Event> is not allowed in <Ad Hoc Sub Process>');
}

if (is(flowElement, 'bpmn:EndEvent')) {
reporter.report(flowElement.id, 'An <End Event> is not allowed in <Ad Hoc Sub Process>');
}

if (isAny(flowElement, [ 'bpmn:IntermediateCatchEvent', 'bpmn:IntermediateThrowEvent' ])) {
if (!flowElement.outgoing || flowElement.outgoing.length === 0) {
reporter.report(flowElement.id, 'An intermediate event inside <Ad Hoc Sub Process> must have an outgoing sequence flow');
}
}

});
}

return {
check
};

};
Loading

0 comments on commit 50bcc92

Please sign in to comment.