@camunda/linting 3.19.0 → 3.20.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.
@@ -1,602 +1,602 @@
1
- import {
2
- isArray,
3
- isString
4
- } from 'min-dash';
5
-
6
- import { is } from 'bpmnlint-utils';
7
-
8
- import { ERROR_TYPES } from 'bpmnlint-plugin-camunda-compat/rules/utils/error-types';
9
-
10
- import { greaterOrEqual } from './version';
11
-
12
- const TIMER_PROPERTIES = [
13
- 'timeDate',
14
- 'timeDuration',
15
- 'timeCycle'
16
- ];
17
-
18
- /**
19
- * Get errors for a given element.
20
- *
21
- * @param {Object[]} reports
22
- * @param {Object} element
23
- *
24
- * @returns {Object}
25
- */
26
- export function getErrors(reports, element) {
27
- return reports.reduce((errors, report) => {
28
- const { category } = report;
29
-
30
- if (!element
31
- || getBusinessObject(element).get('id') !== report.id
32
- || category !== 'error') {
33
- return errors;
34
- }
35
-
36
- const ids = getEntryIds(report);
37
-
38
- if (!ids.length) {
39
- return errors;
40
- }
41
-
42
- let { message } = report;
43
-
44
- return {
45
- ...errors,
46
- ...ids.reduce((errors, id) => {
47
- return {
48
- ...errors,
49
- [ id ]: getErrorMessage(id, report) || message
50
- };
51
- }, {})
52
- };
53
- }, {});
54
- }
55
-
56
- export function getEntryIds(report) {
57
- const {
58
- data = {},
59
- id,
60
- path,
61
- propertiesPanel = {}
62
- } = report;
63
-
64
- if (propertiesPanel.entryIds) {
65
- return propertiesPanel.entryIds;
66
- }
67
-
68
- if (isPropertyError(data, 'isExecutable')) {
69
- return [ 'isExecutable' ];
70
- }
71
-
72
- if (isExtensionElementRequiredError(data, 'zeebe:CalledDecision', 'bpmn:BusinessRuleTask')) {
73
- return [ 'businessRuleImplementation' ];
74
- }
75
-
76
- // script task
77
- if (isExtensionElementRequiredError(data, 'zeebe:Script', 'bpmn:ScriptTask')) {
78
- return [ 'scriptImplementation' ];
79
- }
80
-
81
- if (isPropertyError(data, 'errorRef')) {
82
- return [ 'errorRef' ];
83
- }
84
-
85
- if (isPropertyError(data, 'escalationRef')) {
86
- return [ 'escalationRef' ];
87
- }
88
-
89
- if (isPropertyError(data, 'messageRef')) {
90
- return [ 'messageRef' ];
91
- }
92
-
93
- if (isPropertyError(data, 'signalRef')) {
94
- return [ 'signalRef' ];
95
- }
96
-
97
- if (isPropertyError(data, 'historyTimeToLive')) {
98
- return [ 'historyTimeToLive' ];
99
- }
100
-
101
- if (isPropertyError(data, 'decisionId', 'zeebe:CalledDecision')) {
102
- return [ 'decisionId' ];
103
- }
104
-
105
- if (isPropertyError(data, 'resultVariable')) {
106
- return [ 'resultVariable' ];
107
- }
108
-
109
- if (isPropertyError(data, 'expression', 'zeebe:Script')) {
110
- return [ 'scriptExpression' ];
111
- }
112
-
113
- if (isPropertyError(data, 'errorCode', 'bpmn:Error')) {
114
- return [ 'errorCode' ];
115
- }
116
-
117
- if (isPropertyError(data, 'escalationCode', 'bpmn:Escalation')) {
118
- return [ 'escalationCode' ];
119
- }
120
-
121
- if (isPropertyError(data, 'name', 'bpmn:Message')) {
122
- return [ 'messageName' ];
123
- }
124
-
125
- if (isPropertyError(data, 'name', 'bpmn:Signal')) {
126
- return [ 'signalName' ];
127
- }
128
-
129
- if (isExtensionElementRequiredError(data, 'zeebe:LoopCharacteristics', 'bpmn:MultiInstanceLoopCharacteristics')
130
- || isPropertyError(data, 'inputCollection', 'zeebe:LoopCharacteristics')) {
131
- return [ 'multiInstance-inputCollection' ];
132
- }
133
-
134
- if (isPropertyDependentRequiredError(data, 'outputCollection', 'zeebe:LoopCharacteristics')) {
135
- return [ 'multiInstance-outputCollection' ];
136
- }
137
-
138
- if (isPropertyDependentRequiredError(data, 'outputElement', 'zeebe:LoopCharacteristics')) {
139
- return [ 'multiInstance-outputElement' ];
140
- }
141
-
142
- if (isExtensionElementRequiredError(data, 'zeebe:CalledElement', 'bpmn:CallActivity')
143
- || isPropertyError(data, 'processId', 'zeebe:CalledElement')) {
144
- return [ 'targetProcessId' ];
145
- }
146
-
147
- if (isExtensionElementRequiredError(data, 'zeebe:TaskDefinition')
148
- || isPropertyError(data, 'type', 'zeebe:TaskDefinition')) {
149
- return [ 'taskDefinitionType' ];
150
- }
151
-
152
- if (isPropertyError(data, 'retries', 'zeebe:TaskDefinition')) {
153
- return [ 'taskDefinitionRetries' ];
154
- }
155
-
156
- if (isExtensionElementRequiredError(data, 'zeebe:Subscription')
157
- || isPropertyError(data, 'correlationKey', 'zeebe:Subscription')) {
158
- return [ 'messageSubscriptionCorrelationKey' ];
159
- }
160
-
161
- if (isPropertyError(data, 'formKey', 'zeebe:FormDefinition')) {
162
- return [ 'customFormKey' ];
163
- }
164
-
165
- if (isType(data, 'zeebe:FormDefinition')) {
166
- const {
167
- node,
168
- requiredProperty
169
- } = data;
170
-
171
- if (isArray(requiredProperty)) {
172
- if (requiredProperty.includes('formKey') && isEmptyString(node.get('formKey'))) {
173
- return [ 'customFormKey' ];
174
- } else if (requiredProperty.includes('formId') && isEmptyString(node.get('formId'))) {
175
- return [ 'formId' ];
176
- } else if (requiredProperty.includes('externalReference') && isEmptyString(node.get('externalReference'))) {
177
- return [ 'externalReference' ];
178
- }
179
- }
180
- }
181
-
182
- if (isPropertyError(data, 'formId', 'zeebe:FormDefinition')) {
183
- return [ 'formId' ];
184
- }
185
-
186
- if (isPropertyError(data, 'body', 'zeebe:UserTaskForm')) {
187
- return [ 'formConfiguration' ];
188
- }
189
-
190
- if (isPropertyValueDuplicatedError(data, 'values', 'key', 'zeebe:TaskHeaders')) {
191
- const {
192
- node,
193
- properties,
194
- propertiesName
195
- } = data;
196
-
197
- return properties.map(property => {
198
- const index = node.get(propertiesName).indexOf(property);
199
-
200
- return `${ id }-header-${ index }-key`;
201
- });
202
- }
203
-
204
- if (isExtensionElementNotAllowedError(data, 'zeebe:Properties')) {
205
- const { extensionElement } = data;
206
-
207
- return extensionElement.get('zeebe:properties').map((zeebeProperty, index) => {
208
- return `${ id }-extensionProperty-${ index }-name`;
209
- });
210
- }
211
-
212
- if (isExtensionElementNotAllowedError(data, 'zeebe:UserTask')) {
213
- return [ 'userTaskImplementation' ];
214
- }
215
-
216
- if (isExtensionElementNotAllowedError(data, 'zeebe:FormDefinition', 'bpmn:StartEvent')) {
217
- return [ 'formType' ];
218
- }
219
-
220
-
221
- if (isPropertyError(data, 'conditionExpression', 'bpmn:SequenceFlow')) {
222
- return [ 'conditionExpression' ];
223
- }
224
-
225
- if (isPropertyError(data, 'completionCondition', 'bpmn:MultiInstanceLoopCharacteristics')) {
226
- return [ 'multiInstance-completionCondition' ];
227
- }
228
-
229
- if (TIMER_PROPERTIES.some(property =>
230
- isOneOfPropertiesRequiredError(data, property, 'bpmn:TimerEventDefinition'))
231
- ) {
232
- return [ 'timerEventDefinitionType' ];
233
- }
234
-
235
- if (isExpressionRequiredError(data, 'timeCycle', 'bpmn:FormalExpression')
236
- || isExpressionRequiredError(data, 'timeDate', 'bpmn:FormalExpression')
237
- || isExpressionRequiredError(data, 'timeDuration', 'bpmn:FormalExpression')) {
238
- return [ 'timerEventDefinitionValue' ];
239
- }
240
-
241
- if (isExpressionValueNotAllowedError(data, 'timeCycle', 'bpmn:FormalExpression')
242
- || isExpressionValueNotAllowedError(data, 'timeDate', 'bpmn:FormalExpression')
243
- || isExpressionValueNotAllowedError(data, 'timeDuration', 'bpmn:FormalExpression')) {
244
- return [ 'timerEventDefinitionValue' ];
245
- }
246
-
247
- if (isPropertyError(data, 'timeCycle', 'bpmn:TimerEventDefinition')
248
- || isPropertyError(data, 'timeDate', 'bpmn:TimerEventDefinition')
249
- || isPropertyError(data, 'timeDuration', 'bpmn:TimerEventDefinition')) {
250
- return [ 'timerEventDefinitionType' ];
251
- }
252
-
253
- const LIST_PROPERTIES = [
254
- [ 'zeebe:Input', 'input' ],
255
- [ 'zeebe:Output', 'output' ],
256
- [ 'zeebe:Property', 'extensionProperty' ],
257
- [ 'zeebe:Header', 'header' ]
258
- ];
259
-
260
- for (const [ type, prefix ] of LIST_PROPERTIES) {
261
- if (isType(data, type)
262
- && getPropertyName(data)) {
263
-
264
- const index = path[ path.length - 2 ];
265
-
266
- return [ `${ id }-${ prefix }-${ index }-${ getPropertyName(data) }` ];
267
- }
268
- }
269
-
270
- if (isType(data, 'zeebe:LoopCharacteristics')) {
271
- return [ `multiInstance-${getPropertyName(data)}` ];
272
- }
273
-
274
- if (isPropertyError(data, 'candidateUsers', 'zeebe:AssignmentDefinition')) {
275
- return [ 'assignmentDefinitionCandidateUsers' ];
276
- }
277
-
278
- if (isPropertyError(data, 'historyTimeToLive', 'bpmn:Process')) {
279
- return [ 'historyTimeToLive' ];
280
- }
281
-
282
- if (isExpressionValueNotAllowedError(data, 'dueDate', 'zeebe:TaskSchedule')) {
283
- return [ 'taskScheduleDueDate' ];
284
- }
285
-
286
- if (isExpressionValueNotAllowedError(data, 'followUpDate', 'zeebe:TaskSchedule')) {
287
- return [ 'taskScheduleFollowUpDate' ];
288
- }
289
-
290
- if (isExtensionElementNotAllowedError(data, 'zeebe:TaskSchedule', 'bpmn:UserTask')) {
291
- const { extensionElement: taskSchedule } = data;
292
-
293
- let ids = [];
294
-
295
- if (taskSchedule.get('dueDate')) {
296
- ids = [ ...ids, 'taskScheduleDueDate' ];
297
- }
298
-
299
- if (taskSchedule.get('followUpDate')) {
300
- ids = [ ...ids, 'taskScheduleFollowUpDate' ];
301
- }
302
-
303
- return ids;
304
- }
305
-
306
- if (isPropertyError(data, 'propagateAllParentVariables', 'zeebe:CalledElement')) {
307
- return [ 'propagateAllParentVariables' ];
308
- }
309
-
310
- if (isPropertyError(data, 'name', 'bpmn:LinkEventDefinition')
311
- || isElementPropertyValueDuplicated(data, 'name', 'bpmn:LinkEventDefinition')) {
312
- return [ 'linkName' ];
313
- }
314
-
315
- if (isPropertyError(data, 'waitForCompletion', 'bpmn:CompensateEventDefinition')) {
316
- return [ 'waitForCompletion' ];
317
- }
318
-
319
- return [];
320
- }
321
-
322
- export function getErrorMessage(id, report) {
323
- const {
324
- data = {},
325
- executionPlatformVersion
326
- } = report;
327
-
328
- // adjust FEEL message
329
- if (data.type === ERROR_TYPES.FEEL_EXPRESSION_INVALID) {
330
- return 'Unparsable FEEL expression.';
331
- }
332
-
333
- if (data.type === ERROR_TYPES.EXPRESSION_NOT_ALLOWED) {
334
- return 'Cannot be an expression.';
335
- }
336
-
337
- if (id === 'isExecutable') {
338
- const { parentNode } = data;
339
-
340
- if (parentNode && is(parentNode, 'bpmn:Participant')) {
341
- return 'One process must be executable.';
342
- } else {
343
- return 'Process must be executable.';
344
- }
345
- }
346
-
347
- if ([ 'businessRuleImplementation', 'scriptImplementation' ].includes(id)) {
348
- return 'Implementation must be defined.';
349
- }
350
-
351
- if (id === 'errorRef') {
352
- return 'Global error reference must be defined.';
353
- }
354
-
355
- if (id === 'escalationRef') {
356
- return 'Global escalation reference must be defined.';
357
- }
358
-
359
- if (id === 'messageRef') {
360
- return 'Global message reference must be defined.';
361
- }
362
-
363
- if (id === 'signalRef') {
364
- return 'Global signal reference must be defined.';
365
- }
366
-
367
- if (id === 'decisionId') {
368
- return 'Decision ID must be defined.';
369
- }
370
-
371
- if (id === 'scriptExpression') {
372
- return 'FEEL expression must be defined.';
373
- }
374
-
375
- if (id === 'resultVariable') {
376
- return 'Result variable must be defined.';
377
- }
378
-
379
- if (id === 'errorCode' && data.type === ERROR_TYPES.PROPERTY_REQUIRED) {
380
- return 'Code must be defined.';
381
- }
382
-
383
- if (id === 'escalationCode' && data.type === ERROR_TYPES.PROPERTY_REQUIRED) {
384
- return 'Code must be defined.';
385
- }
386
-
387
- if (id === 'messageName') {
388
- return 'Name must be defined.';
389
- }
390
-
391
- if (id === 'signalName') {
392
- return 'Name must be defined.';
393
- }
394
-
395
- if (id === 'multiInstance-inputCollection') {
396
- return 'Input collection must be defined.';
397
- }
398
-
399
- if (id === 'multiInstance-outputCollection') {
400
- return 'Output collection must be defined.';
401
- }
402
-
403
- if (id === 'multiInstance-outputElement') {
404
- return 'Output element must be defined.';
405
- }
406
-
407
- if (id === 'targetProcessId') {
408
- return 'Process ID must be defined.';
409
- }
410
-
411
- if (id === 'taskDefinitionType') {
412
- return 'Type must be defined.';
413
- }
414
-
415
- if (id === 'timerEventDefinitionType' && data.type === ERROR_TYPES.PROPERTY_REQUIRED) {
416
- return 'Type must be defined.';
417
- }
418
-
419
- if (id === 'messageSubscriptionCorrelationKey'
420
- && [
421
- ERROR_TYPES.EXTENSION_ELEMENT_REQUIRED,
422
- ERROR_TYPES.PROPERTY_REQUIRED
423
- ].includes(data.type)) {
424
- return 'Subscription correlation key must be defined.';
425
- }
426
-
427
- if (id === 'customFormKey') {
428
- return 'Form key must be defined.';
429
- }
430
-
431
- if (id === 'formId') {
432
- if (data.type === ERROR_TYPES.PROPERTY_REQUIRED) {
433
- return 'Form ID must be defined.';
434
- } else if (data.type === ERROR_TYPES.PROPERTY_NOT_ALLOWED) {
435
- return 'Form ID not supported.';
436
- }
437
- }
438
-
439
- if (id === 'externalReference') {
440
- return 'External reference must be defined.';
441
- }
442
-
443
- if (id === 'formConfiguration') {
444
- return 'Form JSON configuration must be defined.';
445
- }
446
-
447
- if (/^.+-header-[0-9]+-key$/.test(id)) {
448
- return 'Must be unique.';
449
- }
450
-
451
- if (/^.+-extensionProperty-[0-9]+-name$/.test(id)) {
452
- return 'Not supported.';
453
- }
454
-
455
- if (id === 'userTaskImplementation') {
456
- return 'Supported only in Camunda 8.5 or newer.';
457
- }
458
-
459
- if (id === 'conditionExpression') {
460
- return 'Condition expression must be defined.';
461
- }
462
-
463
- if (id === 'timerEventDefinitionType' && data.type === ERROR_TYPES.PROPERTY_NOT_ALLOWED) {
464
- return 'Type not supported.';
465
- }
466
-
467
- if (id === 'timerEventDefinitionValue') {
468
- if (data.type === ERROR_TYPES.EXPRESSION_REQUIRED) {
469
- return 'Value must be defined.';
470
- }
471
-
472
- const { property } = data;
473
-
474
- if (property === 'timeCycle') {
475
- if (!greaterOrEqual(executionPlatformVersion, '8.1')) {
476
- return 'Must be an expression, an ISO 8601 repeating interval, or a cron expression (cron only supported by Camunda 8.1 or newer).';
477
- }
478
-
479
- return 'Must be an expression, an ISO 8601 repeating interval, or a cron expression.';
480
- }
481
-
482
- if (property === 'timeDate') {
483
- return 'Must be an expression, or an ISO 8601 date.';
484
- }
485
-
486
- if (property === 'timeDuration') {
487
- return 'Must be an expression, or an ISO 8601 interval.';
488
- }
489
- }
490
-
491
- if (id === 'assignmentDefinitionCandidateUsers') {
492
- return 'Not supported.';
493
- }
494
-
495
- if (id === 'taskScheduleDueDate') {
496
- if (data.type === ERROR_TYPES.EXTENSION_ELEMENT_NOT_ALLOWED) {
497
- return 'Not supported.';
498
- } else {
499
- return 'Must be an ISO 8601 date.';
500
- }
501
- }
502
-
503
- if (id === 'taskScheduleFollowUpDate') {
504
- if (data.type === ERROR_TYPES.EXTENSION_ELEMENT_NOT_ALLOWED) {
505
- return 'Not supported.';
506
- } else {
507
- return 'Must be an ISO 8601 date.';
508
- }
509
- }
510
-
511
- if (id === 'propagateAllParentVariables') {
512
- return 'Not supported.';
513
- }
514
-
515
- if (id === 'linkName') {
516
- if (data.type === ERROR_TYPES.ELEMENT_PROPERTY_VALUE_DUPLICATED) {
517
- return 'Must be unique.';
518
- } else {
519
- return 'Must be defined.';
520
- }
521
- }
522
-
523
- if (id === 'waitForCompletion') {
524
- return 'Must wait for completion.';
525
- }
526
- }
527
-
528
- function isExtensionElementNotAllowedError(data, extensionElement, type) {
529
- return data.type === ERROR_TYPES.EXTENSION_ELEMENT_NOT_ALLOWED
530
- && is(data.extensionElement, extensionElement)
531
- && (!type || is(data.node, type));
532
- }
533
-
534
- function isExtensionElementRequiredError(data, requiredExtensionElement, type) {
535
- return data.type === ERROR_TYPES.EXTENSION_ELEMENT_REQUIRED
536
- && (isArray(data.requiredExtensionElement) && data.requiredExtensionElement.includes(requiredExtensionElement)
537
- || data.requiredExtensionElement === requiredExtensionElement)
538
- && (!type || is(data.node, type));
539
- }
540
-
541
- function isPropertyDependentRequiredError(data, dependentRequiredProperty, type) {
542
- return data.type === ERROR_TYPES.PROPERTY_DEPENDENT_REQUIRED
543
- && data.dependentRequiredProperty === dependentRequiredProperty
544
- && (!type || is(data.node, type));
545
- }
546
-
547
-
548
- function isPropertyError(data, property, type) {
549
- return getPropertyName(data) === property
550
- && (!type || is(data.node, type));
551
- }
552
-
553
- function getPropertyName(data) {
554
- if (data.type === ERROR_TYPES.PROPERTY_REQUIRED) {
555
- return data.requiredProperty;
556
- }
557
-
558
- return data.property;
559
- }
560
-
561
- function isType(data, type) {
562
- return data.node && is(data.node, type);
563
- }
564
-
565
- function isOneOfPropertiesRequiredError(data, requiredProperty, type) {
566
- return data.type === ERROR_TYPES.PROPERTY_REQUIRED
567
- && (isArray(data.requiredProperty) && data.requiredProperty.includes(requiredProperty))
568
- && (!type || is(data.node, type));
569
- }
570
-
571
- function isPropertyValueDuplicatedError(data, propertiesName, duplicatedProperty, type) {
572
- return data.type === ERROR_TYPES.PROPERTY_VALUE_DUPLICATED
573
- && data.propertiesName === propertiesName
574
- && data.duplicatedProperty === duplicatedProperty
575
- && (!type || is(data.node, type));
576
- }
577
-
578
- function isExpressionRequiredError(data, propertyName, type) {
579
- return data.type === ERROR_TYPES.EXPRESSION_REQUIRED
580
- && data.property === propertyName
581
- && (!type || is(data.node, type));
582
- }
583
-
584
- function isExpressionValueNotAllowedError(data, propertyName, type) {
585
- return data.type === ERROR_TYPES.EXPRESSION_VALUE_NOT_ALLOWED
586
- && data.property === propertyName
587
- && (!type || is(data.node, type));
588
- }
589
-
590
- function isElementPropertyValueDuplicated(data, propertyName, type) {
591
- return data.type === ERROR_TYPES.ELEMENT_PROPERTY_VALUE_DUPLICATED
592
- && data.duplicatedProperty === propertyName
593
- && (!type || is(data.node, type));
594
- }
595
-
596
- function getBusinessObject(element) {
597
- return element.businessObject || element;
598
- }
599
-
600
- function isEmptyString(value) {
601
- return isString(value) && value.trim() === '';
1
+ import {
2
+ isArray,
3
+ isString
4
+ } from 'min-dash';
5
+
6
+ import { is } from 'bpmnlint-utils';
7
+
8
+ import { ERROR_TYPES } from 'bpmnlint-plugin-camunda-compat/rules/utils/error-types';
9
+
10
+ import { greaterOrEqual } from './version';
11
+
12
+ const TIMER_PROPERTIES = [
13
+ 'timeDate',
14
+ 'timeDuration',
15
+ 'timeCycle'
16
+ ];
17
+
18
+ /**
19
+ * Get errors for a given element.
20
+ *
21
+ * @param {Object[]} reports
22
+ * @param {Object} element
23
+ *
24
+ * @returns {Object}
25
+ */
26
+ export function getErrors(reports, element) {
27
+ return reports.reduce((errors, report) => {
28
+ const { category } = report;
29
+
30
+ if (!element
31
+ || getBusinessObject(element).get('id') !== report.id
32
+ || category !== 'error') {
33
+ return errors;
34
+ }
35
+
36
+ const ids = getEntryIds(report);
37
+
38
+ if (!ids.length) {
39
+ return errors;
40
+ }
41
+
42
+ let { message } = report;
43
+
44
+ return {
45
+ ...errors,
46
+ ...ids.reduce((errors, id) => {
47
+ return {
48
+ ...errors,
49
+ [ id ]: getErrorMessage(id, report) || message
50
+ };
51
+ }, {})
52
+ };
53
+ }, {});
54
+ }
55
+
56
+ export function getEntryIds(report) {
57
+ const {
58
+ data = {},
59
+ id,
60
+ path,
61
+ propertiesPanel = {}
62
+ } = report;
63
+
64
+ if (propertiesPanel.entryIds) {
65
+ return propertiesPanel.entryIds;
66
+ }
67
+
68
+ if (isPropertyError(data, 'isExecutable')) {
69
+ return [ 'isExecutable' ];
70
+ }
71
+
72
+ if (isExtensionElementRequiredError(data, 'zeebe:CalledDecision', 'bpmn:BusinessRuleTask')) {
73
+ return [ 'businessRuleImplementation' ];
74
+ }
75
+
76
+ // script task
77
+ if (isExtensionElementRequiredError(data, 'zeebe:Script', 'bpmn:ScriptTask')) {
78
+ return [ 'scriptImplementation' ];
79
+ }
80
+
81
+ if (isPropertyError(data, 'errorRef')) {
82
+ return [ 'errorRef' ];
83
+ }
84
+
85
+ if (isPropertyError(data, 'escalationRef')) {
86
+ return [ 'escalationRef' ];
87
+ }
88
+
89
+ if (isPropertyError(data, 'messageRef')) {
90
+ return [ 'messageRef' ];
91
+ }
92
+
93
+ if (isPropertyError(data, 'signalRef')) {
94
+ return [ 'signalRef' ];
95
+ }
96
+
97
+ if (isPropertyError(data, 'historyTimeToLive')) {
98
+ return [ 'historyTimeToLive' ];
99
+ }
100
+
101
+ if (isPropertyError(data, 'decisionId', 'zeebe:CalledDecision')) {
102
+ return [ 'decisionId' ];
103
+ }
104
+
105
+ if (isPropertyError(data, 'resultVariable')) {
106
+ return [ 'resultVariable' ];
107
+ }
108
+
109
+ if (isPropertyError(data, 'expression', 'zeebe:Script')) {
110
+ return [ 'scriptExpression' ];
111
+ }
112
+
113
+ if (isPropertyError(data, 'errorCode', 'bpmn:Error')) {
114
+ return [ 'errorCode' ];
115
+ }
116
+
117
+ if (isPropertyError(data, 'escalationCode', 'bpmn:Escalation')) {
118
+ return [ 'escalationCode' ];
119
+ }
120
+
121
+ if (isPropertyError(data, 'name', 'bpmn:Message')) {
122
+ return [ 'messageName' ];
123
+ }
124
+
125
+ if (isPropertyError(data, 'name', 'bpmn:Signal')) {
126
+ return [ 'signalName' ];
127
+ }
128
+
129
+ if (isExtensionElementRequiredError(data, 'zeebe:LoopCharacteristics', 'bpmn:MultiInstanceLoopCharacteristics')
130
+ || isPropertyError(data, 'inputCollection', 'zeebe:LoopCharacteristics')) {
131
+ return [ 'multiInstance-inputCollection' ];
132
+ }
133
+
134
+ if (isPropertyDependentRequiredError(data, 'outputCollection', 'zeebe:LoopCharacteristics')) {
135
+ return [ 'multiInstance-outputCollection' ];
136
+ }
137
+
138
+ if (isPropertyDependentRequiredError(data, 'outputElement', 'zeebe:LoopCharacteristics')) {
139
+ return [ 'multiInstance-outputElement' ];
140
+ }
141
+
142
+ if (isExtensionElementRequiredError(data, 'zeebe:CalledElement', 'bpmn:CallActivity')
143
+ || isPropertyError(data, 'processId', 'zeebe:CalledElement')) {
144
+ return [ 'targetProcessId' ];
145
+ }
146
+
147
+ if (isExtensionElementRequiredError(data, 'zeebe:TaskDefinition')
148
+ || isPropertyError(data, 'type', 'zeebe:TaskDefinition')) {
149
+ return [ 'taskDefinitionType' ];
150
+ }
151
+
152
+ if (isPropertyError(data, 'retries', 'zeebe:TaskDefinition')) {
153
+ return [ 'taskDefinitionRetries' ];
154
+ }
155
+
156
+ if (isExtensionElementRequiredError(data, 'zeebe:Subscription')
157
+ || isPropertyError(data, 'correlationKey', 'zeebe:Subscription')) {
158
+ return [ 'messageSubscriptionCorrelationKey' ];
159
+ }
160
+
161
+ if (isPropertyError(data, 'formKey', 'zeebe:FormDefinition')) {
162
+ return [ 'customFormKey' ];
163
+ }
164
+
165
+ if (isType(data, 'zeebe:FormDefinition')) {
166
+ const {
167
+ node,
168
+ requiredProperty
169
+ } = data;
170
+
171
+ if (isArray(requiredProperty)) {
172
+ if (requiredProperty.includes('formKey') && isEmptyString(node.get('formKey'))) {
173
+ return [ 'customFormKey' ];
174
+ } else if (requiredProperty.includes('formId') && isEmptyString(node.get('formId'))) {
175
+ return [ 'formId' ];
176
+ } else if (requiredProperty.includes('externalReference') && isEmptyString(node.get('externalReference'))) {
177
+ return [ 'externalReference' ];
178
+ }
179
+ }
180
+ }
181
+
182
+ if (isPropertyError(data, 'formId', 'zeebe:FormDefinition')) {
183
+ return [ 'formId' ];
184
+ }
185
+
186
+ if (isPropertyError(data, 'body', 'zeebe:UserTaskForm')) {
187
+ return [ 'formConfiguration' ];
188
+ }
189
+
190
+ if (isPropertyValueDuplicatedError(data, 'values', 'key', 'zeebe:TaskHeaders')) {
191
+ const {
192
+ node,
193
+ properties,
194
+ propertiesName
195
+ } = data;
196
+
197
+ return properties.map(property => {
198
+ const index = node.get(propertiesName).indexOf(property);
199
+
200
+ return `${ id }-header-${ index }-key`;
201
+ });
202
+ }
203
+
204
+ if (isExtensionElementNotAllowedError(data, 'zeebe:Properties')) {
205
+ const { extensionElement } = data;
206
+
207
+ return extensionElement.get('zeebe:properties').map((zeebeProperty, index) => {
208
+ return `${ id }-extensionProperty-${ index }-name`;
209
+ });
210
+ }
211
+
212
+ if (isExtensionElementNotAllowedError(data, 'zeebe:UserTask')) {
213
+ return [ 'userTaskImplementation' ];
214
+ }
215
+
216
+ if (isExtensionElementNotAllowedError(data, 'zeebe:FormDefinition', 'bpmn:StartEvent')) {
217
+ return [ 'formType' ];
218
+ }
219
+
220
+
221
+ if (isPropertyError(data, 'conditionExpression', 'bpmn:SequenceFlow')) {
222
+ return [ 'conditionExpression' ];
223
+ }
224
+
225
+ if (isPropertyError(data, 'completionCondition', 'bpmn:MultiInstanceLoopCharacteristics')) {
226
+ return [ 'multiInstance-completionCondition' ];
227
+ }
228
+
229
+ if (TIMER_PROPERTIES.some(property =>
230
+ isOneOfPropertiesRequiredError(data, property, 'bpmn:TimerEventDefinition'))
231
+ ) {
232
+ return [ 'timerEventDefinitionType' ];
233
+ }
234
+
235
+ if (isExpressionRequiredError(data, 'timeCycle', 'bpmn:FormalExpression')
236
+ || isExpressionRequiredError(data, 'timeDate', 'bpmn:FormalExpression')
237
+ || isExpressionRequiredError(data, 'timeDuration', 'bpmn:FormalExpression')) {
238
+ return [ 'timerEventDefinitionValue' ];
239
+ }
240
+
241
+ if (isExpressionValueNotAllowedError(data, 'timeCycle', 'bpmn:FormalExpression')
242
+ || isExpressionValueNotAllowedError(data, 'timeDate', 'bpmn:FormalExpression')
243
+ || isExpressionValueNotAllowedError(data, 'timeDuration', 'bpmn:FormalExpression')) {
244
+ return [ 'timerEventDefinitionValue' ];
245
+ }
246
+
247
+ if (isPropertyError(data, 'timeCycle', 'bpmn:TimerEventDefinition')
248
+ || isPropertyError(data, 'timeDate', 'bpmn:TimerEventDefinition')
249
+ || isPropertyError(data, 'timeDuration', 'bpmn:TimerEventDefinition')) {
250
+ return [ 'timerEventDefinitionType' ];
251
+ }
252
+
253
+ const LIST_PROPERTIES = [
254
+ [ 'zeebe:Input', 'input' ],
255
+ [ 'zeebe:Output', 'output' ],
256
+ [ 'zeebe:Property', 'extensionProperty' ],
257
+ [ 'zeebe:Header', 'header' ]
258
+ ];
259
+
260
+ for (const [ type, prefix ] of LIST_PROPERTIES) {
261
+ if (isType(data, type)
262
+ && getPropertyName(data)) {
263
+
264
+ const index = path[ path.length - 2 ];
265
+
266
+ return [ `${ id }-${ prefix }-${ index }-${ getPropertyName(data) }` ];
267
+ }
268
+ }
269
+
270
+ if (isType(data, 'zeebe:LoopCharacteristics')) {
271
+ return [ `multiInstance-${getPropertyName(data)}` ];
272
+ }
273
+
274
+ if (isPropertyError(data, 'candidateUsers', 'zeebe:AssignmentDefinition')) {
275
+ return [ 'assignmentDefinitionCandidateUsers' ];
276
+ }
277
+
278
+ if (isPropertyError(data, 'historyTimeToLive', 'bpmn:Process')) {
279
+ return [ 'historyTimeToLive' ];
280
+ }
281
+
282
+ if (isExpressionValueNotAllowedError(data, 'dueDate', 'zeebe:TaskSchedule')) {
283
+ return [ 'taskScheduleDueDate' ];
284
+ }
285
+
286
+ if (isExpressionValueNotAllowedError(data, 'followUpDate', 'zeebe:TaskSchedule')) {
287
+ return [ 'taskScheduleFollowUpDate' ];
288
+ }
289
+
290
+ if (isExtensionElementNotAllowedError(data, 'zeebe:TaskSchedule', 'bpmn:UserTask')) {
291
+ const { extensionElement: taskSchedule } = data;
292
+
293
+ let ids = [];
294
+
295
+ if (taskSchedule.get('dueDate')) {
296
+ ids = [ ...ids, 'taskScheduleDueDate' ];
297
+ }
298
+
299
+ if (taskSchedule.get('followUpDate')) {
300
+ ids = [ ...ids, 'taskScheduleFollowUpDate' ];
301
+ }
302
+
303
+ return ids;
304
+ }
305
+
306
+ if (isPropertyError(data, 'propagateAllParentVariables', 'zeebe:CalledElement')) {
307
+ return [ 'propagateAllParentVariables' ];
308
+ }
309
+
310
+ if (isPropertyError(data, 'name', 'bpmn:LinkEventDefinition')
311
+ || isElementPropertyValueDuplicated(data, 'name', 'bpmn:LinkEventDefinition')) {
312
+ return [ 'linkName' ];
313
+ }
314
+
315
+ if (isPropertyError(data, 'waitForCompletion', 'bpmn:CompensateEventDefinition')) {
316
+ return [ 'waitForCompletion' ];
317
+ }
318
+
319
+ return [];
320
+ }
321
+
322
+ export function getErrorMessage(id, report) {
323
+ const {
324
+ data = {},
325
+ executionPlatformVersion
326
+ } = report;
327
+
328
+ // adjust FEEL message
329
+ if (data.type === ERROR_TYPES.FEEL_EXPRESSION_INVALID) {
330
+ return 'Unparsable FEEL expression.';
331
+ }
332
+
333
+ if (data.type === ERROR_TYPES.EXPRESSION_NOT_ALLOWED) {
334
+ return 'Cannot be an expression.';
335
+ }
336
+
337
+ if (id === 'isExecutable') {
338
+ const { parentNode } = data;
339
+
340
+ if (parentNode && is(parentNode, 'bpmn:Participant')) {
341
+ return 'One process must be executable.';
342
+ } else {
343
+ return 'Process must be executable.';
344
+ }
345
+ }
346
+
347
+ if ([ 'businessRuleImplementation', 'scriptImplementation' ].includes(id)) {
348
+ return 'Implementation must be defined.';
349
+ }
350
+
351
+ if (id === 'errorRef') {
352
+ return 'Global error reference must be defined.';
353
+ }
354
+
355
+ if (id === 'escalationRef') {
356
+ return 'Global escalation reference must be defined.';
357
+ }
358
+
359
+ if (id === 'messageRef') {
360
+ return 'Global message reference must be defined.';
361
+ }
362
+
363
+ if (id === 'signalRef') {
364
+ return 'Global signal reference must be defined.';
365
+ }
366
+
367
+ if (id === 'decisionId') {
368
+ return 'Decision ID must be defined.';
369
+ }
370
+
371
+ if (id === 'scriptExpression') {
372
+ return 'FEEL expression must be defined.';
373
+ }
374
+
375
+ if (id === 'resultVariable') {
376
+ return 'Result variable must be defined.';
377
+ }
378
+
379
+ if (id === 'errorCode' && data.type === ERROR_TYPES.PROPERTY_REQUIRED) {
380
+ return 'Code must be defined.';
381
+ }
382
+
383
+ if (id === 'escalationCode' && data.type === ERROR_TYPES.PROPERTY_REQUIRED) {
384
+ return 'Code must be defined.';
385
+ }
386
+
387
+ if (id === 'messageName') {
388
+ return 'Name must be defined.';
389
+ }
390
+
391
+ if (id === 'signalName') {
392
+ return 'Name must be defined.';
393
+ }
394
+
395
+ if (id === 'multiInstance-inputCollection') {
396
+ return 'Input collection must be defined.';
397
+ }
398
+
399
+ if (id === 'multiInstance-outputCollection') {
400
+ return 'Output collection must be defined.';
401
+ }
402
+
403
+ if (id === 'multiInstance-outputElement') {
404
+ return 'Output element must be defined.';
405
+ }
406
+
407
+ if (id === 'targetProcessId') {
408
+ return 'Process ID must be defined.';
409
+ }
410
+
411
+ if (id === 'taskDefinitionType') {
412
+ return 'Type must be defined.';
413
+ }
414
+
415
+ if (id === 'timerEventDefinitionType' && data.type === ERROR_TYPES.PROPERTY_REQUIRED) {
416
+ return 'Type must be defined.';
417
+ }
418
+
419
+ if (id === 'messageSubscriptionCorrelationKey'
420
+ && [
421
+ ERROR_TYPES.EXTENSION_ELEMENT_REQUIRED,
422
+ ERROR_TYPES.PROPERTY_REQUIRED
423
+ ].includes(data.type)) {
424
+ return 'Subscription correlation key must be defined.';
425
+ }
426
+
427
+ if (id === 'customFormKey') {
428
+ return 'Form key must be defined.';
429
+ }
430
+
431
+ if (id === 'formId') {
432
+ if (data.type === ERROR_TYPES.PROPERTY_REQUIRED) {
433
+ return 'Form ID must be defined.';
434
+ } else if (data.type === ERROR_TYPES.PROPERTY_NOT_ALLOWED) {
435
+ return 'Form ID not supported.';
436
+ }
437
+ }
438
+
439
+ if (id === 'externalReference') {
440
+ return 'External reference must be defined.';
441
+ }
442
+
443
+ if (id === 'formConfiguration') {
444
+ return 'Form JSON configuration must be defined.';
445
+ }
446
+
447
+ if (/^.+-header-[0-9]+-key$/.test(id)) {
448
+ return 'Must be unique.';
449
+ }
450
+
451
+ if (/^.+-extensionProperty-[0-9]+-name$/.test(id)) {
452
+ return 'Not supported.';
453
+ }
454
+
455
+ if (id === 'userTaskImplementation') {
456
+ return 'Supported only in Camunda 8.5 or newer.';
457
+ }
458
+
459
+ if (id === 'conditionExpression') {
460
+ return 'Condition expression must be defined.';
461
+ }
462
+
463
+ if (id === 'timerEventDefinitionType' && data.type === ERROR_TYPES.PROPERTY_NOT_ALLOWED) {
464
+ return 'Type not supported.';
465
+ }
466
+
467
+ if (id === 'timerEventDefinitionValue') {
468
+ if (data.type === ERROR_TYPES.EXPRESSION_REQUIRED) {
469
+ return 'Value must be defined.';
470
+ }
471
+
472
+ const { property } = data;
473
+
474
+ if (property === 'timeCycle') {
475
+ if (!greaterOrEqual(executionPlatformVersion, '8.1')) {
476
+ return 'Must be an expression, an ISO 8601 repeating interval, or a cron expression (cron only supported by Camunda 8.1 or newer).';
477
+ }
478
+
479
+ return 'Must be an expression, an ISO 8601 repeating interval, or a cron expression.';
480
+ }
481
+
482
+ if (property === 'timeDate') {
483
+ return 'Must be an expression, or an ISO 8601 date.';
484
+ }
485
+
486
+ if (property === 'timeDuration') {
487
+ return 'Must be an expression, or an ISO 8601 interval.';
488
+ }
489
+ }
490
+
491
+ if (id === 'assignmentDefinitionCandidateUsers') {
492
+ return 'Not supported.';
493
+ }
494
+
495
+ if (id === 'taskScheduleDueDate') {
496
+ if (data.type === ERROR_TYPES.EXTENSION_ELEMENT_NOT_ALLOWED) {
497
+ return 'Not supported.';
498
+ } else {
499
+ return 'Must be an ISO 8601 date.';
500
+ }
501
+ }
502
+
503
+ if (id === 'taskScheduleFollowUpDate') {
504
+ if (data.type === ERROR_TYPES.EXTENSION_ELEMENT_NOT_ALLOWED) {
505
+ return 'Not supported.';
506
+ } else {
507
+ return 'Must be an ISO 8601 date.';
508
+ }
509
+ }
510
+
511
+ if (id === 'propagateAllParentVariables') {
512
+ return 'Not supported.';
513
+ }
514
+
515
+ if (id === 'linkName') {
516
+ if (data.type === ERROR_TYPES.ELEMENT_PROPERTY_VALUE_DUPLICATED) {
517
+ return 'Must be unique.';
518
+ } else {
519
+ return 'Must be defined.';
520
+ }
521
+ }
522
+
523
+ if (id === 'waitForCompletion') {
524
+ return 'Must wait for completion.';
525
+ }
526
+ }
527
+
528
+ function isExtensionElementNotAllowedError(data, extensionElement, type) {
529
+ return data.type === ERROR_TYPES.EXTENSION_ELEMENT_NOT_ALLOWED
530
+ && is(data.extensionElement, extensionElement)
531
+ && (!type || is(data.node, type));
532
+ }
533
+
534
+ function isExtensionElementRequiredError(data, requiredExtensionElement, type) {
535
+ return data.type === ERROR_TYPES.EXTENSION_ELEMENT_REQUIRED
536
+ && (isArray(data.requiredExtensionElement) && data.requiredExtensionElement.includes(requiredExtensionElement)
537
+ || data.requiredExtensionElement === requiredExtensionElement)
538
+ && (!type || is(data.node, type));
539
+ }
540
+
541
+ function isPropertyDependentRequiredError(data, dependentRequiredProperty, type) {
542
+ return data.type === ERROR_TYPES.PROPERTY_DEPENDENT_REQUIRED
543
+ && data.dependentRequiredProperty === dependentRequiredProperty
544
+ && (!type || is(data.node, type));
545
+ }
546
+
547
+
548
+ function isPropertyError(data, property, type) {
549
+ return getPropertyName(data) === property
550
+ && (!type || is(data.node, type));
551
+ }
552
+
553
+ function getPropertyName(data) {
554
+ if (data.type === ERROR_TYPES.PROPERTY_REQUIRED) {
555
+ return data.requiredProperty;
556
+ }
557
+
558
+ return data.property;
559
+ }
560
+
561
+ function isType(data, type) {
562
+ return data.node && is(data.node, type);
563
+ }
564
+
565
+ function isOneOfPropertiesRequiredError(data, requiredProperty, type) {
566
+ return data.type === ERROR_TYPES.PROPERTY_REQUIRED
567
+ && (isArray(data.requiredProperty) && data.requiredProperty.includes(requiredProperty))
568
+ && (!type || is(data.node, type));
569
+ }
570
+
571
+ function isPropertyValueDuplicatedError(data, propertiesName, duplicatedProperty, type) {
572
+ return data.type === ERROR_TYPES.PROPERTY_VALUE_DUPLICATED
573
+ && data.propertiesName === propertiesName
574
+ && data.duplicatedProperty === duplicatedProperty
575
+ && (!type || is(data.node, type));
576
+ }
577
+
578
+ function isExpressionRequiredError(data, propertyName, type) {
579
+ return data.type === ERROR_TYPES.EXPRESSION_REQUIRED
580
+ && data.property === propertyName
581
+ && (!type || is(data.node, type));
582
+ }
583
+
584
+ function isExpressionValueNotAllowedError(data, propertyName, type) {
585
+ return data.type === ERROR_TYPES.EXPRESSION_VALUE_NOT_ALLOWED
586
+ && data.property === propertyName
587
+ && (!type || is(data.node, type));
588
+ }
589
+
590
+ function isElementPropertyValueDuplicated(data, propertyName, type) {
591
+ return data.type === ERROR_TYPES.ELEMENT_PROPERTY_VALUE_DUPLICATED
592
+ && data.duplicatedProperty === propertyName
593
+ && (!type || is(data.node, type));
594
+ }
595
+
596
+ function getBusinessObject(element) {
597
+ return element.businessObject || element;
598
+ }
599
+
600
+ function isEmptyString(value) {
601
+ return isString(value) && value.trim() === '';
602
602
  }