bpmnlint-plugin-camunda-compat 2.21.1 → 2.22.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/index.js +9 -2
- package/package.json +2 -2
- package/rules/camunda-cloud/duplicate-execution-listeners.js +33 -0
- package/rules/camunda-cloud/execution-listener.js +34 -0
- package/rules/camunda-cloud/no-execution-listeners.js +21 -0
- package/rules/camunda-cloud/no-loop.js +1 -1
- package/rules/utils/element.js +49 -0
- package/rules/utils/error-types.js +1 -0
package/index.js
CHANGED
@@ -12,6 +12,7 @@ const camundaCloud10Rules = withConfig({
|
|
12
12
|
'loop-characteristics': 'error',
|
13
13
|
'message-reference': 'error',
|
14
14
|
'no-candidate-users': 'error',
|
15
|
+
'no-execution-listeners': 'error',
|
15
16
|
'no-expression': 'error',
|
16
17
|
'no-loop': 'error',
|
17
18
|
'no-multiple-none-start-events': 'error',
|
@@ -75,8 +76,11 @@ const camundaCloud85Rules = withConfig({
|
|
75
76
|
'wait-for-completion': 'error'
|
76
77
|
}, { version: '8.5' });
|
77
78
|
|
78
|
-
const camundaCloud86Rules = withConfig(
|
79
|
-
omit(camundaCloud85Rules, 'inclusive-gateway'
|
79
|
+
const camundaCloud86Rules = withConfig({
|
80
|
+
...omit(camundaCloud85Rules, [ 'inclusive-gateway', 'no-execution-listeners' ]),
|
81
|
+
'duplicate-execution-listeners': 'error',
|
82
|
+
'execution-listener': 'error'
|
83
|
+
}, { version: '8.6' });
|
80
84
|
|
81
85
|
const camundaPlatform719Rules = withConfig({
|
82
86
|
'history-time-to-live': 'info'
|
@@ -105,12 +109,14 @@ const rules = {
|
|
105
109
|
'called-element': './rules/camunda-cloud/called-element',
|
106
110
|
'collapsed-subprocess': './rules/camunda-cloud/collapsed-subprocess',
|
107
111
|
'connector-properties': './rules/camunda-cloud/connector-properties',
|
112
|
+
'duplicate-execution-listeners': './rules/camunda-cloud/duplicate-execution-listeners',
|
108
113
|
'duplicate-task-headers': './rules/camunda-cloud/duplicate-task-headers',
|
109
114
|
'error-reference': './rules/camunda-cloud/error-reference',
|
110
115
|
'escalation-boundary-event-attached-to-ref': './rules/camunda-cloud/escalation-boundary-event-attached-to-ref',
|
111
116
|
'escalation-reference': './rules/camunda-cloud/escalation-reference',
|
112
117
|
'event-based-gateway-target': './rules/camunda-cloud/event-based-gateway-target',
|
113
118
|
'executable-process': './rules/camunda-cloud/executable-process',
|
119
|
+
'execution-listener': './rules/camunda-cloud/execution-listener',
|
114
120
|
'feel': './rules/camunda-cloud/feel',
|
115
121
|
'history-time-to-live': './rules/camunda-platform/history-time-to-live',
|
116
122
|
'implementation': './rules/camunda-cloud/implementation',
|
@@ -119,6 +125,7 @@ const rules = {
|
|
119
125
|
'loop-characteristics': './rules/camunda-cloud/loop-characteristics',
|
120
126
|
'message-reference': './rules/camunda-cloud/message-reference',
|
121
127
|
'no-candidate-users': './rules/camunda-cloud/no-candidate-users',
|
128
|
+
'no-execution-listeners': './rules/camunda-cloud/no-execution-listeners',
|
122
129
|
'no-expression': './rules/camunda-cloud/no-expression',
|
123
130
|
'no-loop': './rules/camunda-cloud/no-loop',
|
124
131
|
'no-multiple-none-start-events': './rules/camunda-cloud/no-multiple-none-start-events',
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "bpmnlint-plugin-camunda-compat",
|
3
|
-
"version": "2.
|
3
|
+
"version": "2.22.0",
|
4
4
|
"description": "A bpmnlint plug-in for Camunda compatibility",
|
5
5
|
"main": "index.js",
|
6
6
|
"scripts": {
|
@@ -34,7 +34,7 @@
|
|
34
34
|
"modeler-moddle": "^0.2.0",
|
35
35
|
"sinon": "^17.0.1",
|
36
36
|
"sinon-chai": "^3.7.0",
|
37
|
-
"zeebe-bpmn-moddle": "^1.
|
37
|
+
"zeebe-bpmn-moddle": "^1.4.0"
|
38
38
|
},
|
39
39
|
"dependencies": {
|
40
40
|
"@bpmn-io/feel-lint": "^1.2.0",
|
@@ -0,0 +1,33 @@
|
|
1
|
+
const {
|
2
|
+
findExtensionElement,
|
3
|
+
hasDuplicatedPropertiesValues
|
4
|
+
} = require('../utils/element');
|
5
|
+
|
6
|
+
const { reportErrors } = require('../utils/reporter');
|
7
|
+
|
8
|
+
const { skipInNonExecutableProcess } = require('../utils/rule');
|
9
|
+
|
10
|
+
module.exports = skipInNonExecutableProcess(function() {
|
11
|
+
function check(node, reporter) {
|
12
|
+
const executionListeners = findExtensionElement(node, 'zeebe:ExecutionListeners');
|
13
|
+
|
14
|
+
if (!executionListeners) {
|
15
|
+
return;
|
16
|
+
}
|
17
|
+
|
18
|
+
const errors = hasDuplicatedExecutionListeners(executionListeners, node);
|
19
|
+
|
20
|
+
if (errors && errors.length) {
|
21
|
+
reportErrors(node, reporter, errors);
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
return {
|
26
|
+
check
|
27
|
+
};
|
28
|
+
});
|
29
|
+
|
30
|
+
// helpers //////////
|
31
|
+
function hasDuplicatedExecutionListeners(executionListeners, parentNode = null) {
|
32
|
+
return hasDuplicatedPropertiesValues(executionListeners, 'listeners', [ 'eventType', 'type' ], parentNode);
|
33
|
+
}
|
@@ -0,0 +1,34 @@
|
|
1
|
+
const {
|
2
|
+
findExtensionElement,
|
3
|
+
hasProperties
|
4
|
+
} = require('../utils/element');
|
5
|
+
|
6
|
+
const { reportErrors } = require('../utils/reporter');
|
7
|
+
|
8
|
+
const { skipInNonExecutableProcess } = require('../utils/rule');
|
9
|
+
|
10
|
+
|
11
|
+
module.exports = skipInNonExecutableProcess(function() {
|
12
|
+
function check(node, reporter) {
|
13
|
+
const executionListeners = findExtensionElement(node, 'zeebe:ExecutionListeners');
|
14
|
+
|
15
|
+
if (!executionListeners) {
|
16
|
+
return;
|
17
|
+
}
|
18
|
+
|
19
|
+
const listeners = executionListeners.get('listeners');
|
20
|
+
const errors = listeners.flatMap(listener => hasProperties(listener, {
|
21
|
+
type: {
|
22
|
+
required: true
|
23
|
+
}
|
24
|
+
}, node));
|
25
|
+
|
26
|
+
if (errors.length) {
|
27
|
+
reportErrors(node, reporter, errors);
|
28
|
+
}
|
29
|
+
}
|
30
|
+
|
31
|
+
return {
|
32
|
+
check
|
33
|
+
};
|
34
|
+
});
|
@@ -0,0 +1,21 @@
|
|
1
|
+
const { reportErrors } = require('../utils/reporter');
|
2
|
+
|
3
|
+
const { skipInNonExecutableProcess } = require('../utils/rule');
|
4
|
+
|
5
|
+
const { hasNoExtensionElement } = require('../utils/element');
|
6
|
+
|
7
|
+
const ALLOWED_VERSION = '8.6';
|
8
|
+
|
9
|
+
module.exports = skipInNonExecutableProcess(function() {
|
10
|
+
function check(node, reporter) {
|
11
|
+
const errors = hasNoExtensionElement(node, 'zeebe:ExecutionListeners', node, ALLOWED_VERSION);
|
12
|
+
|
13
|
+
if (errors && errors.length) {
|
14
|
+
reportErrors(node, reporter, errors);
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
return {
|
19
|
+
check
|
20
|
+
};
|
21
|
+
});
|
package/rules/utils/element.js
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
const {
|
2
|
+
filter,
|
2
3
|
isArray,
|
3
4
|
isDefined,
|
4
5
|
isFunction,
|
@@ -6,6 +7,7 @@ const {
|
|
6
7
|
isObject,
|
7
8
|
isString,
|
8
9
|
isUndefined,
|
10
|
+
matchPattern,
|
9
11
|
some
|
10
12
|
} = require('min-dash');
|
11
13
|
|
@@ -133,6 +135,53 @@ module.exports.hasDuplicatedPropertyValues = function(node, propertiesName, prop
|
|
133
135
|
return [];
|
134
136
|
};
|
135
137
|
|
138
|
+
// @TODO(@barmac): use tree algorithm to reduce complexity
|
139
|
+
module.exports.hasDuplicatedPropertiesValues = function(node, containerPropertyName, propertiesNames, parentNode = null) {
|
140
|
+
const properties = node.get(containerPropertyName);
|
141
|
+
|
142
|
+
// (1) find duplicates
|
143
|
+
const duplicates = properties.reduce((foundDuplicates, property, index) => {
|
144
|
+
const previous = properties.slice(0, index);
|
145
|
+
const isDuplicate = previous.find(p => propertiesNames.every(propertyName => p.get(propertyName) === property.get(propertyName)));
|
146
|
+
|
147
|
+
if (isDuplicate) {
|
148
|
+
return foundDuplicates.concat(property);
|
149
|
+
}
|
150
|
+
|
151
|
+
return foundDuplicates;
|
152
|
+
}, []);
|
153
|
+
|
154
|
+
// (2) report error for each duplicate
|
155
|
+
if (duplicates.length) {
|
156
|
+
return duplicates.map(duplicate => {
|
157
|
+
const propertiesMap = {};
|
158
|
+
for (const property of propertiesNames) {
|
159
|
+
propertiesMap[property] = duplicate.get(property);
|
160
|
+
}
|
161
|
+
|
162
|
+
// (3) find properties with duplicate
|
163
|
+
const duplicateProperties = filter(properties, matchPattern(propertiesMap));
|
164
|
+
const duplicatesSummary = propertiesNames.map(propertyName => `property <${ propertyName }> with duplicate value of <${ propertiesMap[propertyName] }>`).join(', ');
|
165
|
+
|
166
|
+
// (4) report error
|
167
|
+
return {
|
168
|
+
message: `Properties of type <${ duplicate.$type }> have properties with duplicate values (${ duplicatesSummary })`,
|
169
|
+
path: null,
|
170
|
+
data: {
|
171
|
+
type: ERROR_TYPES.PROPERTY_VALUES_DUPLICATED,
|
172
|
+
node,
|
173
|
+
parentNode: parentNode == node ? null : parentNode,
|
174
|
+
duplicatedProperties: propertiesMap,
|
175
|
+
properties: duplicateProperties,
|
176
|
+
propertiesName: containerPropertyName
|
177
|
+
}
|
178
|
+
};
|
179
|
+
});
|
180
|
+
}
|
181
|
+
|
182
|
+
return [];
|
183
|
+
};
|
184
|
+
|
136
185
|
module.exports.hasProperties = function(node, properties, parentNode = null) {
|
137
186
|
return Object.entries(properties).reduce((results, property) => {
|
138
187
|
const [ propertyName, propertyChecks ] = property;
|
@@ -19,6 +19,7 @@ module.exports.ERROR_TYPES = Object.freeze({
|
|
19
19
|
PROPERTY_REQUIRED: 'camunda.propertyRequired',
|
20
20
|
PROPERTY_TYPE_NOT_ALLOWED: 'camunda.propertyTypeNotAllowed',
|
21
21
|
PROPERTY_VALUE_DUPLICATED: 'camunda.propertyValueDuplicated',
|
22
|
+
PROPERTY_VALUES_DUPLICATED: 'camunda.propertiesValuesDuplicated',
|
22
23
|
PROPERTY_VALUE_NOT_ALLOWED: 'camunda.propertyValueNotAllowed',
|
23
24
|
PROPERTY_VALUE_REQUIRED: 'camunda.propertyValueRequired',
|
24
25
|
SECRET_EXPRESSION_FORMAT_DEPRECATED: 'camunda.secretExpressionFormatDeprecated'
|