@camunda/linting 0.8.0 → 0.9.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/lib/Linter.js CHANGED
@@ -10,9 +10,11 @@ import { isString } from 'min-dash';
10
10
  import modelerModdle from 'modeler-moddle/resources/modeler.json';
11
11
  import zeebeModdle from 'zeebe-bpmn-moddle/resources/zeebe.json';
12
12
 
13
- import { getErrorMessage, getExecutionPlatformLabel } from './utils/error-messages';
13
+ import { getErrorMessage } from './utils/error-messages';
14
14
  import { getEntryIds } from './utils/properties-panel';
15
15
 
16
+ import { toSemverMinor } from './utils/version';
17
+
16
18
  const moddle = new BpmnModdle({
17
19
  modeler: modelerModdle,
18
20
  zeebe: zeebeModdle
@@ -68,7 +70,8 @@ export class Linter {
68
70
  ...report,
69
71
  message: getErrorMessage(
70
72
  report,
71
- getExecutionPlatformLabel(executionPlatform, toSemverMinor(executionPlatformVersion)),
73
+ executionPlatform,
74
+ executionPlatformVersion,
72
75
  this._modeler
73
76
  ),
74
77
  propertiesPanel: {
@@ -132,10 +135,6 @@ function toLowerCase(string) {
132
135
  return string.toLowerCase();
133
136
  }
134
137
 
135
- function toSemverMinor(executionPlatformVersion) {
136
- return executionPlatformVersion.split('.').slice(0, 2).join('.');
137
- }
138
-
139
138
  async function createCache(configName) {
140
139
  let config = require('bpmnlint-plugin-camunda-compat').configs[ configName ];
141
140
 
@@ -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
+
4
5
  import {
5
6
  every,
6
7
  isArray
@@ -8,30 +9,78 @@ import {
8
9
 
9
10
  import { getTypeString } from './types';
10
11
 
12
+ import { toSemverMinor } from './version';
13
+
11
14
  const TIMER_PROPERTIES = [
15
+ 'timeCycle',
12
16
  'timeDate',
13
- 'timeDuration',
14
- 'timeCycle'
17
+ 'timeDuration'
15
18
  ];
16
19
 
17
- export function getErrorMessage(report, executionPlatformLabel, modeler = 'desktop') {
20
+ const executionPlatformLabels = {
21
+ 'Camunda Cloud': {
22
+ 'default': 'Camunda',
23
+ '1.0': 'Camunda 8 (Zeebe 1.0)',
24
+ '1.1': 'Camunda 8 (Zeebe 1.1)',
25
+ '1.2': 'Camunda 8 (Zeebe 1.2)',
26
+ '1.3': 'Camunda 8 (Zeebe 1.3)'
27
+ }
28
+ };
29
+
30
+ export function getExecutionPlatformLabel(executionPlatform, executionPlatformVersion) {
31
+ const executionPlatformLabel = executionPlatformLabels[ executionPlatform ]
32
+ && executionPlatformLabels[ executionPlatform ][ toSemverMinor(executionPlatformVersion) ];
33
+
34
+ if (executionPlatformLabel) {
35
+ return executionPlatformLabel;
36
+ }
37
+
38
+ if (executionPlatformLabels[ executionPlatform ]
39
+ && executionPlatformLabels[ executionPlatform ][ 'default' ]) {
40
+ executionPlatform = executionPlatformLabels[ executionPlatform ][ 'default' ];
41
+ }
42
+
43
+ return `${ executionPlatform } ${ toSemverMinor(executionPlatformVersion) }`;
44
+ }
45
+
46
+ function getIndefiniteArticle(type) {
47
+ if ([
48
+ 'Ad',
49
+ 'Error',
50
+ 'Escalation',
51
+ 'Event',
52
+ 'Inclusive',
53
+ 'Intermediate',
54
+ 'Undefined'
55
+ ].includes(type.split(' ')[ 0 ])) {
56
+ return 'An';
57
+ }
58
+
59
+ return 'A';
60
+ }
61
+
62
+ export function getErrorMessage(report, executionPlatform, executionPlatformVersion, modeler = 'desktop') {
18
63
  const {
19
- error,
64
+ data,
20
65
  message
21
66
  } = report;
22
67
 
23
- if (!error) {
68
+ if (!data) {
24
69
  return message;
25
70
  }
26
71
 
27
- const { type } = error;
72
+ const { type } = data;
73
+
74
+ if (type === ERROR_TYPES.ELEMENT_COLLAPSED_NOT_ALLOWED) {
75
+ return getElementCollapsedNotAllowedErrorMessage(report);
76
+ }
28
77
 
29
78
  if (type === ERROR_TYPES.ELEMENT_TYPE_NOT_ALLOWED) {
30
- return getElementTypeNotAllowedErrorMessage(report, executionPlatformLabel);
79
+ return getElementTypeNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion);
31
80
  }
32
81
 
33
82
  if (type === ERROR_TYPES.EXTENSION_ELEMENT_NOT_ALLOWED) {
34
- return getExtensionElementNotAllowedErrorMessage(report, executionPlatformLabel);
83
+ return getExtensionElementNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion);
35
84
  }
36
85
 
37
86
  if (type === ERROR_TYPES.EXTENSION_ELEMENT_REQUIRED) {
@@ -43,80 +92,61 @@ export function getErrorMessage(report, executionPlatformLabel, modeler = 'deskt
43
92
  }
44
93
 
45
94
  if (type === ERROR_TYPES.PROPERTY_NOT_ALLOWED) {
46
- return getPropertyNotAllowedErrorMessage(report, executionPlatformLabel, modeler);
95
+ return getPropertyNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion, modeler);
47
96
  }
48
97
 
49
98
  if (type === ERROR_TYPES.PROPERTY_REQUIRED) {
50
- return getPropertyRequiredErrorMessage(report, executionPlatformLabel);
51
- }
52
-
53
- if (type === ERROR_TYPES.PROPERTY_TYPE_NOT_ALLOWED) {
54
- return getPropertyTypeNotAllowedErrorMessage(report, executionPlatformLabel);
99
+ return getPropertyRequiredErrorMessage(report);
55
100
  }
56
101
 
57
102
  if (type === ERROR_TYPES.PROPERTY_VALUE_DUPLICATED) {
58
103
  return getPropertyValueDuplicatedErrorMessage(report);
59
104
  }
60
105
 
61
- if (type === ERROR_TYPES.PROPERTY_VALUE_NOT_ALLOWED) {
62
- return getPropertyValueNotAllowedErrorMessage(report, executionPlatformLabel);
106
+ if (type === ERROR_TYPES.EXPRESSION_REQUIRED) {
107
+ return getExpressionRequiredErrorMessage(report);
63
108
  }
64
109
 
65
- return message;
66
- }
67
-
68
- const executionPlatformLabels = {
69
- 'Camunda Cloud': {
70
- 'defaultPlatformName': 'Camunda',
71
- '1.0': 'Camunda 8 (Zeebe 1.0)',
72
- '1.1': 'Camunda 8 (Zeebe 1.1)',
73
- '1.2': 'Camunda 8 (Zeebe 1.2)',
74
- '1.3': 'Camunda 8 (Zeebe 1.3)'
110
+ if (type === ERROR_TYPES.EXPRESSION_VALUE_NOT_ALLOWED) {
111
+ return getExpressionValueNotAllowedErrorMessage(report);
75
112
  }
76
- };
77
113
 
78
- export function getExecutionPlatformLabel(executionPlatform, executionPlatformVersion) {
79
- const translatedLabel = executionPlatformLabels[ executionPlatform ] && executionPlatformLabels[ executionPlatform ][ executionPlatformVersion ];
114
+ return message;
115
+ }
80
116
 
81
- if (translatedLabel) {
82
- return translatedLabel;
83
- }
117
+ function getElementCollapsedNotAllowedErrorMessage(report) {
118
+ const {
119
+ data,
120
+ message
121
+ } = report;
84
122
 
85
- if (executionPlatformLabels[executionPlatform] && executionPlatformLabels[executionPlatform]['defaultPlatformName']) {
86
- executionPlatform = executionPlatformLabels[executionPlatform]['defaultPlatformName'];
87
- }
123
+ const { node } = data;
88
124
 
89
- return `${ executionPlatform } ${ executionPlatformVersion }`;
90
- }
125
+ const typeString = getTypeString(node);
91
126
 
92
- function getIndefiniteArticle(type) {
93
- if ([
94
- 'Error',
95
- 'Escalation',
96
- 'Event',
97
- 'Inclusive',
98
- 'Intermediate',
99
- 'Undefined'
100
- ].includes(type.split(' ')[ 0 ])) {
101
- return 'An';
127
+ if (is(node, 'bpmn:SubProcess')) {
128
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> must be expanded`;
102
129
  }
103
130
 
104
- return 'A';
131
+ return message;
105
132
  }
106
133
 
107
- function getElementTypeNotAllowedErrorMessage(report, executionPlatformLabel) {
108
- const { error } = report;
134
+ function getElementTypeNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion) {
135
+ const { data } = report;
109
136
 
110
- const { node } = error;
137
+ const {
138
+ allowedVersion,
139
+ node
140
+ } = data;
111
141
 
112
142
  const typeString = getTypeString(node);
113
143
 
114
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> is not supported by ${ executionPlatformLabel }`;
144
+ return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }>`, executionPlatform, executionPlatformVersion, allowedVersion);
115
145
  }
116
146
 
117
147
  function getPropertyValueDuplicatedErrorMessage(report) {
118
148
  const {
119
- error,
149
+ data,
120
150
  message
121
151
  } = report;
122
152
 
@@ -125,7 +155,7 @@ function getPropertyValueDuplicatedErrorMessage(report) {
125
155
  parentNode,
126
156
  duplicatedPropertyValue,
127
157
  properties
128
- } = error;
158
+ } = data;
129
159
 
130
160
  const typeString = getTypeString(parentNode || node);
131
161
 
@@ -136,26 +166,27 @@ function getPropertyValueDuplicatedErrorMessage(report) {
136
166
  return message;
137
167
  }
138
168
 
139
- function getExtensionElementNotAllowedErrorMessage(report, executionPlatformLabel) {
169
+ function getExtensionElementNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion) {
140
170
  const {
141
- error,
171
+ data,
142
172
  message
143
173
  } = report;
144
174
 
145
175
  const {
176
+ allowedVersion,
146
177
  node,
147
178
  parentNode,
148
179
  extensionElement
149
- } = error;
180
+ } = data;
150
181
 
151
182
  const typeString = getTypeString(parentNode || node);
152
183
 
153
184
  if (is(node, 'bpmn:BusinessRuleTask') && is(extensionElement, 'zeebe:CalledDecision')) {
154
- return `A <Business Rule Task> with <Implementation: DMN decision> is not supported by ${ executionPlatformLabel }`;
185
+ return getSupportedMessage('A <Business Rule Task> with <Implementation: DMN decision>', executionPlatform, executionPlatformVersion, allowedVersion);
155
186
  }
156
187
 
157
188
  if (is(extensionElement, 'zeebe:Properties')) {
158
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Extension properties> is not supported by ${ executionPlatformLabel }`;
189
+ return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Extension properties>`, executionPlatform, executionPlatformVersion, allowedVersion);
159
190
  }
160
191
 
161
192
  return message;
@@ -163,7 +194,7 @@ function getExtensionElementNotAllowedErrorMessage(report, executionPlatformLabe
163
194
 
164
195
  function getExtensionElementRequiredErrorMessage(report) {
165
196
  const {
166
- error,
197
+ data,
167
198
  message
168
199
  } = report;
169
200
 
@@ -171,7 +202,7 @@ function getExtensionElementRequiredErrorMessage(report) {
171
202
  node,
172
203
  parentNode,
173
204
  requiredExtensionElement
174
- } = error;
205
+ } = data;
175
206
 
176
207
  const typeString = getTypeString(parentNode || node);
177
208
 
@@ -200,7 +231,7 @@ function getExtensionElementRequiredErrorMessage(report) {
200
231
 
201
232
  function getPropertyDependendRequiredErrorMessage(report) {
202
233
  const {
203
- error,
234
+ data,
204
235
  message
205
236
  } = report;
206
237
 
@@ -209,7 +240,7 @@ function getPropertyDependendRequiredErrorMessage(report) {
209
240
  parentNode,
210
241
  property,
211
242
  dependendRequiredProperty
212
- } = error;
243
+ } = data;
213
244
 
214
245
  const typeString = getTypeString(parentNode || node);
215
246
 
@@ -224,39 +255,40 @@ function getPropertyDependendRequiredErrorMessage(report) {
224
255
  return message;
225
256
  }
226
257
 
227
- function getPropertyNotAllowedErrorMessage(report, executionPlatformLabel, modeler = 'desktop') {
258
+ function getPropertyNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion, modeler = 'desktop') {
228
259
  const {
229
- error,
260
+ data,
230
261
  message
231
262
  } = report;
232
263
 
233
264
  const {
265
+ allowedVersion,
234
266
  node,
235
267
  parentNode,
236
268
  property
237
- } = error;
269
+ } = data;
238
270
 
239
271
  const typeString = getTypeString(parentNode || node);
240
272
 
241
273
  if (property === 'modelerTemplate') {
242
274
  if (modeler === 'desktop') {
243
- return `${ getIndefiniteArticle(typeString) } <Template ${ typeString }> is not supported by ${ executionPlatformLabel }`;
275
+ return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <Template ${ typeString }>`, executionPlatform, executionPlatformVersion, allowedVersion);
244
276
  } else if (modeler === 'web') {
245
- return `${ getIndefiniteArticle(typeString) } <Connector ${ typeString }> is not supported by ${ executionPlatformLabel }`;
277
+ return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <Connector ${ typeString }>`, executionPlatform, executionPlatformVersion, allowedVersion);
246
278
  }
247
279
  }
248
280
 
249
281
  if (is(node, 'bpmn:InclusiveGateway') && property === 'incoming') {
250
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with more than one incoming <Sequence Flow> is not supported by ${ executionPlatformLabel }`;
282
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with more than one incoming <Sequence Flow> is not supported by ${ getExecutionPlatformLabel(executionPlatform, executionPlatformVersion) }`;
251
283
  }
252
284
 
253
285
  return message;
254
286
  }
255
287
 
256
288
 
257
- function getPropertyRequiredErrorMessage(report, executionPlatformLabel) {
289
+ function getPropertyRequiredErrorMessage(report) {
258
290
  const {
259
- error,
291
+ data,
260
292
  message
261
293
  } = report;
262
294
 
@@ -264,7 +296,7 @@ function getPropertyRequiredErrorMessage(report, executionPlatformLabel) {
264
296
  node,
265
297
  parentNode,
266
298
  requiredProperty
267
- } = error;
299
+ } = data;
268
300
 
269
301
  const typeString = getTypeString(parentNode || node);
270
302
 
@@ -288,10 +320,6 @@ function getPropertyRequiredErrorMessage(report, executionPlatformLabel) {
288
320
  return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Error Reference> must have a defined <Error code>`;
289
321
  }
290
322
 
291
- if (is(node, 'bpmn:Event') && requiredProperty === 'eventDefinitions') {
292
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> is not supported by ${ executionPlatformLabel }`;
293
- }
294
-
295
323
  if (is(node, 'zeebe:LoopCharacteristics') && requiredProperty === 'inputCollection') {
296
324
  return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Multi-instance marker> must have a defined <Input collection>`;
297
325
  }
@@ -339,72 +367,57 @@ function getPropertyRequiredErrorMessage(report, executionPlatformLabel) {
339
367
  return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Timer duration>`;
340
368
  }
341
369
 
342
- if (is(node, 'bpmn:FormalExpression')
343
- && requiredProperty === 'body'
344
- && TIMER_PROPERTIES.includes(secondLast(report.path))
345
- ) {
346
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Timer value>`;
347
- }
348
-
349
370
  return message;
350
371
  }
351
372
 
352
- function getPropertyTypeNotAllowedErrorMessage(report, executionPlatformLabel) {
373
+ function getExpressionRequiredErrorMessage(report) {
353
374
  const {
354
- error,
355
- message
375
+ data
356
376
  } = report;
357
377
 
358
378
  const {
359
379
  node,
360
380
  parentNode,
361
381
  property
362
- } = error;
382
+ } = data;
363
383
 
364
384
  const typeString = getTypeString(parentNode || node);
365
385
 
366
- if (is(node, 'bpmn:Event') && property === 'eventDefinitions') {
367
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> is not supported by ${ executionPlatformLabel }`;
386
+ if (is(node, 'bpmn:FormalExpression') && TIMER_PROPERTIES.includes(property)) {
387
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Timer value>`;
368
388
  }
369
-
370
- return message;
371
389
  }
372
390
 
373
- function getPropertyValueNotAllowedErrorMessage(report, executionPlatformLabel) {
391
+ function getExpressionValueNotAllowedErrorMessage(report) {
374
392
  const {
375
- error
393
+ data
376
394
  } = report;
377
395
 
378
396
  const {
379
397
  node,
380
398
  parentNode,
381
399
  property
382
- } = error;
400
+ } = data;
383
401
 
384
402
  const typeString = getTypeString(parentNode || node);
385
403
 
386
- if (is(node, 'bpmn:FormalExpression')
387
- && property === 'body'
388
- && secondLast(report.path) === 'timeCycle'
389
- ) {
404
+ if (is(node, 'bpmn:FormalExpression') && property === 'timeCycle') {
390
405
  return `${ getIndefiniteArticle(typeString) } <${ typeString }> <Time cycle> should be an expression, an ISO 8601 repeating interval, or a cron expression (cron requires Camunda Platform 8.1 or newer)`;
391
406
  }
392
407
 
393
- if (is(node, 'bpmn:FormalExpression')
394
- && property === 'body'
395
- && secondLast(report.path) === 'timeDate'
396
- ) {
408
+ if (is(node, 'bpmn:FormalExpression') && property === 'timeDate') {
397
409
  return `${ getIndefiniteArticle(typeString) } <${ typeString }> <Time date> should be an expression, or an ISO 8601 date`;
398
410
  }
399
411
 
400
- if (is(node, 'bpmn:FormalExpression')
401
- && property === 'body'
402
- && secondLast(report.path) === 'timeDuration'
403
- ) {
412
+ if (is(node, 'bpmn:FormalExpression') && property === 'timeDuration') {
404
413
  return `${ getIndefiniteArticle(typeString) } <${ typeString }> <Time duration> should be an expression, or an ISO 8601 interval`;
405
414
  }
406
415
  }
407
416
 
408
- function secondLast(array) {
409
- return array[array.length - 2];
410
- }
417
+ function getSupportedMessage(prefix, executionPlatform, executionPlatformVersion, allowedVersion) {
418
+ if (allowedVersion) {
419
+ return `${ prefix } is only supported by ${ getExecutionPlatformLabel(executionPlatform, allowedVersion) } or newer`;
420
+ }
421
+
422
+ return `${ prefix } is not supported by ${ getExecutionPlatformLabel(executionPlatform, executionPlatformVersion) }`;
423
+ }
@@ -46,80 +46,85 @@ export function getErrors(reports, element) {
46
46
 
47
47
  export function getEntryIds(report) {
48
48
  const {
49
- error = {},
50
- id
49
+ data = {},
50
+ id,
51
+ path
51
52
  } = report;
52
53
 
53
- if (isExtensionElementRequiredError(error, 'zeebe:CalledDecision', 'bpmn:BusinessRuleTask')) {
54
+ if (isExtensionElementRequiredError(data, 'zeebe:CalledDecision', 'bpmn:BusinessRuleTask')) {
54
55
  return [ 'businessRuleImplementation' ];
55
56
  }
56
57
 
57
- if (isPropertyRequiredError(error, 'errorRef')) {
58
+ if (isPropertyError(data, 'errorRef')) {
58
59
  return [ 'errorRef' ];
59
60
  }
60
61
 
61
- if (isPropertyRequiredError(error, 'messageRef')) {
62
+ if (isPropertyError(data, 'messageRef')) {
62
63
  return [ 'messageRef' ];
63
64
  }
64
65
 
65
- if (isPropertyRequiredError(error, 'decisionId', 'zeebe:CalledDecision')) {
66
+ if (isPropertyError(data, 'decisionId', 'zeebe:CalledDecision')) {
66
67
  return [ 'decisionId' ];
67
68
  }
68
69
 
69
- if (isPropertyRequiredError(error, 'resultVariable', 'zeebe:CalledDecision')) {
70
+ if (isPropertyError(data, 'resultVariable', 'zeebe:CalledDecision')) {
70
71
  return [ 'resultVariable' ];
71
72
  }
72
73
 
73
- if (isPropertyRequiredError(error, 'errorCode', 'bpmn:Error')) {
74
+ if (isPropertyError(data, 'errorCode', 'bpmn:Error')) {
74
75
  return [ 'errorCode' ];
75
76
  }
76
77
 
77
- if (isPropertyRequiredError(error, 'name', 'bpmn:Message')) {
78
+ if (isPropertyError(data, 'name', 'bpmn:Message')) {
78
79
  return [ 'messageName' ];
79
80
  }
80
81
 
81
- if (isExtensionElementRequiredError(error, 'zeebe:LoopCharacteristics', 'bpmn:MultiInstanceLoopCharacteristics')
82
- || isPropertyRequiredError(error, 'inputCollection', 'zeebe:LoopCharacteristics')) {
82
+ if (isExtensionElementRequiredError(data, 'zeebe:LoopCharacteristics', 'bpmn:MultiInstanceLoopCharacteristics')
83
+ || isPropertyError(data, 'inputCollection', 'zeebe:LoopCharacteristics')) {
83
84
  return [ 'multiInstance-inputCollection' ];
84
85
  }
85
86
 
86
- if (isPropertyDependendRequiredError(error, 'outputCollection', 'zeebe:LoopCharacteristics')) {
87
+ if (isPropertyDependendRequiredError(data, 'outputCollection', 'zeebe:LoopCharacteristics')) {
87
88
  return [ 'multiInstance-outputCollection' ];
88
89
  }
89
90
 
90
- if (isPropertyDependendRequiredError(error, 'outputElement', 'zeebe:LoopCharacteristics')) {
91
+ if (isPropertyDependendRequiredError(data, 'outputElement', 'zeebe:LoopCharacteristics')) {
91
92
  return [ 'multiInstance-outputElement' ];
92
93
  }
93
94
 
94
- if (isExtensionElementRequiredError(error, 'zeebe:CalledElement', 'bpmn:CallActivity')
95
- || isPropertyRequiredError(error, 'processId', 'zeebe:CalledElement')) {
95
+ if (isExtensionElementRequiredError(data, 'zeebe:CalledElement', 'bpmn:CallActivity')
96
+ || isPropertyError(data, 'processId', 'zeebe:CalledElement')) {
96
97
  return [ 'targetProcessId' ];
97
98
  }
98
99
 
99
- if (isExtensionElementRequiredError(error, 'zeebe:TaskDefinition')
100
- || isPropertyRequiredError(error, 'type', 'zeebe:TaskDefinition')) {
100
+ if (isExtensionElementRequiredError(data, 'zeebe:TaskDefinition')
101
+ || isPropertyError(data, 'type', 'zeebe:TaskDefinition')) {
101
102
  return [ 'taskDefinitionType' ];
102
103
  }
103
104
 
104
- if (isExtensionElementRequiredError(error, 'zeebe:Subscription')
105
- || isPropertyRequiredError(error, 'correlationKey', 'zeebe:Subscription')) {
105
+ if (isPropertyError(data, 'retries', 'zeebe:TaskDefinition')) {
106
+ return [ 'taskDefinitionRetries' ];
107
+ }
108
+
109
+ if (isExtensionElementRequiredError(data, 'zeebe:Subscription')
110
+ || isPropertyError(data, 'correlationKey', 'zeebe:Subscription')) {
106
111
  return [ 'messageSubscriptionCorrelationKey' ];
107
112
  }
108
113
 
109
- if (isPropertyRequiredError(error, 'formKey', 'zeebe:FormDefinition')) {
114
+ if (isPropertyError(data, 'formKey', 'zeebe:FormDefinition')) {
110
115
  return [ 'customFormKey' ];
111
116
  }
112
117
 
113
- if (isPropertyRequiredError(error, 'body', 'zeebe:UserTaskForm')) {
118
+ if (isPropertyError(data, 'body', 'zeebe:UserTaskForm')) {
114
119
  return [ 'formConfiguration' ];
115
120
  }
116
121
 
117
- if (isPropertyValueDuplicatedError(error, 'values', 'key', 'zeebe:TaskHeaders')) {
122
+ if (isPropertyValueDuplicatedError(data, 'values', 'key', 'zeebe:TaskHeaders')) {
118
123
  const {
119
124
  node,
120
125
  properties,
121
126
  propertiesName
122
- } = error;
127
+ } = data;
123
128
 
124
129
  return properties.map(property => {
125
130
  const index = node.get(propertiesName).indexOf(property);
@@ -128,40 +133,76 @@ export function getEntryIds(report) {
128
133
  });
129
134
  }
130
135
 
131
- if (isExtensionElementNotAllowedError(error, 'zeebe:Properties')) {
132
- const { extensionElement } = error;
136
+ if (isExtensionElementNotAllowedError(data, 'zeebe:Properties')) {
137
+ const { extensionElement } = data;
133
138
 
134
139
  return extensionElement.get('zeebe:properties').map((zeebeProperty, index) => {
135
140
  return `${ id }-extensionProperty-${ index }-name`;
136
141
  });
137
142
  }
138
143
 
139
- if (isPropertyRequiredError(error, 'conditionExpression', 'bpmn:SequenceFlow')) {
144
+ if (isPropertyError(data, 'conditionExpression', 'bpmn:SequenceFlow')) {
140
145
  return [ 'conditionExpression' ];
141
146
  }
142
147
 
143
- if (isPropertyRequiredError(error, 'timeDuration', 'bpmn:TimerEventDefinition')) {
148
+ if (isPropertyError(data, 'timeDuration', 'bpmn:TimerEventDefinition')) {
144
149
  return [ 'timerEventDefinitionDurationValue' ];
145
150
  }
146
151
 
152
+ if (isPropertyError(data, 'completionCondition', 'bpmn:MultiInstanceLoopCharacteristics')) {
153
+ return [ 'multiInstance-completionCondition' ];
154
+ }
155
+
147
156
  if (TIMER_PROPERTIES.some(property =>
148
- isOneOfPropertiesRequiredError(error, property , 'bpmn:TimerEventDefinition'))
157
+ isOneOfPropertiesRequiredError(data, property, 'bpmn:TimerEventDefinition'))
149
158
  ) {
150
159
  return [ 'timerEventDefinitionType' ];
151
160
  }
152
161
 
153
- if (isPropertyRequiredError(error, 'body', 'bpmn:FormalExpression') && TIMER_PROPERTIES.includes(secondLast(report.path))) {
154
- return hasOnlyDurationTimer(error.parentNode) ? [ 'timerEventDefinitionDurationValue' ] : [ 'timerEventDefinitionValue' ];
162
+ if (isExpressionRequiredError(data, 'timeCycle', 'bpmn:FormalExpression')
163
+ || isExpressionRequiredError(data, 'timeDate', 'bpmn:FormalExpression')
164
+ || isExpressionRequiredError(data, 'timeDuration', 'bpmn:FormalExpression')) {
165
+ return hasOnlyDurationTimer(data.parentNode) ? [ 'timerEventDefinitionDurationValue' ] : [ 'timerEventDefinitionValue' ];
155
166
  }
156
167
 
157
- if (isPropertyValueNotAllowedError(error, 'body', 'bpmn:FormalExpression') && TIMER_PROPERTIES.includes(secondLast(report.path))) {
158
- return hasOnlyDurationTimer(error.parentNode) ? [ 'timerEventDefinitionDurationValue' ] : [ 'timerEventDefinitionValue' ];
168
+ if (isExpressionValueNotAllowedError(data, 'timeCycle', 'bpmn:FormalExpression')
169
+ || isExpressionValueNotAllowedError(data, 'timeDate', 'bpmn:FormalExpression')
170
+ || isExpressionValueNotAllowedError(data, 'timeDuration', 'bpmn:FormalExpression')) {
171
+ return hasOnlyDurationTimer(data.parentNode) ? [ 'timerEventDefinitionDurationValue' ] : [ 'timerEventDefinitionValue' ];
172
+ }
173
+
174
+ const LIST_PROPERTIES = [
175
+ [ 'zeebe:Input', 'input' ],
176
+ [ 'zeebe:Output', 'output' ],
177
+ [ 'zeebe:Property', 'extensionProperty' ],
178
+ [ 'zeebe:Header', 'header' ]
179
+ ];
180
+
181
+ for (const [ type, prefix ] of LIST_PROPERTIES) {
182
+ if (hasType(data, type)
183
+ && getPropertyName(data)) {
184
+
185
+ const index = path[path.length - 2];
186
+
187
+ return [ `${ id }-${prefix}-${index}-${ getPropertyName(data) }` ];
188
+ }
189
+ }
190
+
191
+ if (hasType(data, 'zeebe:LoopCharacteristics')) {
192
+ return [ `multiInstance-${getPropertyName(data)}` ];
159
193
  }
160
194
 
161
195
  return [];
162
196
  }
163
197
 
164
198
  export function getErrorMessage(id, report) {
199
+ const { data } = report;
200
+
201
+ // do not override FEEL message
202
+ if (data.type === ERROR_TYPES.FEEL_EXPRESSION_INVALID) {
203
+ return;
204
+ }
205
+
165
206
  if (id === 'businessRuleImplementation') {
166
207
  return 'Implementation must be defined.';
167
208
  }
@@ -235,16 +276,16 @@ export function getErrorMessage(id, report) {
235
276
  }
236
277
 
237
278
  if (id === 'timerEventDefinitionDurationValue') {
238
- return report.error.type === ERROR_TYPES.PROPERTY_REQUIRED ?
279
+ return data.type === ERROR_TYPES.EXPRESSION_REQUIRED ?
239
280
  'Duration must be defined.' : 'Must be an expression, or an ISO 8601 interval.';
240
281
  }
241
282
 
242
283
  if (id === 'timerEventDefinitionValue') {
243
- if (report.error.type === ERROR_TYPES.PROPERTY_REQUIRED) {
284
+ if (data.type === ERROR_TYPES.EXPRESSION_REQUIRED) {
244
285
  return 'Value must be defined.';
245
286
  }
246
287
 
247
- const property = secondLast(report.path);
288
+ const { property } = data;
248
289
 
249
290
  if (property === 'timeCycle') {
250
291
  return 'Must be an expression, an ISO 8601 repeating interval, or a cron expression (cron requires Camunda Platform 8.1 or newer).';
@@ -260,56 +301,68 @@ export function getErrorMessage(id, report) {
260
301
  }
261
302
  }
262
303
 
263
- function isExtensionElementNotAllowedError(error, extensionElement, type) {
264
- return error.type === ERROR_TYPES.EXTENSION_ELEMENT_NOT_ALLOWED
265
- && is(error.extensionElement, extensionElement)
266
- && (!type || is(error.node, type));
304
+ function isExtensionElementNotAllowedError(data, extensionElement, type) {
305
+ return data.type === ERROR_TYPES.EXTENSION_ELEMENT_NOT_ALLOWED
306
+ && is(data.extensionElement, extensionElement)
307
+ && (!type || is(data.node, type));
267
308
  }
268
309
 
269
- function isExtensionElementRequiredError(error, requiredExtensionElement, type) {
270
- return error.type === ERROR_TYPES.EXTENSION_ELEMENT_REQUIRED
271
- && (isArray(error.requiredExtensionElement) && error.requiredExtensionElement.includes(requiredExtensionElement)
272
- || error.requiredExtensionElement === requiredExtensionElement)
273
- && (!type || is(error.node, type));
310
+ function isExtensionElementRequiredError(data, requiredExtensionElement, type) {
311
+ return data.type === ERROR_TYPES.EXTENSION_ELEMENT_REQUIRED
312
+ && (isArray(data.requiredExtensionElement) && data.requiredExtensionElement.includes(requiredExtensionElement)
313
+ || data.requiredExtensionElement === requiredExtensionElement)
314
+ && (!type || is(data.node, type));
274
315
  }
275
316
 
276
- function isPropertyDependendRequiredError(error, dependendRequiredProperty, type) {
277
- return error.type === ERROR_TYPES.PROPERTY_DEPENDEND_REQUIRED
278
- && error.dependendRequiredProperty === dependendRequiredProperty
279
- && (!type || is(error.node, type));
317
+ function isPropertyDependendRequiredError(data, dependendRequiredProperty, type) {
318
+ return data.type === ERROR_TYPES.PROPERTY_DEPENDEND_REQUIRED
319
+ && data.dependendRequiredProperty === dependendRequiredProperty
320
+ && (!type || is(data.node, type));
280
321
  }
281
322
 
282
- function isPropertyRequiredError(error, requiredProperty, type) {
283
- return error.type === ERROR_TYPES.PROPERTY_REQUIRED
284
- && (error.requiredProperty === requiredProperty)
285
- && (!type || is(error.node, type));
323
+
324
+ function isPropertyError(data, property, type) {
325
+ return getPropertyName(data) === property
326
+ && (!type || is(data.node, type));
286
327
  }
287
328
 
288
- function isOneOfPropertiesRequiredError(error, requiredProperty, type) {
289
- return error.type === ERROR_TYPES.PROPERTY_REQUIRED
290
- && (isArray(error.requiredProperty) && error.requiredProperty.includes(requiredProperty))
291
- && (!type || is(error.node, type));
329
+ function hasType(data, type) {
330
+ return data.node && is(data.node, type);
292
331
  }
293
332
 
294
- function isPropertyValueDuplicatedError(error, propertiesName, duplicatedProperty, type) {
295
- return error.type === ERROR_TYPES.PROPERTY_VALUE_DUPLICATED
296
- && error.propertiesName === propertiesName
297
- && error.duplicatedProperty === duplicatedProperty
298
- && (!type || is(error.node, type));
333
+ function getPropertyName(data) {
334
+ const propertyKey = data.type === ERROR_TYPES.PROPERTY_REQUIRED ? 'requiredProperty' : 'property';
335
+
336
+ return data[ propertyKey ];
299
337
  }
300
338
 
301
- function isPropertyValueNotAllowedError(error, propertyName, type) {
302
- return error.type === ERROR_TYPES.PROPERTY_VALUE_NOT_ALLOWED
303
- && error.property === propertyName
304
- && (!type || is(error.node, type));
339
+ function isOneOfPropertiesRequiredError(data, requiredProperty, type) {
340
+ return data.type === ERROR_TYPES.PROPERTY_REQUIRED
341
+ && (isArray(data.requiredProperty) && data.requiredProperty.includes(requiredProperty))
342
+ && (!type || is(data.node, type));
305
343
  }
306
344
 
307
- function getBusinessObject(element) {
308
- return element.businessObject || element;
345
+ function isPropertyValueDuplicatedError(data, propertiesName, duplicatedProperty, type) {
346
+ return data.type === ERROR_TYPES.PROPERTY_VALUE_DUPLICATED
347
+ && data.propertiesName === propertiesName
348
+ && data.duplicatedProperty === duplicatedProperty
349
+ && (!type || is(data.node, type));
309
350
  }
310
351
 
311
- function secondLast(array) {
312
- return array[array.length - 2];
352
+ function isExpressionRequiredError(data, propertyName, type) {
353
+ return data.type === ERROR_TYPES.EXPRESSION_REQUIRED
354
+ && data.property === propertyName
355
+ && (!type || is(data.node, type));
356
+ }
357
+
358
+ function isExpressionValueNotAllowedError(data, propertyName, type) {
359
+ return data.type === ERROR_TYPES.EXPRESSION_VALUE_NOT_ALLOWED
360
+ && data.property === propertyName
361
+ && (!type || is(data.node, type));
362
+ }
363
+
364
+ function getBusinessObject(element) {
365
+ return element.businessObject || element;
313
366
  }
314
367
 
315
368
  function hasOnlyDurationTimer(node) {
@@ -0,0 +1,3 @@
1
+ export function toSemverMinor(executionPlatformVersion) {
2
+ return executionPlatformVersion.split('.').slice(0, 2).join('.');
3
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camunda/linting",
3
- "version": "0.8.0",
3
+ "version": "0.9.1",
4
4
  "description": "Linting for Camunda Platform",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -27,7 +27,7 @@
27
27
  "dependencies": {
28
28
  "bpmn-moddle": "^7.1.3",
29
29
  "bpmnlint": "^8.0.0",
30
- "bpmnlint-plugin-camunda-compat": "^0.13.1",
30
+ "bpmnlint-plugin-camunda-compat": "^0.14.1",
31
31
  "bpmnlint-utils": "^1.0.2",
32
32
  "min-dash": "^4.0.0",
33
33
  "min-dom": "^4.0.1",