bpmnlint-plugin-camunda-compat 0.9.2 → 0.12.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 CHANGED
@@ -1,71 +1,66 @@
1
+ const { omit } = require('min-dash');
2
+
1
3
  const calledDecisionOrTaskDefinitionConfig = require('./rules/called-decision-or-task-definition/config'),
2
4
  elementTypeConfig = require('./rules/element-type/config');
3
5
 
6
+ const camundaCloud10Rules = {
7
+ 'called-decision-or-task-definition': [ 'error', calledDecisionOrTaskDefinitionConfig.camundaCloud10 ],
8
+ 'called-element': 'error',
9
+ 'duplicate-task-headers': 'error',
10
+ 'element-type': [ 'error', elementTypeConfig.camundaCloud10 ],
11
+ 'error-reference': 'error',
12
+ 'loop-characteristics': 'error',
13
+ 'message-reference': 'error',
14
+ 'no-template': 'error',
15
+ 'no-zeebe-properties': 'error',
16
+ 'subscription': 'error',
17
+ 'user-task-form': 'error'
18
+ };
19
+
20
+ const camundaCloud11Rules = {
21
+ ...camundaCloud10Rules,
22
+ 'called-decision-or-task-definition': [ 'error', calledDecisionOrTaskDefinitionConfig.camundaCloud11 ],
23
+ 'element-type': [ 'error', elementTypeConfig.camundaCloud11 ]
24
+ };
25
+
26
+ const camundaCloud12Rules = {
27
+ ...camundaCloud11Rules,
28
+ 'called-decision-or-task-definition': [ 'error', calledDecisionOrTaskDefinitionConfig.camundaCloud12 ],
29
+ 'element-type': [ 'error', elementTypeConfig.camundaCloud12 ]
30
+ };
31
+
32
+ const camundaCloud13Rules = {
33
+ ...camundaCloud12Rules,
34
+ 'called-decision-or-task-definition': [ 'error', calledDecisionOrTaskDefinitionConfig.camundaCloud13 ]
35
+ };
36
+
37
+ const camundaCloud80Rules = omit(camundaCloud13Rules, 'no-template');
38
+
39
+ const camundaCloud81Rules = {
40
+ ...omit(camundaCloud80Rules, 'no-zeebe-properties'),
41
+ 'element-type': [ 'error', elementTypeConfig.camundaCloud81 ],
42
+ 'inclusive-gateway': 'error'
43
+ };
44
+
4
45
  module.exports = {
5
46
  configs: {
6
47
  'camunda-cloud-1-0': {
7
- rules: {
8
- 'called-decision-or-task-definition': [ 'error', calledDecisionOrTaskDefinitionConfig.camundaCloud10 ],
9
- 'called-element': 'error',
10
- 'element-type': [ 'error', elementTypeConfig.camundaCloud10 ],
11
- 'error-reference': 'error',
12
- 'loop-characteristics': 'error',
13
- 'message-reference': 'error',
14
- 'no-template': 'error',
15
- 'subscription': 'error',
16
- 'user-task-form': 'error'
17
- }
48
+ rules: camundaCloud10Rules
18
49
  },
19
50
  'camunda-cloud-1-1': {
20
- rules: {
21
- 'called-decision-or-task-definition': [ 'error', calledDecisionOrTaskDefinitionConfig.camundaCloud11 ],
22
- 'called-element': 'error',
23
- 'element-type': [ 'error', elementTypeConfig.camundaCloud11 ],
24
- 'error-reference': 'error',
25
- 'loop-characteristics': 'error',
26
- 'message-reference': 'error',
27
- 'no-template': 'error',
28
- 'subscription': 'error',
29
- 'user-task-form': 'error'
30
- }
51
+ rules: camundaCloud11Rules
31
52
  },
32
53
  'camunda-cloud-1-2': {
33
- rules: {
34
- 'called-decision-or-task-definition': [ 'error', calledDecisionOrTaskDefinitionConfig.camundaCloud12 ],
35
- 'called-element': 'error',
36
- 'element-type': [ 'error', elementTypeConfig.camundaCloud12 ],
37
- 'error-reference': 'error',
38
- 'loop-characteristics': 'error',
39
- 'message-reference': 'error',
40
- 'no-template': 'error',
41
- 'subscription': 'error',
42
- 'user-task-form': 'error'
43
- }
54
+ rules: camundaCloud12Rules
44
55
  },
45
56
  'camunda-cloud-1-3': {
46
- rules: {
47
- 'called-decision-or-task-definition': [ 'error', calledDecisionOrTaskDefinitionConfig.camundaCloud13 ],
48
- 'called-element': 'error',
49
- 'element-type': [ 'error', elementTypeConfig.camundaCloud12 ],
50
- 'error-reference': 'error',
51
- 'loop-characteristics': 'error',
52
- 'message-reference': 'error',
53
- 'no-template': 'error',
54
- 'subscription': 'error',
55
- 'user-task-form': 'error'
56
- }
57
+ rules: camundaCloud13Rules
57
58
  },
58
59
  'camunda-cloud-8-0': {
59
- rules: {
60
- 'called-decision-or-task-definition': [ 'error', calledDecisionOrTaskDefinitionConfig.camundaCloud13 ],
61
- 'called-element': 'error',
62
- 'element-type': [ 'error', elementTypeConfig.camundaCloud12 ],
63
- 'error-reference': 'error',
64
- 'loop-characteristics': 'error',
65
- 'message-reference': 'error',
66
- 'subscription': 'error',
67
- 'user-task-form': 'error'
68
- }
60
+ rules: camundaCloud80Rules
61
+ },
62
+ 'camunda-cloud-8-1': {
63
+ rules: camundaCloud81Rules
69
64
  }
70
65
  }
71
66
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bpmnlint-plugin-camunda-compat",
3
- "version": "0.9.2",
3
+ "version": "0.12.0",
4
4
  "description": "A bpmnlint plug-in for Camunda Platform compatibility",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -23,21 +23,21 @@
23
23
  },
