bpmnlint 10.3.0 → 10.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/package.json +1 -1
- package/rules/global.js +66 -43
- package/rules/helper.js +31 -1
- package/rules/label-required.js +0 -4
- package/rules/no-implicit-end.js +40 -1
package/package.json
CHANGED
package/rules/global.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const {
|
|
2
|
-
|
|
2
|
+
is,
|
|
3
|
+
isAny
|
|
3
4
|
} = require('bpmnlint-utils');
|
|
4
5
|
|
|
5
6
|
|
|
@@ -10,13 +11,13 @@ const {
|
|
|
10
11
|
*
|
|
11
12
|
* * `bpmn:Error`
|
|
12
13
|
* * `bpmn:Escalation`
|
|
13
|
-
* * `bpmn:Signal`
|
|
14
14
|
* * `bpmn:Message`
|
|
15
|
+
* * `bpmn:Signal`
|
|
15
16
|
*
|
|
16
17
|
* For each of these elements proper usage implies:
|
|
17
18
|
*
|
|
18
19
|
* * element must have a name
|
|
19
|
-
* * element is
|
|
20
|
+
* * element is referenced by at least one element
|
|
20
21
|
* * there exists only a single element per type with a given name
|
|
21
22
|
*/
|
|
22
23
|
module.exports = function() {
|
|
@@ -27,20 +28,21 @@ module.exports = function() {
|
|
|
27
28
|
return false;
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
const
|
|
31
|
-
const eventDefinitions = getEventDefinitions(node);
|
|
31
|
+
const rootElements = getRootElements(node);
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
const referencingElements = getReferencingElements(node);
|
|
34
|
+
|
|
35
|
+
rootElements.forEach(rootElement => {
|
|
36
|
+
if (!hasName(rootElement)) {
|
|
37
|
+
reporter.report(rootElement.id, 'Element is missing name');
|
|
36
38
|
}
|
|
37
39
|
|
|
38
|
-
if (!isReferenced(
|
|
39
|
-
reporter.report(
|
|
40
|
+
if (!isReferenced(rootElement, referencingElements)) {
|
|
41
|
+
reporter.report(rootElement.id, 'Element is unused');
|
|
40
42
|
}
|
|
41
43
|
|
|
42
|
-
if (!isUnique(
|
|
43
|
-
reporter.report(
|
|
44
|
+
if (!isUnique(rootElement, rootElements)) {
|
|
45
|
+
reporter.report(rootElement.id, 'Element name is not unique');
|
|
44
46
|
}
|
|
45
47
|
});
|
|
46
48
|
|
|
@@ -52,29 +54,42 @@ module.exports = function() {
|
|
|
52
54
|
|
|
53
55
|
// helpers /////////////////////////////
|
|
54
56
|
|
|
55
|
-
function
|
|
56
|
-
return
|
|
57
|
+
function getRootElements(definitions) {
|
|
58
|
+
return definitions.rootElements.filter(node => isAny(node, [ 'bpmn:Error', 'bpmn:Escalation', 'bpmn:Message', 'bpmn:Signal' ]));
|
|
57
59
|
}
|
|
58
60
|
|
|
59
|
-
function
|
|
60
|
-
const
|
|
61
|
+
function getReferencingElements(definitions) {
|
|
62
|
+
const referencingElements = [];
|
|
61
63
|
|
|
62
64
|
function traverse(element) {
|
|
63
|
-
if (element.rootElements) {
|
|
64
|
-
element.rootElements.forEach(traverse);
|
|
65
|
+
if (is(element, 'bpmn:Definitions') && element.get('rootElements').length) {
|
|
66
|
+
element.get('rootElements').forEach(traverse);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (is(element, 'bpmn:FlowElementsContainer') && element.get('flowElements').length) {
|
|
70
|
+
element.get('flowElements').forEach(traverse);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (is(element, 'bpmn:Event') && element.get('eventDefinitions').length) {
|
|
74
|
+
element.get('eventDefinitions').forEach(eventDefinition => referencingElements.push(eventDefinition));
|
|
65
75
|
}
|
|
66
76
|
|
|
67
|
-
if (element.
|
|
68
|
-
element.
|
|
77
|
+
if (is(element, 'bpmn:Collaboration') && element.get('messageFlows').length) {
|
|
78
|
+
element.get('messageFlows').forEach(traverse);
|
|
69
79
|
}
|
|
70
80
|
|
|
71
|
-
if (element
|
|
72
|
-
|
|
81
|
+
if (isAny(element, [
|
|
82
|
+
'bpmn:MessageFlow',
|
|
83
|
+
'bpmn:ReceiveTask',
|
|
84
|
+
'bpmn:SendTask'
|
|
85
|
+
])) {
|
|
86
|
+
referencingElements.push(element);
|
|
73
87
|
}
|
|
74
88
|
}
|
|
75
89
|
|
|
76
|
-
traverse(
|
|
77
|
-
|
|
90
|
+
traverse(definitions);
|
|
91
|
+
|
|
92
|
+
return referencingElements;
|
|
78
93
|
}
|
|
79
94
|
|
|
80
95
|
function hasName(event) {
|
|
@@ -83,35 +98,43 @@ module.exports = function() {
|
|
|
83
98
|
);
|
|
84
99
|
}
|
|
85
100
|
|
|
86
|
-
function isReferenced(
|
|
87
|
-
if (is(
|
|
88
|
-
return (
|
|
89
|
-
|
|
90
|
-
|
|
101
|
+
function isReferenced(rootElement, referencingElements) {
|
|
102
|
+
if (is(rootElement, 'bpmn:Error')) {
|
|
103
|
+
return referencingElements.some(referencingElement => {
|
|
104
|
+
return is(referencingElement, 'bpmn:ErrorEventDefinition')
|
|
105
|
+
&& rootElement.get('id') === referencingElement.get('errorRef')?.get('id');
|
|
106
|
+
});
|
|
91
107
|
}
|
|
92
108
|
|
|
93
|
-
if (is(
|
|
94
|
-
return (
|
|
95
|
-
|
|
96
|
-
|
|
109
|
+
if (is(rootElement, 'bpmn:Escalation')) {
|
|
110
|
+
return referencingElements.some(referencingElement => {
|
|
111
|
+
return is(referencingElement, 'bpmn:EscalationEventDefinition')
|
|
112
|
+
&& rootElement.get('id') === referencingElement.get('escalationRef')?.get('id');
|
|
113
|
+
});
|
|
97
114
|
}
|
|
98
115
|
|
|
99
|
-
if (is(
|
|
100
|
-
return (
|
|
101
|
-
|
|
102
|
-
|
|
116
|
+
if (is(rootElement, 'bpmn:Message')) {
|
|
117
|
+
return referencingElements.some(referencingElement => {
|
|
118
|
+
return isAny(referencingElement, [
|
|
119
|
+
'bpmn:MessageEventDefinition',
|
|
120
|
+
'bpmn:MessageFlow',
|
|
121
|
+
'bpmn:ReceiveTask',
|
|
122
|
+
'bpmn:SendTask'
|
|
123
|
+
]) && rootElement.get('id') === referencingElement.get('messageRef')?.get('id');
|
|
124
|
+
});
|
|
103
125
|
}
|
|
104
126
|
|
|
105
|
-
if (is(
|
|
106
|
-
return (
|
|
107
|
-
|
|
108
|
-
|
|
127
|
+
if (is(rootElement, 'bpmn:Signal')) {
|
|
128
|
+
return referencingElements.some(referencingElement => {
|
|
129
|
+
return is(referencingElement, 'bpmn:SignalEventDefinition')
|
|
130
|
+
&& rootElement.get('id') === referencingElement.get('signalRef')?.get('id');
|
|
131
|
+
});
|
|
109
132
|
}
|
|
110
133
|
}
|
|
111
134
|
|
|
112
|
-
function isUnique(
|
|
135
|
+
function isUnique(rootElement, rootElements) {
|
|
113
136
|
return (
|
|
114
|
-
|
|
137
|
+
rootElements.filter(otherRootElement => is(otherRootElement, rootElement.$type) && rootElement.name === otherRootElement.name).length === 1
|
|
115
138
|
);
|
|
116
139
|
}
|
|
117
140
|
};
|
package/rules/helper.js
CHANGED
|
@@ -28,4 +28,34 @@ function disallowNodeType(type) {
|
|
|
28
28
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
module.exports.disallowNodeType = disallowNodeType;
|
|
31
|
+
module.exports.disallowNodeType = disallowNodeType;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Find a parent for the given element
|
|
35
|
+
*
|
|
36
|
+
* @param {ModdleElement} node
|
|
37
|
+
*
|
|
38
|
+
* @param {String} type
|
|
39
|
+
*
|
|
40
|
+
* @return {ModdleElement} element
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
function findParent(node, type) {
|
|
44
|
+
if (!node) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const parent = node.$parent;
|
|
49
|
+
|
|
50
|
+
if (!parent) {
|
|
51
|
+
return node;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (is(parent, type)) {
|
|
55
|
+
return parent;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return findParent(parent, type);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
module.exports.findParent = findParent;
|
package/rules/label-required.js
CHANGED
package/rules/no-implicit-end.js
CHANGED
|
@@ -3,6 +3,9 @@ const {
|
|
|
3
3
|
isAny
|
|
4
4
|
} = require('bpmnlint-utils');
|
|
5
5
|
|
|
6
|
+
const {
|
|
7
|
+
findParent
|
|
8
|
+
} = require('./helper');
|
|
6
9
|
|
|
7
10
|
/**
|
|
8
11
|
* A rule that checks that an element is not an implicit end (token sink).
|
|
@@ -17,6 +20,34 @@ module.exports = function() {
|
|
|
17
20
|
);
|
|
18
21
|
}
|
|
19
22
|
|
|
23
|
+
function isCompensationEvent(node) {
|
|
24
|
+
const eventDefinitions = node.eventDefinitions || [];
|
|
25
|
+
|
|
26
|
+
return eventDefinitions.length && eventDefinitions.every(
|
|
27
|
+
definition => is(definition, 'bpmn:CompensateEventDefinition')
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function hasCompensationActivity(node) {
|
|
32
|
+
const parent = findParent(node, 'bpmn:Process');
|
|
33
|
+
|
|
34
|
+
const artifacts = parent.artifacts || [];
|
|
35
|
+
|
|
36
|
+
return artifacts.some((element) => {
|
|
37
|
+
if (!is(element, 'bpmn:Association')) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const source = element.sourceRef;
|
|
42
|
+
|
|
43
|
+
return source.id === node.id;
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function isForCompensation(node) {
|
|
48
|
+
return node.isForCompensation;
|
|
49
|
+
}
|
|
50
|
+
|
|
20
51
|
function isImplicitEnd(node) {
|
|
21
52
|
const outgoing = node.outgoing || [];
|
|
22
53
|
|
|
@@ -32,6 +63,14 @@ module.exports = function() {
|
|
|
32
63
|
return false;
|
|
33
64
|
}
|
|
34
65
|
|
|
66
|
+
if (is(node, 'bpmn:BoundaryEvent') && isCompensationEvent(node) && hasCompensationActivity(node)) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (is(node, 'bpmn:Task') && isForCompensation(node)) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
|
|
35
74
|
return outgoing.length === 0;
|
|
36
75
|
}
|
|
37
76
|
|
|
@@ -47,4 +86,4 @@ module.exports = function() {
|
|
|
47
86
|
}
|
|
48
87
|
|
|
49
88
|
return { check };
|
|
50
|
-
};
|
|
89
|
+
};
|