@camunda/linting 0.3.5 → 0.4.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 +4 -0
- package/lib/Linter.js +4 -2
- package/lib/utils/error-messages.js +27 -0
- package/lib/utils/properties-panel.js +75 -46
- package/package.json +6 -2
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,10 @@ All notable changes to [@camunda/linting](https://github.com/camunda/linting) ar
|
|
|
6
6
|
|
|
7
7
|
___Note:__ Yet to be released changes appear here._
|
|
8
8
|
|
|
9
|
+
## 0.4.0
|
|
10
|
+
|
|
11
|
+
* `FEAT`: add duplicate task headers rule ([#41](https://github.com/camunda/bpmnlint-plugin-camunda-compat/pull/41))
|
|
12
|
+
|
|
9
13
|
## 0.3.5
|
|
10
14
|
|
|
11
15
|
* `FIX`: ignore null properties ([#39](https://github.com/camunda/bpmnlint-plugin-camunda-compat/pull/39))
|
package/lib/Linter.js
CHANGED
|
@@ -12,7 +12,7 @@ import modelerModdle from 'modeler-moddle/resources/modeler.json';
|
|
|
12
12
|
import zeebeModdle from 'zeebe-bpmn-moddle/resources/zeebe.json';
|
|
13
13
|
|
|
14
14
|
import { getErrorMessage } from './utils/error-messages';
|
|
15
|
-
import {
|
|
15
|
+
import { getEntryIds } from './utils/properties-panel';
|
|
16
16
|
|
|
17
17
|
const moddle = new BpmnModdle({
|
|
18
18
|
modeler: modelerModdle,
|
|
@@ -63,6 +63,8 @@ export class Linter {
|
|
|
63
63
|
return [
|
|
64
64
|
...allReports,
|
|
65
65
|
...reports.map(report => {
|
|
66
|
+
const entryIds = getEntryIds(report);
|
|
67
|
+
|
|
66
68
|
return {
|
|
67
69
|
...report,
|
|
68
70
|
message: getErrorMessage(
|
|
@@ -71,7 +73,7 @@ export class Linter {
|
|
|
71
73
|
this._modeler
|
|
72
74
|
),
|
|
73
75
|
propertiesPanel: {
|
|
74
|
-
entryId:
|
|
76
|
+
entryId: entryIds[ Math.max(0, entryIds.length - 1) ]
|
|
75
77
|
}
|
|
76
78
|
};
|
|
77
79
|
})
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ERROR_TYPES } from 'bpmnlint-plugin-camunda-compat/rules/utils/element';
|
|
2
2
|
|
|
3
3
|
import { is } from 'bpmnlint-utils';
|
|
4
|
+
import { every } from 'min-dash';
|
|
4
5
|
|
|
5
6
|
import { isArray } from 'min-dash';
|
|
6
7
|
|
|
@@ -46,6 +47,10 @@ export function getErrorMessage(report, executionPlatformLabel, modeler = 'deskt
|
|
|
46
47
|
return getPropertyTypeNotAllowedErrorMessage(report, executionPlatformLabel);
|
|
47
48
|
}
|
|
48
49
|
|
|
50
|
+
if (type === ERROR_TYPES.PROPERTY_VALUE_DUPLICATED) {
|
|
51
|
+
return getPropertyValueDuplicatedErrorMessage(report);
|
|
52
|
+
}
|
|
53
|
+
|
|
49
54
|
return message;
|
|
50
55
|
}
|
|
51
56
|
|
|
@@ -73,6 +78,28 @@ function getElementTypeNotAllowedErrorMessage(report, executionPlatformLabel) {
|
|
|
73
78
|
return `${ getIndefiniteArticle(typeString) } <${ typeString }> is not supported by ${ executionPlatformLabel }`;
|
|
74
79
|
}
|
|
75
80
|
|
|
81
|
+
function getPropertyValueDuplicatedErrorMessage(report) {
|
|
82
|
+
const {
|
|
83
|
+
error,
|
|
84
|
+
message
|
|
85
|
+
} = report;
|
|
86
|
+
|
|
87
|
+
const {
|
|
88
|
+
node,
|
|
89
|
+
parentNode,
|
|
90
|
+
duplicatedPropertyValue,
|
|
91
|
+
properties
|
|
92
|
+
} = error;
|
|
93
|
+
|
|
94
|
+
const typeString = getTypeString(parentNode || node);
|
|
95
|
+
|
|
96
|
+
if (is(node, 'zeebe:TaskHeaders') && every(properties, property => is(property, 'zeebe:Header'))) {
|
|
97
|
+
return `${ getIndefiniteArticle(typeString) } <${ typeString }> with two or more <Headers> with the same <Key> (${ duplicatedPropertyValue }) is not supported`;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return message;
|
|
101
|
+
}
|
|
102
|
+
|
|
76
103
|
function getExtensionElementNotAllowedErrorMessage(report, executionPlatformLabel) {
|
|
77
104
|
const {
|
|
78
105
|
error,
|
|
@@ -4,107 +4,125 @@ import { is } from 'bpmnlint-utils';
|
|
|
4
4
|
|
|
5
5
|
import { ERROR_TYPES } from 'bpmnlint-plugin-camunda-compat/rules/utils/error-types';
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Get errors for a given element.
|
|
9
|
+
*
|
|
10
|
+
* @param {Object[]} reports
|
|
11
|
+
* @param {Object} element
|
|
12
|
+
*
|
|
13
|
+
* @returns {Object}
|
|
14
|
+
*/
|
|
15
|
+
export function getErrors(reports, element) {
|
|
16
|
+
return reports.reduce((errors, report) => {
|
|
17
|
+
if (!element || getBusinessObject(element).get('id') !== report.id) {
|
|
18
|
+
return errors;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const ids = getEntryIds(report);
|
|
22
|
+
|
|
23
|
+
if (!ids.length) {
|
|
24
|
+
return errors;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let { message } = report;
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
...errors,
|
|
31
|
+
...ids.reduce((errors, id) => {
|
|
32
|
+
return {
|
|
33
|
+
...errors,
|
|
34
|
+
[ id ]: getErrorMessage(id) || message
|
|
35
|
+
};
|
|
36
|
+
}, {})
|
|
37
|
+
};
|
|
38
|
+
}, {});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function getEntryIds(report) {
|
|
8
42
|
const {
|
|
9
|
-
error = {}
|
|
43
|
+
error = {},
|
|
44
|
+
id
|
|
10
45
|
} = report;
|
|
11
46
|
|
|
12
47
|
if (isExtensionElementRequiredError(error, 'zeebe:CalledDecision', 'bpmn:BusinessRuleTask')) {
|
|
13
|
-
return 'businessRuleImplementation';
|
|
48
|
+
return [ 'businessRuleImplementation' ];
|
|
14
49
|
}
|
|
15
50
|
|
|
16
51
|
if (isPropertyRequiredError(error, 'errorRef')) {
|
|
17
|
-
return 'errorRef';
|
|
52
|
+
return [ 'errorRef' ];
|
|
18
53
|
}
|
|
19
54
|
|
|
20
55
|
if (isPropertyRequiredError(error, 'messageRef')) {
|
|
21
|
-
return 'messageRef';
|
|
56
|
+
return [ 'messageRef' ];
|
|
22
57
|
}
|
|
23
58
|
|
|
24
59
|
if (isPropertyRequiredError(error, 'decisionId', 'zeebe:CalledDecision')) {
|
|
25
|
-
return 'decisionId';
|
|
60
|
+
return [ 'decisionId' ];
|
|
26
61
|
}
|
|
27
62
|
|
|
28
63
|
if (isPropertyRequiredError(error, 'resultVariable', 'zeebe:CalledDecision')) {
|
|
29
|
-
return 'resultVariable';
|
|
64
|
+
return [ 'resultVariable' ];
|
|
30
65
|
}
|
|
31
66
|
|
|
32
67
|
if (isPropertyRequiredError(error, 'errorCode', 'bpmn:Error')) {
|
|
33
|
-
return 'errorCode';
|
|
68
|
+
return [ 'errorCode' ];
|
|
34
69
|
}
|
|
35
70
|
|
|
36
71
|
if (isPropertyRequiredError(error, 'name', 'bpmn:Message')) {
|
|
37
|
-
return 'messageName';
|
|
72
|
+
return [ 'messageName' ];
|
|
38
73
|
}
|
|
39
74
|
|
|
40
75
|
if (isExtensionElementRequiredError(error, 'zeebe:LoopCharacteristics', 'bpmn:MultiInstanceLoopCharacteristics')
|
|
41
76
|
|| isPropertyRequiredError(error, 'inputCollection', 'zeebe:LoopCharacteristics')) {
|
|
42
|
-
return 'multiInstance-inputCollection';
|
|
77
|
+
return [ 'multiInstance-inputCollection' ];
|
|
43
78
|
}
|
|
44
79
|
|
|
45
80
|
if (isPropertyDependendRequiredError(error, 'outputCollection', 'zeebe:LoopCharacteristics')) {
|
|
46
|
-
return 'multiInstance-outputCollection';
|
|
81
|
+
return [ 'multiInstance-outputCollection' ];
|
|
47
82
|
}
|
|
48
83
|
|
|
49
84
|
if (isPropertyDependendRequiredError(error, 'outputElement', 'zeebe:LoopCharacteristics')) {
|
|
50
|
-
return 'multiInstance-outputElement';
|
|
85
|
+
return [ 'multiInstance-outputElement' ];
|
|
51
86
|
}
|
|
52
87
|
|
|
53
88
|
if (isExtensionElementRequiredError(error, 'zeebe:CalledElement', 'bpmn:CallActivity')
|
|
54
89
|
|| isPropertyRequiredError(error, 'processId', 'zeebe:CalledElement')) {
|
|
55
|
-
return 'targetProcessId';
|
|
90
|
+
return [ 'targetProcessId' ];
|
|
56
91
|
}
|
|
57
92
|
|
|
58
93
|
if (isExtensionElementRequiredError(error, 'zeebe:TaskDefinition')
|
|
59
94
|
|| isPropertyRequiredError(error, 'type', 'zeebe:TaskDefinition')) {
|
|
60
|
-
return 'taskDefinitionType';
|
|
95
|
+
return [ 'taskDefinitionType' ];
|
|
61
96
|
}
|
|
62
97
|
|
|
63
98
|
if (isExtensionElementRequiredError(error, 'zeebe:Subscription')
|
|
64
99
|
|| isPropertyRequiredError(error, 'correlationKey', 'zeebe:Subscription')) {
|
|
65
|
-
return 'messageSubscriptionCorrelationKey';
|
|
100
|
+
return [ 'messageSubscriptionCorrelationKey' ];
|
|
66
101
|
}
|
|
67
102
|
|
|
68
103
|
if (isPropertyRequiredError(error, 'formKey', 'zeebe:FormDefinition')) {
|
|
69
|
-
return 'customFormKey';
|
|
104
|
+
return [ 'customFormKey' ];
|
|
70
105
|
}
|
|
71
106
|
|
|
72
107
|
if (isPropertyRequiredError(error, 'body', 'zeebe:UserTaskForm')) {
|
|
73
|
-
return 'formConfiguration';
|
|
108
|
+
return [ 'formConfiguration' ];
|
|
74
109
|
}
|
|
75
110
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
* @param {Object[]} reports
|
|
83
|
-
* @param {Object} element
|
|
84
|
-
*
|
|
85
|
-
* @returns {Object}
|
|
86
|
-
*/
|
|
87
|
-
export function getErrors(reports, element) {
|
|
88
|
-
return reports.reduce((errors, report) => {
|
|
89
|
-
if (!element || getBusinessObject(element).get('id') !== report.id) {
|
|
90
|
-
return errors;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const id = getEntryId(report);
|
|
111
|
+
if (isPropertyValueDuplicatedError(error, 'values', 'key', 'zeebe:TaskHeaders')) {
|
|
112
|
+
const {
|
|
113
|
+
node,
|
|
114
|
+
properties,
|
|
115
|
+
propertiesName
|
|
116
|
+
} = error;
|
|
94
117
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
let { message } = report;
|
|
118
|
+
return properties.map(property => {
|
|
119
|
+
const index = node.get(propertiesName).indexOf(property);
|
|
100
120
|
|
|
101
|
-
|
|
121
|
+
return `${ id }-header-${ index }-key`;
|
|
122
|
+
});
|
|
123
|
+
}
|
|
102
124
|
|
|
103
|
-
|
|
104
|
-
...errors,
|
|
105
|
-
[ id ]: message
|
|
106
|
-
};
|
|
107
|
-
}, {});
|
|
125
|
+
return [];
|
|
108
126
|
}
|
|
109
127
|
|
|
110
128
|
export function getErrorMessage(id) {
|
|
@@ -167,6 +185,10 @@ export function getErrorMessage(id) {
|
|
|
167
185
|
if (id === 'formConfiguration') {
|
|
168
186
|
return 'Form JSON configuration must be defined.';
|
|
169
187
|
}
|
|
188
|
+
|
|
189
|
+
if (/^.+-header-[0-9]+-key$/.test(id)) {
|
|
190
|
+
return 'Must be unique.';
|
|
191
|
+
}
|
|
170
192
|
}
|
|
171
193
|
|
|
172
194
|
function isExtensionElementRequiredError(error, requiredExtensionElement, type) {
|
|
@@ -188,6 +210,13 @@ function isPropertyRequiredError(error, requiredProperty, type) {
|
|
|
188
210
|
&& (!type || is(error.node, type));
|
|
189
211
|
}
|
|
190
212
|
|
|
213
|
+
function isPropertyValueDuplicatedError(error, propertiesName, duplicatedProperty, type) {
|
|
214
|
+
return error.type === ERROR_TYPES.PROPERTY_VALUE_DUPLICATED
|
|
215
|
+
&& error.propertiesName === propertiesName
|
|
216
|
+
&& error.duplicatedProperty === duplicatedProperty
|
|
217
|
+
&& (!type || is(error.node, type));
|
|
218
|
+
}
|
|
219
|
+
|
|
191
220
|
function getBusinessObject(element) {
|
|
192
221
|
return element.businessObject || element;
|
|
193
222
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camunda/linting",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Linting for Camunda Platform",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -17,11 +17,15 @@
|
|
|
17
17
|
"name": "Philipp Fromme",
|
|
18
18
|
"url": "https://github.com/philippfromme"
|
|
19
19
|
},
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "https://github.com/camunda/linting"
|
|
23
|
+
},
|
|
20
24
|
"license": "MIT",
|
|
21
25
|
"dependencies": {
|
|
22
26
|
"bpmn-moddle": "^7.1.2",
|
|
23
27
|
"bpmnlint": "^7.8.0",
|
|
24
|
-
"bpmnlint-plugin-camunda-compat": "^0.
|
|
28
|
+
"bpmnlint-plugin-camunda-compat": "^0.10.0",
|
|
25
29
|
"bpmnlint-utils": "^1.0.2",
|
|
26
30
|
"modeler-moddle": "^0.2.0",
|
|
27
31
|
"zeebe-bpmn-moddle": "^0.12.1"
|