24
24
  "license": "MIT",
25
25
  "devDependencies": {
26
- "bpmn-moddle": "^7.1.2",
26
+ "bpmn-moddle": "^7.1.3",
27
27
  "bpmnlint": "^7.8.0",
28
- "chai": "^4.3.5",
29
- "eslint": "^7.32.0",
30
- "eslint-plugin-bpmn-io": "^0.13.0",
31
- "mocha": "^5.2.0",
28
+ "chai": "^4.3.6",
29
+ "eslint": "^8.23.0",
30
+ "eslint-plugin-bpmn-io": "^0.14.1",
31
+ "mocha": "^10.0.0",
32
32
  "modeler-moddle": "^0.1.0",
33
- "sinon": "^13.0.1",
33
+ "sinon": "^14.0.0",
34
34
  "sinon-chai": "^3.7.0",
35
- "zeebe-bpmn-moddle": "^0.12.1"
35
+ "zeebe-bpmn-moddle": "^0.14.0"
36
36
  },
37
37
  "dependencies": {
38
38
  "@bpmn-io/moddle-utils": "^0.1.0",
39
39
  "bpmnlint-utils": "^1.0.2",
40
- "min-dash": "^3.8.0"
40
+ "min-dash": "^3.8.1"
41
41
  },
42
42
  "files": [
43
43
  "rules",
@@ -8,9 +8,8 @@ const { getPath } = require('@bpmn-io/moddle-utils');
8
8
  const {
9
9
  findExtensionElement,
10
10
  getEventDefinition,
11
- hasProperties,
12
- hasExtensionElementOfType,
13
- hasExtensionElementsOfTypes
11
+ hasExtensionElement,
12
+ hasProperties
14
13
  } = require('../utils/element');
15
14
 
16
15
  const { reportErrors } = require('../utils/reporter');
@@ -99,14 +98,14 @@ module.exports = function(config) {
99
98
  }
100
99
 
101
100
  if (isAny(node, elementsCalledDecision) && isAny(node, elementsTaskDefinition)) {
102
- errors = hasExtensionElementsOfTypes(node, [
101
+ errors = hasExtensionElement(node, [
103
102
  'zeebe:CalledDecision',
104
103
  'zeebe:TaskDefinition'
105
- ], node, true);
104
+ ], node);
106
105
  } else if (isAny(node, elementsCalledDecision)) {
107
- errors = hasExtensionElementOfType(node, 'zeebe:CalledDecision', node);
106
+ errors = hasExtensionElement(node, 'zeebe:CalledDecision', node);
108
107
  } else {
109
- errors = hasExtensionElementOfType(node, 'zeebe:TaskDefinition', node);
108
+ errors = hasExtensionElement(node, 'zeebe:TaskDefinition', node);
110
109
  }
111
110
 
112
111
  if (errors && errors.length) {
@@ -2,7 +2,7 @@ const { is } = require('bpmnlint-utils');
2
2
 
3
3
  const {
4
4
  findExtensionElement,
5
- hasExtensionElementOfType,
5
+ hasExtensionElement,
6
6
  hasProperties
7
7
  } = require('./utils/element');
8
8
 
@@ -14,7 +14,7 @@ module.exports = function() {
14
14
  return;
15
15
  }
16
16
 
17
- let errors = hasExtensionElementOfType(node, 'zeebe:CalledElement', node);
17
+ let errors = hasExtensionElement(node, 'zeebe:CalledElement', node);
18
18
 
19
19
  if (errors && errors.length) {
20
20
  reportErrors(node, reporter, errors);
@@ -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
+ }
@@ -1,186 +1,121 @@
1
- module.exports = {
2
- camundaCloud10: {
3
- elements: [
4
- 'bpmn:Association',
5
- 'bpmn:BoundaryEvent',
6
- 'bpmn:CallActivity',
7
- 'bpmn:Collaboration',
8
- 'bpmn:Definitions',
9
- 'bpmn:EndEvent',
10
- 'bpmn:EventBasedGateway',
11
- 'bpmn:ExclusiveGateway',
12
- 'bpmn:Group',
13
- 'bpmn:IntermediateCatchEvent',
14
- 'bpmn:MessageFlow',
15
- 'bpmn:ParallelGateway',
16
- 'bpmn:Participant',
17
- 'bpmn:Process',
18
- 'bpmn:ReceiveTask',
19
- 'bpmn:SequenceFlow',
20
- 'bpmn:ServiceTask',
21
- 'bpmn:StartEvent',
22
- 'bpmn:SubProcess',
23
- 'bpmn:TextAnnotation',
24
- 'bpmn:UserTask'
25
- ],
26
- elementsNoEventDefinitionRequired: [
27
- 'bpmn:EndEvent',
28
- 'bpmn:StartEvent'
29
- ],
30
- eventDefinitions: {
31
- 'bpmn:BoundaryEvent': [
32
- 'bpmn:ErrorEventDefinition',
33
- 'bpmn:MessageEventDefinition',
34
- 'bpmn:TimerEventDefinition'
35
- ],
36
- 'bpmn:EndEvent': [
37
- 'bpmn:ErrorEventDefinition'
38
- ],
39
- 'bpmn:IntermediateCatchEvent': [
40
- 'bpmn:MessageEventDefinition',
41
- 'bpmn:TimerEventDefinition'
42
- ],
43
- 'bpmn:StartEvent': [
44
- 'bpmn:ErrorEventDefinition',
45
- 'bpmn:MessageEventDefinition',
46
- 'bpmn:TimerEventDefinition'
47
- ]
48
- }
49
- },
50
- camundaCloud11: {
51
- elements: [
1
+ const camundaCloud10Elements = [
2
+ 'bpmn:Association',
3
+ 'bpmn:BoundaryEvent',
4
+ 'bpmn:CallActivity',
5
+ 'bpmn:Collaboration',
6
+ 'bpmn:Definitions',
7
+ 'bpmn:EndEvent',
8
+ 'bpmn:EventBasedGateway',
9
+ 'bpmn:ExclusiveGateway',
10
+ 'bpmn:Group',
11
+ 'bpmn:IntermediateCatchEvent',
12
+ 'bpmn:MessageFlow',
13
+ 'bpmn:ParallelGateway',
14
+ 'bpmn:Participant',
15
+ 'bpmn:Process',
16
+ 'bpmn:ReceiveTask',
17
+ 'bpmn:SequenceFlow',
18
+ 'bpmn:ServiceTask',
19
+ 'bpmn:StartEvent',
20
+ 'bpmn:SubProcess',
21
+ 'bpmn:TextAnnotation',
22
+ 'bpmn:UserTask'
23
+ ];
52
24
 
53
- // 1.0
54
- 'bpmn:Association',
55
- 'bpmn:BoundaryEvent',
56
- 'bpmn:CallActivity',
57
- 'bpmn:Collaboration',
58
- 'bpmn:Definitions',
59
- 'bpmn:EndEvent',
60
- 'bpmn:EventBasedGateway',
61
- 'bpmn:ExclusiveGateway',
62
- 'bpmn:Group',
63
- 'bpmn:IntermediateCatchEvent',
64
- 'bpmn:MessageFlow',
65
- 'bpmn:ParallelGateway',
66
- 'bpmn:Participant',
67
- 'bpmn:Process',
68
- 'bpmn:ReceiveTask',
69
- 'bpmn:SequenceFlow',
70
- 'bpmn:ServiceTask',
71
- 'bpmn:StartEvent',
72
- 'bpmn:SubProcess',
73
- 'bpmn:TextAnnotation',
74
- 'bpmn:UserTask',
25
+ const camundaCloud11Elements = [
26
+ ...camundaCloud10Elements,
27
+ 'bpmn:BusinessRuleTask',
28
+ 'bpmn:IntermediateThrowEvent',
29
+ 'bpmn:ManualTask',
30
+ 'bpmn:ScriptTask',
31
+ 'bpmn:SendTask'
32
+ ];
75
33
 
76
- // 1.1
77
- 'bpmn:BusinessRuleTask',
78
- 'bpmn:IntermediateThrowEvent',
79
- 'bpmn:ManualTask',
80
- 'bpmn:ScriptTask',
81
- 'bpmn:SendTask'
82
- ],
83
- elementsNoEventDefinitionRequired: [
34
+ const camundaCloud12Elements = [
35
+ ...camundaCloud11Elements
36
+ ];
84
37
 
85
- // 1.0
86
- 'bpmn:EndEvent',
87
- 'bpmn:StartEvent',
38
+ const camundaCloud81Elements = [
39
+ ...camundaCloud12Elements,
40
+ 'bpmn:InclusiveGateway'
41
+ ];
88
42
 
89
- // 1.1
90
- 'bpmn:IntermediateThrowEvent'
91
- ],
92
- eventDefinitions: {
93
- 'bpmn:BoundaryEvent': [
94
- 'bpmn:ErrorEventDefinition',
95
- 'bpmn:MessageEventDefinition',
96
- 'bpmn:TimerEventDefinition'
97
- ],
98
- 'bpmn:EndEvent': [
99
- 'bpmn:ErrorEventDefinition'
100
- ],
101
- 'bpmn:IntermediateCatchEvent': [
102
- 'bpmn:MessageEventDefinition',
103
- 'bpmn:TimerEventDefinition'
104
- ],
105
- 'bpmn:StartEvent': [
106
- 'bpmn:ErrorEventDefinition',
107
- 'bpmn:MessageEventDefinition',
108
- 'bpmn:TimerEventDefinition'
109
- ]
110
- }
111
- },
112
- camundaCloud12: {
113
- elements: [
43
+ const camundaCloud10ElementsNoEventDefinitionRequired = [
44
+ 'bpmn:EndEvent',
45
+ 'bpmn:StartEvent'
46
+ ];
114
47
 
115
- // 1.0
116
- 'bpmn:Association',
117
- 'bpmn:BoundaryEvent',
118
- 'bpmn:CallActivity',
119
- 'bpmn:Collaboration',
120
- 'bpmn:Definitions',
121
- 'bpmn:EndEvent',
122
- 'bpmn:EventBasedGateway',
123
- 'bpmn:ExclusiveGateway',
124
- 'bpmn:Group',
125
- 'bpmn:IntermediateCatchEvent',
126
- 'bpmn:MessageFlow',
127
- 'bpmn:ParallelGateway',
128
- 'bpmn:Participant',
129
- 'bpmn:Process',
130
- 'bpmn:ReceiveTask',
131
- 'bpmn:SequenceFlow',
132
- 'bpmn:ServiceTask',
133
- 'bpmn:StartEvent',
134
- 'bpmn:SubProcess',
135
- 'bpmn:TextAnnotation',
136
- 'bpmn:UserTask',
48
+ const camundaCloud11ElementsNoEventDefinitionRequired = [
49
+ ...camundaCloud10ElementsNoEventDefinitionRequired,
50
+ 'bpmn:IntermediateThrowEvent'
51
+ ];
137
52
 
138
- // 1.1
139
- 'bpmn:BusinessRuleTask',
140
- 'bpmn:IntermediateThrowEvent',
141
- 'bpmn:ManualTask',
142
- 'bpmn:ScriptTask',
143
- 'bpmn:SendTask'
144
- ],
145
- elementsNoEventDefinitionRequired: [
53
+ const camundaCloud12ElementsNoEventDefinitionRequired = [
54
+ ...camundaCloud11ElementsNoEventDefinitionRequired
55
+ ];
146
56
 
147
- // 1.0
148
- 'bpmn:EndEvent',
149
- 'bpmn:StartEvent',
57
+ const camundaCloud81ElementsNoEventDefinitionRequired = [
58
+ ...camundaCloud12ElementsNoEventDefinitionRequired
59
+ ];
150
60
 
151
- // 1.1
152
- 'bpmn:IntermediateThrowEvent'
153
- ],
154
- eventDefinitions: {
61
+ const camundaCloud10EventDefinitions = {
62
+ 'bpmn:BoundaryEvent': [
63
+ 'bpmn:ErrorEventDefinition',
64
+ 'bpmn:MessageEventDefinition',
65
+ 'bpmn:TimerEventDefinition'
66
+ ],
67
+ 'bpmn:EndEvent': [
68
+ 'bpmn:ErrorEventDefinition'
69
+ ],
70
+ 'bpmn:IntermediateCatchEvent': [
71
+ 'bpmn:MessageEventDefinition',
72
+ 'bpmn:TimerEventDefinition'
73
+ ],
74
+ 'bpmn:StartEvent': [
75
+ 'bpmn:ErrorEventDefinition',
76
+ 'bpmn:MessageEventDefinition',
77
+ 'bpmn:TimerEventDefinition'
78
+ ]
79
+ };
155
80
 
156
- // 1.1
157
- 'bpmn:BoundaryEvent': [
158
- 'bpmn:ErrorEventDefinition',
159
- 'bpmn:MessageEventDefinition',
160
- 'bpmn:TimerEventDefinition'
161
- ],
162
- 'bpmn:EndEvent': [
81
+ const camundaCloud11EventDefinitions = {
82
+ ...camundaCloud10EventDefinitions
83
+ };
163
84
 
164
- // 1.0
165
- 'bpmn:ErrorEventDefinition',
85
+ const camundaCloud12EventDefinitions = {
86
+ ...camundaCloud11EventDefinitions,
87
+ 'bpmn:EndEvent': [
88
+ ...camundaCloud11EventDefinitions['bpmn:EndEvent'],
89
+ 'bpmn:MessageEventDefinition'
90
+ ],
91
+ 'bpmn:IntermediateThrowEvent': [
92
+ 'bpmn:MessageEventDefinition'
93
+ ]
94
+ };
166
95
 
167
- // 1.1
168
- 'bpmn:MessageEventDefinition'
169
- ],
170
- 'bpmn:IntermediateCatchEvent': [
171
- 'bpmn:MessageEventDefinition',
172
- 'bpmn:TimerEventDefinition'
173
- ],
174
- 'bpmn:StartEvent': [
175
- 'bpmn:ErrorEventDefinition',
176
- 'bpmn:MessageEventDefinition',
177
- 'bpmn:TimerEventDefinition'
178
- ],
96
+ const camundaCloud81EventDefinitions = {
97
+ ...camundaCloud12EventDefinitions
98
+ };
179
99
 
180
- // 1.2
181
- 'bpmn:IntermediateThrowEvent': [
182
- 'bpmn:MessageEventDefinition'
183
- ]
184
- }
100
+ module.exports = {
101
+ camundaCloud10: {
102
+ elements: camundaCloud10Elements,
103
+ elementsNoEventDefinitionRequired: camundaCloud10ElementsNoEventDefinitionRequired,
104
+ eventDefinitions: camundaCloud10EventDefinitions
105
+ },
106
+ camundaCloud11: {
107
+ elements: camundaCloud11Elements,
108
+ elementsNoEventDefinitionRequired: camundaCloud11ElementsNoEventDefinitionRequired,
109
+ eventDefinitions: camundaCloud11EventDefinitions
110
+ },
111
+ camundaCloud12: {
112
+ elements: camundaCloud12Elements,
113
+ elementsNoEventDefinitionRequired: camundaCloud12ElementsNoEventDefinitionRequired,
114
+ eventDefinitions: camundaCloud12EventDefinitions
115
+ },
116
+ camundaCloud81: {
117
+ elements: camundaCloud81Elements,
118
+ elementsNoEventDefinitionRequired: camundaCloud81ElementsNoEventDefinitionRequired,
119
+ eventDefinitions: camundaCloud81EventDefinitions
185
120
  }
186
121
  };
@@ -0,0 +1,52 @@
1
+ const { is } = require('bpmnlint-utils');
2
+
3
+ const { hasProperties, ERROR_TYPES } = require('./utils/element');
4
+
5
+ const { reportErrors } = require('./utils/reporter');
6
+
7
+ module.exports = function() {
8
+ function check(node, reporter) {
9
+ if (!is(node, 'bpmn:InclusiveGateway')) {
10
+ return;
11
+ }
12
+
13
+ const incoming = node.get('incoming');
14
+
15
+ if (incoming && incoming.length > 1) {
16
+ const error = {
17
+ message: `Element of type <${ node.$type }> must have one property <incoming> of type <bpmn:SequenceFlow>`,
18
+ path: [ 'incoming' ],
19
+ error: {
20
+ type: ERROR_TYPES.PROPERTY_NOT_ALLOWED,
21
+ node,
22
+ parentNode: null,
23
+ property: 'incoming'
24
+ }
25
+ };
26
+
27
+ reportErrors(node, reporter, error);
28
+ }
29
+
30
+ const outgoing = node.get('outgoing');
31
+
32
+ if (outgoing && outgoing.length > 1) {
33
+ for (let sequenceFlow of outgoing) {
34
+ if (node.get('default') !== sequenceFlow) {
35
+ const errors = hasProperties(sequenceFlow, {
36
+ conditionExpression: {
37
+ required: true
38
+ }
39
+ }, sequenceFlow);
40
+
41
+ if (errors.length) {
42
+ reportErrors(sequenceFlow, reporter, errors);
43
+ }
44
+ }
45
+ }
46
+ }
47
+ }
48
+
49
+ return {
50
+ check
51
+ };
52
+ };
@@ -3,7 +3,7 @@ const { is } = require('bpmnlint-utils');
3
3
  const {
4
4
  findExtensionElement,
5
5
  hasProperties,
6
- hasExtensionElementOfType
6
+ hasExtensionElement
7
7
  } = require('./utils/element');
8
8
 
9
9
  const { reportErrors } = require('./utils/reporter');
@@ -32,7 +32,7 @@ module.exports = function() {
32
32
  return;
33
33
  }
34
34
 
35
- errors = hasExtensionElementOfType(loopCharacteristics, 'zeebe:LoopCharacteristics', node);
35
+ errors = hasExtensionElement(loopCharacteristics, 'zeebe:LoopCharacteristics', node);
36
36
 
37
37
  if (errors && errors.length) {
38
38
  reportErrors(node, reporter, errors);
@@ -0,0 +1,23 @@
1
+ const { is } = require('bpmnlint-utils');
2
+
3
+ const { hasNoExtensionElement } = require('./utils/element');
4
+
5
+ const { reportErrors } = require('./utils/reporter');
6
+
7
+ module.exports = function() {
8
+ function check(node, reporter) {
9
+ if (!is(node, 'zeebe:PropertiesHolder')) {
10
+ return;
11
+ }
12
+
13
+ const errors = hasNoExtensionElement(node, 'zeebe:Properties', node);
14
+
15
+ if (errors && errors.length) {
16
+ reportErrors(node, reporter, errors);
17
+ }
18
+ }
19
+
20
+ return {
21
+ check
22
+ };
23
+ };
@@ -6,7 +6,7 @@ const {
6
6
  const {
7
7
  findExtensionElement,
8
8
  getEventDefinition,
9
- hasExtensionElementOfType,
9
+ hasExtensionElement,
10
10
  hasProperties
11
11
  } = require('./utils/element');
12
12
 
@@ -37,7 +37,7 @@ module.exports = function() {
37
37
  return;
38
38
  }
39
39
 
40
- let errors = hasExtensionElementOfType(messageRef, 'zeebe:Subscription', node);
40
+ let errors = hasExtensionElement(messageRef, 'zeebe:Subscription', node);
41
41
 
42
42
  if (errors && errors.length) {
43
43
  reportErrors(node, reporter, errors);
@@ -56,6 +56,8 @@ module.exports = function() {
56
56
  };
57
57
  };
58
58
 
59
+ // helpers //////////
60
+
59
61
  function findUserTaskForm(node, formKey) {
60
62
  const process = findParent(node, 'bpmn:Process');
61
63
 
@@ -5,7 +5,10 @@ const {
5
5
  some
6
6
  } = require('min-dash');
7
7
 
8
- const { isAny } = require('bpmnlint-utils');
8
+ const {
9
+ is,
10
+ isAny
11
+ } = require('bpmnlint-utils');
9
12
 
10
13
  const { getPath } = require('@bpmn-io/moddle-utils');
11
14
 
@@ -13,12 +16,22 @@ const { ERROR_TYPES } = require('./error-types');
13
16
 
14
17
  module.exports.ERROR_TYPES = ERROR_TYPES;
15
18
 
16
- module.exports.getEventDefinition = function(node) {
19
+ function getEventDefinition(node) {
17
20
  const eventDefinitions = node.get('eventDefinitions');
18
21
 
19
22
  if (eventDefinitions) {
20
23
  return eventDefinitions[ 0 ];
21
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);
22
35
  };
23
36
 
24
37
  function findExtensionElements(node, types) {
@@ -72,6 +85,50 @@ function formatTypes(types, exclusive = false) {
72
85
 
73
86
  module.exports.formatTypes = formatTypes;
74
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
+
75
132
  module.exports.hasProperties = function(node, properties, parentNode = null) {
76
133
  return Object.entries(properties).reduce((results, property) => {
77
134
  const [ propertyName, propertyChecks ] = property;
@@ -133,7 +190,7 @@ module.exports.hasProperties = function(node, properties, parentNode = null) {
133
190
  return [
134
191
  ...results,
135
192
  {
136
- message: `Property <${ propertyName }> of type <${ propertyValue.$type }> not allowed`,
193
+ message: `Element of type <${ node.$type }> must not have property <${ propertyName }> of type <${ propertyValue.$type }>`,
137
194
  path: path
138
195
  ? [ ...path, propertyName ]
139
196
  : [ propertyName ],
@@ -152,7 +209,7 @@ module.exports.hasProperties = function(node, properties, parentNode = null) {
152
209
  return [
153
210
  ...results,
154
211
  {
155
- message: `Property <${ propertyName }> not allowed`,
212
+ message: `Element of type <${ node.$type }> must not have property <${ propertyName }>`,
156
213
  path: path
157
214
  ? [ ...path, propertyName ]
158
215
  : [ propertyName ],
@@ -170,38 +227,21 @@ module.exports.hasProperties = function(node, properties, parentNode = null) {
170
227
  }, []);
171
228
  };
172
229
 
173
- module.exports.hasExtensionElementsOfTypes = function(node, types, parentNode = null, exclusive = false) {
174
- const extensionElements = findExtensionElements(node, types);
230
+ module.exports.hasExtensionElement = function(node, types, parentNode = null) {
231
+ const typesArray = isArray(types) ? types : [ types ];
175
232
 
176
- if (!extensionElements || !extensionElements.length) {
177
- return [
178
- {
179
- message: exclusive
180
- ? `Element of type <${ node.$type }> must have one extension element of type ${ formatTypes(types, true) }`
181
- : `Element of type <${ node.$type }> must have one or many extension elements of type ${ formatTypes(types, true) }`,
182
- path: getPath(node, parentNode),
183
- error: {
184
- type: ERROR_TYPES.EXTENSION_ELEMENT_REQUIRED,
185
- node,
186
- parentNode: parentNode == node ? null : parentNode,
187
- requiredExtensionElement: types,
188
- exclusive
189
- }
190
- }
191
- ];
192
- }
233
+ const extensionElements = findExtensionElements(node, typesArray);
193
234
 
194
- if (exclusive && extensionElements.length > 1) {
235
+ if (!extensionElements || extensionElements.length !== 1) {
195
236
  return [
196
237
  {
197
- message: `Element of type <${ node.$type }> must have one extension element of type ${ formatTypes(types, true) }`,
238
+ message: `Element of type <${ node.$type }> must have one extension element of type ${ formatTypes(typesArray, true) }`,
198
239
  path: getPath(node, parentNode),
199
240
  error: {
200
241
  type: ERROR_TYPES.EXTENSION_ELEMENT_REQUIRED,
201
242
  node,
202
243
  parentNode: parentNode == node ? null : parentNode,
203
- requiredExtensionElement: types,
204
- exclusive
244
+ requiredExtensionElement: types
205
245
  }
206
246
  }
207
247
  ];
@@ -210,19 +250,19 @@ module.exports.hasExtensionElementsOfTypes = function(node, types, parentNode =
210
250
  return [];
211
251
  };
212
252
 
213
- module.exports.hasExtensionElementOfType = function(node, type, parentNode = null) {
253
+ module.exports.hasNoExtensionElement = function(node, type, parentNode = null) {
214
254
  const extensionElement = findExtensionElement(node, type);
215
255
 
216
- if (!extensionElement) {
256
+ if (extensionElement) {
217
257
  return [
218
258
  {
219
- message: `Element of type <${ node.$type }> must have extension element of type <${ type }>`,
220
- path: getPath(node, parentNode),
259
+ message: `Element of type <${ node.$type }> must not have extension element of type <${ type }>`,
260
+ path: getPath(extensionElement, parentNode),
221
261
  error: {
222
- type: ERROR_TYPES.EXTENSION_ELEMENT_REQUIRED,
262
+ type: ERROR_TYPES.EXTENSION_ELEMENT_NOT_ALLOWED,
223
263
  node,
224
264
  parentNode: parentNode == node ? null : parentNode,
225
- requiredExtensionElement: type
265
+ extensionElement
226
266
  }
227
267
  }
228
268
  ];
@@ -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/CHANGELOG.md DELETED
@@ -1,87 +0,0 @@
1
- # Changelog
2
-
3
- All notable changes to [bpmnlint-plugin-camunda-compat](https://github.com/camunda/bpmnlint-plugin-camunda-compat) are documented here. We use [semantic versioning](http://semver.org/) for releases.
4
-
5
- ## Unreleased
6
-
7
- ___Note:__ Yet to be released changes appear here._
8
-
9
- ## 0.9.2
10
-
11
- * `FIX`: ignore null properties ([#39](https://github.com/camunda/bpmnlint-plugin-camunda-compat/pull/39))
12
-
13
- ## 0.9.1
14
-
15
- * `FIX`: add name to reports ([#38](https://github.com/camunda/bpmnlint-plugin-camunda-compat/pull/38))
16
-
17
- ## 0.9.0
18
-
19
- * `FEAT`: add user task forms rule ([#32](https://github.com/camunda/bpmnlint-plugin-camunda-compat/pull/32))
20
-
21
- ## 0.8.0
22
-
23
- * `FEAT`: add templates rule ([#31](https://github.com/camunda/bpmnlint-plugin-camunda-compat/pull/31))
24
-
25
- ## 0.7.1
26
-
27
- * `FIX`: lint subscription only if start event child of sub process ([#34](https://github.com/camunda/bpmnlint-plugin-camunda-compat/pull/34))
28
-
29
- ## 0.7.0
30
-
31
- * `FEAT`: refactor plugin structure ([#29](https://github.com/camunda/bpmnlint-plugin-camunda-compat/pull/29))
32
- * `DEPS`: update to `bpmnlint@7.8.0` ([#29](https://github.com/camunda/bpmnlint-plugin-camunda-compat/pull/29))
33
-
34
- ### Breaking Changes
35
-
36
- * configuration not selected based on execution platform and version anymore, either configure manually or use [`@camunda/linting`](https://github.com/camunda/linting)
37
- * error message not adjusted to be shown in Camunda Modeler anymore
38
- * error type ELEMENT_TYPE changed to ELEMENT_TYPE_NOT_ALLOWED
39
- * error type PROPERTY_TYPE changed to PROPERTY_TYPE_NOT_ALLOWED
40
- * error data changed (cf. docs/ERRORS.md)
41
-
42
- ## 0.6.2
43
-
44
- * `FIX`: fix error message formatting ([#27](https://github.com/camunda/bpmnlint-plugin-camunda-compat/pull/27))
45
-
46
- ## 0.6.1
47
-
48
- * `FIX`: lanes supported ([#26](https://github.com/camunda/bpmnlint-plugin-camunda-compat/pull/26))
49
-
50
- ## 0.6.0
51
-
52
- * `FEAT`: adjust error messages to be more friendly ([#22](https://github.com/camunda/bpmnlint-plugin-camunda-compat/pull/22))
53
- * `FEAT`: lint error code and message name ([#21](https://github.com/camunda/bpmnlint-plugin-camunda-compat/pull/21))
54
- * `FIX`: task definition retries not required ([#20](https://github.com/camunda/bpmnlint-plugin-camunda-compat/pull/20))
55
-
56
- ## 0.5.0
57
-
58
- * `FEAT`: update Camunda Cloud rules to lint extension elements and their properties ([#18](https://github.com/camunda/bpmnlint-plugin-camunda-compat/pull/18))
59
-
60
- ## 0.4.0
61
-
62
- * `CHORE`: rename `Cloud` `1.4` to `8.0` ([#14](https://github.com/camunda/bpmnlint-plugin-camunda-compat/pull/14))
63
- * `CHORE`: rename `Cloud` to `Platform`/`Zeebe` ([#15](https://github.com/camunda/bpmnlint-plugin-camunda-compat/pull/15))
64
-
65
- ## 0.3.0
66
-
67
- * `FEAT`: support multiInstance for subprocesses with cloud 1.0 ([#6](https://github.com/camunda/bpmnlint-plugin-camunda-compat/pull/6))
68
- * `FEAT`: add Camunda Platform rules ([#5](https://github.com/camunda/bpmnlint-plugin-camunda-compat/pull/5))
69
- * `FEAT`: add Camunda Cloud 1.4 rule ([#5](https://github.com/camunda/bpmnlint-plugin-camunda-compat/pull/5))
70
- * `TEST`: add Cloud 1.1, 1.2, 1.3 integration tests ([#4](https://github.com/camunda/bpmnlint-plugin-camunda-compat/pull/4))
71
- * `TEST`: verify exported configs ([#5](https://github.com/camunda/bpmnlint-plugin-camunda-compat/pull/5))
72
- * `DEPS`: fix security audit warnings ([#6](https://github.com/camunda/bpmnlint-plugin-camunda-compat/pull/6))
73
- * `DOCS`: update link to documentation
74
- * `DOCS`: link Camunda Cloud and Platform BPMN coverage
75
-
76
- ## 0.2.0
77
-
78
- * `FEAT`: early return if execution platform does not match
79
- * `FIX`: correct check for `bpmn:BaseElement`
80
-
81
- ## 0.1.1
82
-
83
- * `FEAT`: initial support for Camunda Cloud 1.0, 1.1, 1.2, and 1.3
84
-
85
- ## ...
86
-
87
- Check `git log` for earlier history.