bpmnlint-plugin-camunda-compat 0.9.0 → 0.10.0
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/CHANGELOG.md +13 -0
- package/index.js +5 -0
- package/package.json +1 -1
- package/rules/duplicate-task-headers.js +57 -0
- package/rules/user-task-form.js +2 -0
- package/rules/utils/element.js +61 -3
- package/rules/utils/error-types.js +2 -1
- package/rules/utils/reporter.js +28 -1
package/CHANGELOG.md
CHANGED
@@ -6,6 +6,19 @@ All notable changes to [bpmnlint-plugin-camunda-compat](https://github.com/camun
|
|
6
6
|
|
7
7
|
___Note:__ Yet to be released changes appear here._
|
8
8
|
|
9
|
+
## 0.10.0
|
10
|
+
|
11
|
+
* `FEAT`: add duplicate task headers rule ([#41](https://github.com/camunda/bpmnlint-plugin-camunda-compat/pull/41))
|
12
|
+
|
13
|
+
|
14
|
+
## 0.9.2
|
15
|
+
|
16
|
+
* `FIX`: ignore null properties ([#39](https://github.com/camunda/bpmnlint-plugin-camunda-compat/pull/39))
|
17
|
+
|
18
|
+
## 0.9.1
|
19
|
+
|
20
|
+
* `FIX`: add name to reports ([#38](https://github.com/camunda/bpmnlint-plugin-camunda-compat/pull/38))
|
21
|
+
|
9
22
|
## 0.9.0
|
10
23
|
|
11
24
|
* `FEAT`: add user task forms rule ([#32](https://github.com/camunda/bpmnlint-plugin-camunda-compat/pull/32))
|
package/index.js
CHANGED
@@ -7,6 +7,7 @@ module.exports = {
|
|
7
7
|
rules: {
|
8
8
|
'called-decision-or-task-definition': [ 'error', calledDecisionOrTaskDefinitionConfig.camundaCloud10 ],
|
9
9
|
'called-element': 'error',
|
10
|
+
'duplicate-task-headers': 'error',
|
10
11
|
'element-type': [ 'error', elementTypeConfig.camundaCloud10 ],
|
11
12
|
'error-reference': 'error',
|
12
13
|
'loop-characteristics': 'error',
|
@@ -20,6 +21,7 @@ module.exports = {
|
|
20
21
|
rules: {
|
21
22
|
'called-decision-or-task-definition': [ 'error', calledDecisionOrTaskDefinitionConfig.camundaCloud11 ],
|
22
23
|
'called-element': 'error',
|
24
|
+
'duplicate-task-headers': 'error',
|
23
25
|
'element-type': [ 'error', elementTypeConfig.camundaCloud11 ],
|
24
26
|
'error-reference': 'error',
|
25
27
|
'loop-characteristics': 'error',
|
@@ -33,6 +35,7 @@ module.exports = {
|
|
33
35
|
rules: {
|
34
36
|
'called-decision-or-task-definition': [ 'error', calledDecisionOrTaskDefinitionConfig.camundaCloud12 ],
|
35
37
|
'called-element': 'error',
|
38
|
+
'duplicate-task-headers': 'error',
|
36
39
|
'element-type': [ 'error', elementTypeConfig.camundaCloud12 ],
|
37
40
|
'error-reference': 'error',
|
38
41
|
'loop-characteristics': 'error',
|
@@ -46,6 +49,7 @@ module.exports = {
|
|
46
49
|
rules: {
|
47
50
|
'called-decision-or-task-definition': [ 'error', calledDecisionOrTaskDefinitionConfig.camundaCloud13 ],
|
48
51
|
'called-element': 'error',
|
52
|
+
'duplicate-task-headers': 'error',
|
49
53
|
'element-type': [ 'error', elementTypeConfig.camundaCloud12 ],
|
50
54
|
'error-reference': 'error',
|
51
55
|
'loop-characteristics': 'error',
|
@@ -59,6 +63,7 @@ module.exports = {
|
|
59
63
|
rules: {
|
60
64
|
'called-decision-or-task-definition': [ 'error', calledDecisionOrTaskDefinitionConfig.camundaCloud13 ],
|
61
65
|
'called-element': 'error',
|
66
|
+
'duplicate-task-headers': 'error',
|
62
67
|
'element-type': [ 'error', elementTypeConfig.camundaCloud12 ],
|
63
68
|
'error-reference': 'error',
|
64
69
|
'loop-characteristics': 'error',
|
package/package.json
CHANGED
@@ -0,0 +1,57 @@
|
|
1
|
+
const {
|
2
|
+
is,
|
3
|
+
isAny
|
4
|
+
} = require('bpmnlint-utils');
|
5
|
+
|
6
|
+
const {
|
7
|
+
findExtensionElement,
|
8
|
+
getMessageEventDefinition,
|
9
|
+
hasDuplicatedPropertyValues
|
10
|
+
} = require('./utils/element');
|
11
|
+
|
12
|
+
const { reportErrors } = require('./utils/reporter');
|
13
|
+
|
14
|
+
module.exports = function() {
|
15
|
+
function check(node, reporter) {
|
16
|
+
if (!is(node, 'bpmn:UserTask') && !isZeebeServiceTask(node)) {
|
17
|
+
return;
|
18
|
+
}
|
19
|
+
|
20
|
+
const taskHeaders = findExtensionElement(node, 'zeebe:TaskHeaders');
|
21
|
+
|
22
|
+
if (!taskHeaders) {
|
23
|
+
return;
|
24
|
+
}
|
25
|
+
|
26
|
+
const errors = hasDuplicatedPropertyValues(taskHeaders, 'values', 'key', node);
|
27
|
+
|
28
|
+
if (errors && errors.length) {
|
29
|
+
reportErrors(node, reporter, errors);
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
return {
|
34
|
+
check
|
35
|
+
};
|
36
|
+
};
|
37
|
+
|
38
|
+
// helpers //////////
|
39
|
+
|
40
|
+
function isZeebeServiceTask(element) {
|
41
|
+
if (is(element, 'zeebe:ZeebeServiceTask')) {
|
42
|
+
return true;
|
43
|
+
}
|
44
|
+
|
45
|
+
if (isAny(element, [
|
46
|
+
'bpmn:EndEvent',
|
47
|
+
'bpmn:IntermediateThrowEvent'
|
48
|
+
])) {
|
49
|
+
return getMessageEventDefinition(element);
|
50
|
+
}
|
51
|
+
|
52
|
+
if (is(element, 'bpmn:BusinessRuleTask')) {
|
53
|
+
return findExtensionElement(element, 'zeebe:TaskDefinition');
|
54
|
+
}
|
55
|
+
|
56
|
+
return false;
|
57
|
+
}
|
package/rules/user-task-form.js
CHANGED
package/rules/utils/element.js
CHANGED
@@ -1,10 +1,14 @@
|
|
1
1
|
const {
|
2
2
|
isArray,
|
3
3
|
isDefined,
|
4
|
+
isNil,
|
4
5
|
some
|
5
6
|
} = require('min-dash');
|
6
7
|
|
7
|
-
const {
|
8
|
+
const {
|
9
|
+
is,
|
10
|
+
isAny
|
11
|
+
} = require('bpmnlint-utils');
|
8
12
|
|
9
13
|
const { getPath } = require('@bpmn-io/moddle-utils');
|
10
14
|
|
@@ -12,12 +16,22 @@ const { ERROR_TYPES } = require('./error-types');
|
|
12
16
|
|
13
17
|
module.exports.ERROR_TYPES = ERROR_TYPES;
|
14
18
|
|
15
|
-
|
19
|
+
function getEventDefinition(node) {
|
16
20
|
const eventDefinitions = node.get('eventDefinitions');
|
17
21
|
|
18
22
|
if (eventDefinitions) {
|
19
23
|
return eventDefinitions[ 0 ];
|
20
24
|
}
|
25
|
+
}
|
26
|
+
|
27
|
+
module.exports.getEventDefinition = getEventDefinition;
|
28
|
+
|
29
|
+
module.exports.getMessageEventDefinition = function(node) {
|
30
|
+
if (is(node, 'bpmn:ReceiveTask')) {
|
31
|
+
return node;
|
32
|
+
}
|
33
|
+
|
34
|
+
return getEventDefinition(node);
|
21
35
|
};
|
22
36
|
|
23
37
|
function findExtensionElements(node, types) {
|
@@ -71,6 +85,50 @@ function formatTypes(types, exclusive = false) {
|
|
71
85
|
|
72
86
|
module.exports.formatTypes = formatTypes;
|
73
87
|
|
88
|
+
module.exports.hasDuplicatedPropertyValues = function(node, propertiesName, propertyName, parentNode = null) {
|
89
|
+
const properties = node.get(propertiesName);
|
90
|
+
|
91
|
+
const propertyValues = properties.map(property => property.get(propertyName));
|
92
|
+
|
93
|
+
// (1) find duplicates
|
94
|
+
const duplicates = propertyValues.reduce((duplicates, propertyValue, index) => {
|
95
|
+
if (propertyValues.indexOf(propertyValue) !== index && !duplicates.includes(propertyValue)) {
|
96
|
+
return [
|
97
|
+
...duplicates,
|
98
|
+
propertyValue
|
99
|
+
];
|
100
|
+
}
|
101
|
+
|
102
|
+
return duplicates;
|
103
|
+
}, []);
|
104
|
+
|
105
|
+
// (2) report error for each duplicate
|
106
|
+
if (duplicates.length) {
|
107
|
+
return duplicates.map(duplicate => {
|
108
|
+
|
109
|
+
// (3) find properties with duplicate
|
110
|
+
const duplicateProperties = properties.filter(property => property.get(propertyName) === duplicate);
|
111
|
+
|
112
|
+
// (4) report error
|
113
|
+
return {
|
114
|
+
message: `Properties of type <${ duplicateProperties[ 0 ].$type }> have property <${ propertyName }> with duplicate value of <${ duplicate }>`,
|
115
|
+
path: null,
|
116
|
+
error: {
|
117
|
+
type: ERROR_TYPES.PROPERTY_VALUE_DUPLICATED,
|
118
|
+
node,
|
119
|
+
parentNode: parentNode == node ? null : parentNode,
|
120
|
+
duplicatedProperty: propertyName,
|
121
|
+
duplicatedPropertyValue: duplicate,
|
122
|
+
properties: duplicateProperties,
|
123
|
+
propertiesName
|
124
|
+
}
|
125
|
+
};
|
126
|
+
});
|
127
|
+
}
|
128
|
+
|
129
|
+
return [];
|
130
|
+
};
|
131
|
+
|
74
132
|
module.exports.hasProperties = function(node, properties, parentNode = null) {
|
75
133
|
return Object.entries(properties).reduce((results, property) => {
|
76
134
|
const [ propertyName, propertyChecks ] = property;
|
@@ -147,7 +205,7 @@ module.exports.hasProperties = function(node, properties, parentNode = null) {
|
|
147
205
|
];
|
148
206
|
}
|
149
207
|
|
150
|
-
if (propertyChecks.allowed === false && isDefined(propertyValue)) {
|
208
|
+
if (propertyChecks.allowed === false && isDefined(propertyValue) && !isNil(propertyValue)) {
|
151
209
|
return [
|
152
210
|
...results,
|
153
211
|
{
|
@@ -5,5 +5,6 @@ module.exports.ERROR_TYPES = Object.freeze({
|
|
5
5
|
PROPERTY_DEPENDEND_REQUIRED: 'propertyDependendRequired',
|
6
6
|
PROPERTY_NOT_ALLOWED: 'propertyNotAllowed',
|
7
7
|
PROPERTY_REQUIRED: 'propertyRequired',
|
8
|
-
PROPERTY_TYPE_NOT_ALLOWED: 'propertyTypeNotAllowed'
|
8
|
+
PROPERTY_TYPE_NOT_ALLOWED: 'propertyTypeNotAllowed',
|
9
|
+
PROPERTY_VALUE_DUPLICATED: 'propertyValueDuplicated'
|
9
10
|
});
|
package/rules/utils/reporter.js
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
const { is } = require('bpmnlint-utils');
|
2
|
+
|
1
3
|
const { isArray } = require('min-dash');
|
2
4
|
|
3
5
|
module.exports.reportErrors = function(node, reporter, errors) {
|
@@ -6,6 +8,31 @@ module.exports.reportErrors = function(node, reporter, errors) {
|
|
6
8
|
}
|
7
9
|
|
8
10
|
errors.forEach(({ message, ...options }) => {
|
11
|
+
const name = getName(node);
|
12
|
+
|
13
|
+
if (name) {
|
14
|
+
options = {
|
15
|
+
...options,
|
16
|
+
name
|
17
|
+
};
|
18
|
+
}
|
19
|
+
|
9
20
|
reporter.report(node.get('id'), message, options);
|
10
21
|
});
|
11
|
-
};
|
22
|
+
};
|
23
|
+
|
24
|
+
function getName(node) {
|
25
|
+
if (is(node, 'bpmn:TextAnnotation')) {
|
26
|
+
return node.get('text');
|
27
|
+
}
|
28
|
+
|
29
|
+
if (is(node, 'bpmn:Group')) {
|
30
|
+
const categoryValueRef = node.get('categoryValueRef');
|
31
|
+
|
32
|
+
return categoryValueRef && categoryValueRef.get('value');
|
33
|
+
}
|
34
|
+
|
35
|
+
return node.get('name');
|
36
|
+
}
|
37
|
+
|
38
|
+
module.exports.getName = getName;
|