@camunda/linting 3.37.1 → 3.38.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,828 +1,828 @@
1
- import { ERROR_TYPES } from 'bpmnlint-plugin-camunda-compat/rules/utils/element';
2
-
3
- import { is, isAny } from 'bpmnlint-utils';
4
-
5
- import {
6
- every,
7
- isArray,
8
- isString
9
- } from 'min-dash';
10
-
11
- import { getTypeString } from './types';
12
-
13
- import {
14
- greaterOrEqual,
15
- toSemverMinor
16
- } from './version';
17
-
18
- const TIMER_PROPERTIES = [
19
- 'timeCycle',
20
- 'timeDate',
21
- 'timeDuration'
22
- ];
23
-
24
- const TIMER_PROPERTY_LABELS = {
25
- timeCycle: 'Cycle',
26
- timeDate: 'Date',
27
- timeDuration: 'Duration'
28
- };
29
-
30
- const executionPlatformLabels = {
31
- 'Camunda Cloud': {
32
- 'default': 'Camunda',
33
- '1.0': 'Camunda 8 (Zeebe 1.0)',
34
- '1.1': 'Camunda 8 (Zeebe 1.1)',
35
- '1.2': 'Camunda 8 (Zeebe 1.2)',
36
- '1.3': 'Camunda 8 (Zeebe 1.3)'
37
- }
38
- };
39
-
40
- export function getExecutionPlatformLabel(executionPlatform, executionPlatformVersion) {
41
- const executionPlatformLabel = executionPlatformLabels[ executionPlatform ]
42
- && executionPlatformLabels[ executionPlatform ][ toSemverMinor(executionPlatformVersion) ];
43
-
44
- if (executionPlatformLabel) {
45
- return executionPlatformLabel;
46
- }
47
-
48
- if (executionPlatformLabels[ executionPlatform ]
49
- && executionPlatformLabels[ executionPlatform ][ 'default' ]) {
50
- executionPlatform = executionPlatformLabels[ executionPlatform ][ 'default' ];
51
- }
52
-
53
- return `${ executionPlatform } ${ toSemverMinor(executionPlatformVersion) }`;
54
- }
55
-
56
- function getIndefiniteArticle(type, uppercase = true) {
57
- if ([
58
- 'Ad',
59
- 'Error',
60
- 'Escalation',
61
- 'Event',
62
- 'Inclusive',
63
- 'Intermediate',
64
- 'Undefined'
65
- ].includes(type.split(' ')[ 0 ])) {
66
- return uppercase ? 'An' : 'an';
67
- }
68
-
69
- return uppercase ? 'A' : 'a';
70
- }
71
-
72
- export function getErrorMessage(report, executionPlatform, executionPlatformVersion, modeler = 'desktop') {
73
- const {
74
- data,
75
- message
76
- } = report;
77
-
78
- if (!data) {
79
- return message;
80
- }
81
-
82
- const { type } = data;
83
-
84
- if (type === ERROR_TYPES.CHILD_ELEMENT_TYPE_NOT_ALLOWED) {
85
- return getChildElementTypeNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion);
86
- }
87
-
88
- if (type === ERROR_TYPES.ELEMENT_COLLAPSED_NOT_ALLOWED) {
89
- return getElementCollapsedNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion);
90
- }
91
-
92
- if (type === ERROR_TYPES.ELEMENT_PROPERTY_VALUE_DUPLICATED) {
93
- return getElementPropertyValueDuplicatedErrorMessage(report);
94
- }
95
-
96
- if (type === ERROR_TYPES.ELEMENT_TYPE_NOT_ALLOWED) {
97
- return getElementTypeNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion);
98
- }
99
-
100
- if (type === ERROR_TYPES.EXTENSION_ELEMENT_NOT_ALLOWED) {
101
- return getExtensionElementNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion);
102
- }
103
-
104
- if (type === ERROR_TYPES.EXTENSION_ELEMENT_REQUIRED) {
105
- return getExtensionElementRequiredErrorMessage(report, executionPlatform, executionPlatformVersion);
106
- }
107
-
108
- if (type === ERROR_TYPES.PROPERTY_DEPENDENT_REQUIRED) {
109
- return getPropertyDependentRequiredErrorMessage(report);
110
- }
111
-
112
- if (type === ERROR_TYPES.PROPERTY_NOT_ALLOWED) {
113
- return getPropertyNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion, modeler);
114
- }
115
-
116
- if (type === ERROR_TYPES.PROPERTY_REQUIRED) {
117
- return getPropertyRequiredErrorMessage(report, executionPlatform, executionPlatformVersion);
118
- }
119
-
120
- if (type === ERROR_TYPES.PROPERTY_VALUE_DUPLICATED) {
121
- return getPropertyValueDuplicatedErrorMessage(report);
122
- }
123
-
124
- if (type === ERROR_TYPES.PROPERTY_VALUES_DUPLICATED) {
125
- return getPropertyValuesDuplicatedErrorMessage(report);
126
- }
127
-
128
- if (type == ERROR_TYPES.PROPERTY_VALUE_NOT_ALLOWED) {
129
- return getPropertyValueNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion, modeler);
130
- }
131
-
132
- if (type === ERROR_TYPES.PROPERTY_VALUE_REQUIRED) {
133
- return getPropertyValueRequiredErrorMessage(report, executionPlatform, executionPlatformVersion);
134
- }
135
-
136
- if (type === ERROR_TYPES.EXPRESSION_REQUIRED) {
137
- return getExpressionRequiredErrorMessage(report);
138
- }
139
-
140
- if (type === ERROR_TYPES.EXPRESSION_VALUE_NOT_ALLOWED) {
141
- return getExpressionValueNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion);
142
- }
143
-
144
- if (type === ERROR_TYPES.EXPRESSION_NOT_ALLOWED) {
145
- return getExpressionNotAllowedErrorMessage(report);
146
- }
147
-
148
- if (type === ERROR_TYPES.EVENT_BASED_GATEWAY_TARGET_NOT_ALLOWED) {
149
- return getEventBasedGatewayTargetNotAllowedErrorMessage(report);
150
- }
151
-
152
- if (type === ERROR_TYPES.SECRET_EXPRESSION_FORMAT_DEPRECATED) {
153
- return getSecretExpressionFormatDeprecatedErrorMessage(report);
154
- }
155
-
156
- if (type === ERROR_TYPES.LOOP_NOT_ALLOWED) {
157
- return getLoopNotAllowedErrorMessage(report);
158
- }
159
-
160
- if (type === ERROR_TYPES.ATTACHED_TO_REF_ELEMENT_TYPE_NOT_ALLOWED) {
161
- return getAttachedToRefElementTypeNotAllowed(report);
162
- }
163
-
164
- return message;
165
- }
166
-
167
- function getChildElementTypeNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion) {
168
- const { data } = report;
169
-
170
- const {
171
- allowedVersion,
172
- node,
173
- parent
174
- } = data;
175
-
176
- const typeString = getTypeString(node),
177
- parentTypeString = getTypeString(parent);
178
-
179
- return getSupportedMessage(
180
- `${ getIndefiniteArticle(typeString) } <${ typeString }> in ${ getIndefiniteArticle(parentTypeString, false) } <${ parentTypeString }>`,
181
- executionPlatform,
182
- executionPlatformVersion,
183
- allowedVersion
184
- );
185
- }
186
-
187
- function getElementCollapsedNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion) {
188
- const {
189
- data,
190
- message
191
- } = report;
192
-
193
- const { allowedVersion, node } = data;
194
-
195
- const typeString = getTypeString(node);
196
-
197
- if (is(node, 'bpmn:SubProcess')) {
198
- return getSupportedMessage(`A collapsed <${typeString}>`, executionPlatform, executionPlatformVersion, allowedVersion);
199
- }
200
-
201
- return message;
202
- }
203
-
204
- function getElementTypeNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion) {
205
- const { data } = report;
206
-
207
- const {
208
- allowedVersion,
209
- node
210
- } = data;
211
-
212
- const typeString = getTypeString(node);
213
-
214
- return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }>`, executionPlatform, executionPlatformVersion, allowedVersion);
215
- }
216
-
217
- function getPropertyValueDuplicatedErrorMessage(report) {
218
- const {
219
- data,
220
- message
221
- } = report;
222
-
223
- const {
224
- node,
225
- parentNode,
226
- duplicatedPropertyValue,
227
- properties
228
- } = data;
229
-
230
- const typeString = getTypeString(parentNode || node);
231
-
232
- if (is(node, 'zeebe:TaskHeaders') && every(properties, property => is(property, 'zeebe:Header'))) {
233
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with two or more <Headers> with the same <Key> (${ duplicatedPropertyValue }) is not supported`;
234
- }
235
-
236
- return message;
237
- }
238
-
239
- function getPropertyValuesDuplicatedErrorMessage(report) {
240
- const {
241
- data,
242
- message
243
- } = report;
244
-
245
- const {
246
- node,
247
- parentNode,
248
- duplicatedProperties,
249
- properties
250
- } = data;
251
-
252
- const {
253
- eventType,
254
- type
255
- } = duplicatedProperties;
256
-
257
- const typeString = getTypeString(parentNode || node);
258
-
259
- if (is(node, 'zeebe:ExecutionListeners') && every(properties, property => is(property, 'zeebe:ExecutionListener'))) {
260
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with two or more <Execution Listeners> with the same <Event Type> (${ eventType }) and <Type> (${ type }) is not supported`;
261
- }
262
-
263
- return message;
264
- }
265
-
266
- function getPropertyValueRequiredErrorMessage(report, executionPlatform, executionPlatformVersion) {
267
- const {
268
- data,
269
- message
270
- } = report;
271
-
272
- const {
273
- allowedVersion,
274
- node,
275
- property,
276
- parentNode
277
- } = data;
278
-
279
- if (is(node, 'bpmn:Process') && property === 'isExecutable') {
280
- if (parentNode && is(parentNode, 'bpmn:Participant')) {
281
- return 'One <Process> must be <Executable>';
282
- } else {
283
- return 'A <Process> must be <Executable>';
284
- }
285
- }
286
-
287
- const typeString = getTypeString(parentNode || node);
288
-
289
- if (is(node, 'bpmn:CompensateEventDefinition') && property === 'waitForCompletion') {
290
- return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Wait for completion> disabled`, executionPlatform, executionPlatformVersion, allowedVersion);
291
- }
292
-
293
- return message;
294
- }
295
-
296
- function getExtensionElementNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion) {
297
- const {
298
- data,
299
- message
300
- } = report;
301
-
302
- const {
303
- allowedVersion,
304
- node,
305
- parentNode,
306
- extensionElement
307
- } = data;
308
-
309
- const typeString = getTypeString(parentNode || node);
310
-
311
- if (is(node, 'bpmn:BusinessRuleTask') && is(extensionElement, 'zeebe:CalledDecision')) {
312
- return getSupportedMessage('A <Business Rule Task> with <Implementation: DMN decision>', executionPlatform, executionPlatformVersion, allowedVersion);
313
- }
314
-
315
- if (is(extensionElement, 'zeebe:Properties')) {
316
- return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Extension properties>`, executionPlatform, executionPlatformVersion, allowedVersion);
317
- }
318
-
319
- if (is(extensionElement, 'zeebe:UserTask')) {
320
- return getSupportedMessage('A <User Task> with <Implementation: Camunda user task>', executionPlatform, executionPlatformVersion, allowedVersion);
321
- }
322
-
323
- if (is(node, 'bpmn:ScriptTask') && is(extensionElement, 'zeebe:Script')) {
324
- return getSupportedMessage('A <Script Task> with <Implementation: FEEL expression>', executionPlatform, executionPlatformVersion, allowedVersion);
325
- }
326
-
327
- if (is(node, 'bpmn:UserTask') && is(extensionElement, 'zeebe:TaskSchedule')) {
328
- return getSupportedMessage('A <User Task> with <Due date> or <Follow up date>', executionPlatform, executionPlatformVersion, allowedVersion);
329
- }
330
-
331
- if (is(node, 'bpmn:UserTask') && is(extensionElement, 'zeebe:PriorityDefinition')) {
332
- return getSupportedMessage('A <User Task> with <Priority>', executionPlatform, executionPlatformVersion, allowedVersion);
333
- }
334
-
335
- if (is(node, 'bpmn:StartEvent') && is(extensionElement, 'zeebe:FormDefinition')) {
336
- return getSupportedMessage('A <Start Event> with <User Task Form>', executionPlatform, executionPlatformVersion, allowedVersion);
337
- }
338
-
339
- if (is(extensionElement, 'zeebe:ExecutionListeners')) {
340
- return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Execution listeners>`, executionPlatform, executionPlatformVersion, allowedVersion);
341
- }
342
-
343
- if (is(extensionElement, 'zeebe:TaskListeners')) {
344
- return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Task listeners>`, executionPlatform, executionPlatformVersion, allowedVersion);
345
- }
346
-
347
- if (is(node, 'bpmn:Process') && is(extensionElement, 'zeebe:VersionTag')) {
348
- return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Version tag>`, executionPlatform, executionPlatformVersion, allowedVersion);
349
- }
350
-
351
- return message;
352
- }
353
-
354
- function getExtensionElementRequiredErrorMessage(report, executionPlatform, executionPlatformVersion) {
355
- const {
356
- data,
357
- message
358
- } = report;
359
-
360
- const {
361
- node,
362
- parentNode,
363
- requiredExtensionElement
364
- } = data;
365
-
366
- const typeString = getTypeString(parentNode || node);
367
-
368
- if (requiredExtensionElement === 'zeebe:CalledElement') {
369
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Called element>`;
370
- }
371
-
372
- if (requiredExtensionElement === 'zeebe:LoopCharacteristics') {
373
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Multi-instance marker> must have a defined <Input collection>`;
374
- }
375
-
376
- if (requiredExtensionElement === 'zeebe:Subscription') {
377
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Message Reference> must have a defined <Subscription correlation key>`;
378
- }
379
-
380
- if (requiredExtensionElement === 'zeebe:TaskDefinition') {
381
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a <Task definition type>`;
382
- }
383
-
384
- if (isArray(requiredExtensionElement) && requiredExtensionElement.includes('zeebe:CalledDecision')) {
385
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Implementation>`;
386
- }
387
-
388
- if (isArray(requiredExtensionElement) && requiredExtensionElement.includes('zeebe:Script')) {
389
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Implementation>`;
390
- }
391
-
392
- if (requiredExtensionElement === 'zeebe:FormDefinition') {
393
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> should have a defined <Form>`;
394
- }
395
-
396
- if (requiredExtensionElement === 'zeebe:UserTask') {
397
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Implementation: Job worker> managed by Camunda is deprecated. Consider migrating to <Implementation: Camunda user task>.`;
398
- }
399
-
400
- return message;
401
- }
402
-
403
- function getPropertyDependentRequiredErrorMessage(report) {
404
- const {
405
- data,
406
- message
407
- } = report;
408
-
409
- const {
410
- node,
411
- parentNode,
412
- property,
413
- dependentRequiredProperty
414
- } = data;
415
-
416
- const typeString = getTypeString(parentNode || node);
417
-
418
- if (is(node, 'zeebe:LoopCharacteristics') && property === 'outputCollection' && dependentRequiredProperty === 'outputElement') {
419
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Multi-instance marker> and defined <Output collection> must have a defined <Output element>`;
420
- }
421
-
422
- if (is(node, 'zeebe:LoopCharacteristics') && property === 'outputElement' && dependentRequiredProperty === 'outputCollection') {
423
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Multi-instance marker> and defined <Output element> must have a defined <Output collection>`;
424
- }
425
-
426
- return message;
427
- }
428
-
429
- function getPropertyNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion, modeler = 'desktop') {
430
- const {
431
- data,
432
- message
433
- } = report;
434
-
435
- const {
436
- allowedVersion,
437
- node,
438
- parentNode,
439
- property
440
- } = data;
441
-
442
- const typeString = getTypeString(parentNode || node);
443
-
444
- if (property === 'modelerTemplate') {
445
- if (modeler === 'desktop') {
446
- return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <Template ${ typeString }>`, executionPlatform, executionPlatformVersion, allowedVersion);
447
- } else if (modeler === 'web') {
448
- return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <Connector ${ typeString }>`, executionPlatform, executionPlatformVersion, allowedVersion);
449
- }
450
- }
451
-
452
- if (is(node, 'bpmn:InclusiveGateway') && property === 'incoming') {
453
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with more than one incoming <Sequence Flow> is not supported by ${ getExecutionPlatformLabel(executionPlatform, executionPlatformVersion) }`;
454
- }
455
-
456
- if (is(node, 'zeebe:AssignmentDefinition') && property === 'candidateUsers') {
457
- return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Candidate users>`, executionPlatform, executionPlatformVersion, allowedVersion);
458
- }
459
-
460
- if (is(node, 'bpmn:SequenceFlow') && property === 'conditionExpression') {
461
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Condition expression> is only supported if the source is an <Exclusive Gateway> or <Inclusive Gateway>`;
462
- }
463
-
464
- if (is(node, 'bpmn:TimerEventDefinition') && TIMER_PROPERTIES.includes(property)) {
465
- return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <${ TIMER_PROPERTY_LABELS[ property ] }>`, executionPlatform, executionPlatformVersion, allowedVersion);
466
- }
467
-
468
- if (is(node, 'zeebe:FormDefinition') && property === 'formId') {
469
- return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Form type: Camunda form (linked)>`, executionPlatform, executionPlatformVersion, allowedVersion);
470
- }
471
-
472
- return message;
473
- }
474
-
475
-
476
- function getPropertyRequiredErrorMessage(report, executionPlatform, executionPlatformVersion) {
477
- const {
478
- data,
479
- message
480
- } = report;
481
-
482
- const {
483
- allowedVersion,
484
- node,
485
- parentNode,
486
- requiredProperty
487
- } = data;
488
-
489
- function isRequiredProperty(requiredPropertyToLookUp) {
490
- return requiredProperty === requiredPropertyToLookUp || (isArray(requiredProperty) && requiredProperty.includes(requiredPropertyToLookUp));
491
- }
492
-
493
- const typeString = getTypeString(parentNode || node);
494
-
495
- if (parentNode && is(parentNode, 'bpmn:BusinessRuleTask') && is(node, 'zeebe:CalledDecision') && requiredProperty === 'decisionId') {
496
- return 'A <Business Rule Task> with <Implementation: DMN decision> must have a defined <Called decision ID>';
497
- }
498
-
499
- if (parentNode && is(parentNode, 'bpmn:BusinessRuleTask') && is(node, 'zeebe:CalledDecision') && requiredProperty === 'resultVariable') {
500
- return 'A <Business Rule Task> with <Implementation: DMN decision> must have a defined <Result variable>';
501
- }
502
-
503
- if (parentNode && is(parentNode, 'bpmn:ScriptTask') && is(node, 'zeebe:Script') && requiredProperty === 'expression') {
504
- return 'A <Script Task> with <Implementation: FEEL expression> must have a defined <FEEL expression>';
505
- }
506
-
507
- if (parentNode && is(parentNode, 'bpmn:ScriptTask') && is(node, 'zeebe:Script') && requiredProperty === 'resultVariable') {
508
- return 'A <Script Task> with <Implementation: FEEL expression> must have a defined <Result variable>';
509
- }
510
-
511
- if (parentNode && isAny(parentNode, [ 'bpmn:BusinessRuleTask', 'bpmn:ScriptTask' ]) && is(node, 'zeebe:TaskDefinition') && requiredProperty === 'type') {
512
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Implementation: Job worker> must have a defined <Task definition type>`;
513
- }
514
-
515
- if (is(node, 'zeebe:CalledElement') && requiredProperty === 'processId') {
516
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Called element>`;
517
- }
518
-
519
- if (is(node, 'bpmn:Error') && requiredProperty === 'errorCode') {
520
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Error Reference> must have a defined <Error code>`;
521
- }
522
-
523
- if (is(node, 'bpmn:Escalation') && requiredProperty === 'escalationCode') {
524
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Escalation Reference> must have a defined <Escalation code>`;
525
- }
526
-
527
- if (is(node, 'zeebe:LoopCharacteristics') && requiredProperty === 'inputCollection') {
528
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Multi-instance marker> must have a defined <Input collection>`;
529
- }
530
-
531
- if (is(node, 'bpmn:Message') && requiredProperty === 'name') {
532
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Message Reference> must have a defined <Name>`;
533
- }
534
-
535
- if (is(node, 'bpmn:Signal') && requiredProperty === 'name') {
536
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Signal Reference> must have a defined <Name>`;
537
- }
538
-
539
- if (is(node, 'zeebe:Subscription') && requiredProperty === 'correlationKey') {
540
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Message Reference> must have a defined <Subscription correlation key>`;
541
- }
542
-
543
- if (is(node, 'zeebe:TaskDefinition') && requiredProperty === 'type') {
544
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Implementation: Job worker> must have a defined <Task definition type>`;
545
- }
546
-
547
- if (is(node, 'zeebe:ExecutionListener') && requiredProperty === 'type') {
548
- return 'An <Execution Listener> must have a defined <Type>';
549
- }
550
-
551
- if (is(node, 'zeebe:TaskListener') && requiredProperty === 'type') {
552
- return 'A <Task Listener> must have a defined <Type>';
553
- }
554
-
555
- if (requiredProperty === 'errorRef') {
556
-
557
- if (parentNode && is(parentNode, 'bpmn:CatchEvent')) {
558
- return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> without defined <Error Reference>`, executionPlatform, executionPlatformVersion, allowedVersion);
559
- } else if (parentNode && is(parentNode, 'bpmn:ThrowEvent')) {
560
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Error Reference>`;
561
- }
562
-
563
- }
564
-
565
- if (requiredProperty === 'messageRef') {
566
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Message Reference>`;
567
- }
568
-
569
- if (requiredProperty === 'signalRef') {
570
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Signal Reference>`;
571
- }
572
-
573
- if (is(node, 'zeebe:FormDefinition')
574
- && (
575
- requiredProperty === 'formKey'
576
- || (isArray(requiredProperty) && requiredProperty.includes('formKey') && isEmptyString(node.get('formKey')))
577
- )) {
578
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Form type: Custom form key> must have a defined <Form key>`;
579
- }
580
-
581
- // Camunda User Task
582
- if (is(node, 'zeebe:FormDefinition') && isZeebeUserTask(parentNode)) {
583
- if (isRequiredProperty('externalReference') && isEmptyString(node.get('externalReference'))) {
584
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Form type: External reference> must have a defined <External reference>`;
585
- } else if (isRequiredProperty('formId') && isEmptyString(node.get('formId'))) {
586
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Form type: Camunda Form> must have a defined <Form ID>`;
587
- }
588
- }
589
-
590
- if (is(node, 'zeebe:FormDefinition') && isRequiredProperty('formId') && isEmptyString(node.get('formId'))) {
591
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Form type: Camunda form (linked)> must have a defined <Form ID>`;
592
- }
593
-
594
- if (is(node, 'zeebe:UserTaskForm') && requiredProperty === 'body') {
595
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Form type: Camunda form (embedded)> must have a defined <Form JSON configuration>`;
596
- }
597
-
598
- if (is(node, 'bpmn:SequenceFlow') && requiredProperty === 'conditionExpression') {
599
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Condition expression> or be the default <Sequence Flow>`;
600
- }
601
-
602
- if (is(node, 'bpmn:TimerEventDefinition')
603
- && isArray(requiredProperty)
604
- && TIMER_PROPERTIES.some(property => requiredProperty.includes(property))
605
- ) {
606
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Timer type>`;
607
- }
608
-
609
- if (is(node, 'bpmn:Process') && requiredProperty === 'historyTimeToLive') {
610
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <History time to live>`;
611
- }
612
-
613
- if (is(node, 'bpmn:LinkEventDefinition') && requiredProperty === 'name') {
614
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Name>`;
615
- }
616
-
617
- if (isAny(node, [
618
- 'zeebe:CalledDecision',
619
- 'zeebe:CalledElement',
620
- 'zeebe:FormDefinition'
621
- ]) && requiredProperty === 'versionTag') {
622
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Binding: version tag> must have a defined <Version tag>`;
623
- }
624
-
625
- return message;
626
- }
627
-
628
- function getExpressionRequiredErrorMessage(report) {
629
- const {
630
- data,
631
- message
632
- } = report;
633
-
634
- const {
635
- node,
636
- parentNode,
637
- property
638
- } = data;
639
-
640
- const typeString = getTypeString(parentNode || node);
641
-
642
- if (is(node, 'bpmn:FormalExpression') && TIMER_PROPERTIES.includes(property)) {
643
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Timer value>`;
644
- }
645
-
646
- return message;
647
- }
648
-
649
- function getExpressionValueNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion) {
650
- const {
651
- data,
652
- message
653
- } = report;
654
-
655
- const {
656
- node,
657
- parentNode,
658
- property
659
- } = data;
660
-
661
- const typeString = getTypeString(parentNode || node);
662
-
663
- if (is(node, 'bpmn:FormalExpression') && property === 'timeCycle') {
664
- if (!greaterOrEqual(executionPlatformVersion, '8.1')) {
665
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> <Time cycle> must be an expression, an ISO 8601 repeating interval, or a cron expression (cron only supported by Camunda 8.1 or newer)`;
666
- } else {
667
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> <Time cycle> must be an expression, an ISO 8601 repeating interval, or a cron expression`;
668
- }
669
- }
670
-
671
- if (is(node, 'bpmn:FormalExpression') && property === 'timeDate') {
672
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> <Time date> must be an expression, or an ISO 8601 date`;
673
- }
674
-
675
- if (is(node, 'bpmn:FormalExpression') && property === 'timeDuration') {
676
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> <Time duration> must be an expression, or an ISO 8601 interval`;
677
- }
678
-
679
- if (is(node, 'zeebe:TaskSchedule') && property === 'dueDate') {
680
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> <Due date> must be an ISO 8601 date`;
681
- }
682
-
683
- if (is(node, 'zeebe:TaskSchedule') && property === 'followUpDate') {
684
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> <Follow up date> must be an ISO 8601 date`;
685
- }
686
-
687
- if (is(node, 'zeebe:PriorityDefinition') && property === 'priority') {
688
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> <Priority> must be an expression, or an integer between 0 and 100`;
689
- }
690
-
691
- return message;
692
- }
693
-
694
- function getSupportedMessage(prefix, executionPlatform, executionPlatformVersion, allowedVersion) {
695
- if (allowedVersion) {
696
- return `${ prefix } is only supported by ${ getExecutionPlatformLabel(executionPlatform, allowedVersion) } or newer`;
697
- }
698
-
699
- return `${ prefix } is not supported by ${ getExecutionPlatformLabel(executionPlatform, executionPlatformVersion) }`;
700
- }
701
-
702
- function getExpressionNotAllowedErrorMessage(report) {
703
- const {
704
- data
705
- } = report;
706
-
707
- const {
708
- node,
709
- parentNode,
710
- property
711
- } = data;
712
-
713
- if (is(node, 'bpmn:Escalation') && property === 'escalationCode' && is(parentNode, 'bpmn:CatchEvent')) {
714
- return 'Escalation code used in a catch event must be a static value';
715
- } else if (is(node, 'bpmn:Error') && property === 'errorCode' && is(parentNode, 'bpmn:CatchEvent')) {
716
- return 'Error code used in a catch event must be a static value';
717
- }
718
-
719
- return report.message;
720
- }
721
-
722
- function getEventBasedGatewayTargetNotAllowedErrorMessage(report) {
723
- const { data } = report;
724
-
725
- const { node } = data;
726
-
727
- if (is(node, 'bpmn:ReceiveTask')) {
728
- return 'A <Receive Task> cannot be the target of an <Event-Based Gateway>';
729
- }
730
-
731
- return report.message;
732
- }
733
-
734
- function getPropertyValueNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion, modeler = 'desktop') {
735
- const {
736
- data,
737
- message
738
- } = report;
739
-
740
- const {
741
- allowedVersion,
742
- node,
743
- parentNode,
744
- property
745
- } = data;
746
-
747
- const typeString = getTypeString(parentNode || node);
748
-
749
- if (is(node, 'zeebe:CalledElement') && property === 'propagateAllParentVariables') {
750
- return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Propagate all variables> disabled`, executionPlatform, executionPlatformVersion, allowedVersion);
751
- }
752
-
753
- if (isAny(node, [
754
- 'zeebe:CalledDecision',
755
- 'zeebe:CalledElement',
756
- 'zeebe:FormDefinition'
757
- ]) && property === 'bindingType') {
758
- const bindingType = node.get('bindingType');
759
-
760
- let bindingTypeString = bindingType;
761
-
762
- if (bindingType === 'versionTag') {
763
- bindingTypeString = 'version tag';
764
- }
765
-
766
- return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Binding: ${ bindingTypeString }>`, executionPlatform, executionPlatformVersion, allowedVersion);
767
- }
768
-
769
- return message;
770
- }
771
-
772
- function getSecretExpressionFormatDeprecatedErrorMessage(report) {
773
- const { data } = report;
774
-
775
- const { property } = data;
776
-
777
- return `Property <${ property }> uses deprecated secret expression format secrets.SECRET, use {{secrets.SECRET}} instead`;
778
- }
779
-
780
- function getElementPropertyValueDuplicatedErrorMessage(report) {
781
- const {
782
- data,
783
- message
784
- } = report;
785
-
786
- const {
787
- node,
788
- parentNode,
789
- duplicatedProperty
790
- } = data;
791
-
792
- const typeString = getTypeString(parentNode || node);
793
-
794
- if (is(node, 'bpmn:LinkEventDefinition') && duplicatedProperty === 'name') {
795
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a unique <Name>`;
796
- }
797
-
798
- return message;
799
- }
800
-
801
- function getLoopNotAllowedErrorMessage(report) {
802
- const { data } = report;
803
-
804
- const { elements } = data;
805
-
806
- return `A <Process> is not allowed to contain a straight-through processing loop: ${ elements.map(element => `<${ element }>`).join(', ') }`;
807
- }
808
-
809
- function getAttachedToRefElementTypeNotAllowed(report) {
810
- const { data } = report;
811
-
812
- const { node , attachedToRef } = data;
813
-
814
- const nodeTypeString = getTypeString(node);
815
- const attachedToTypeString = getTypeString(attachedToRef);
816
-
817
- return `${ getIndefiniteArticle(nodeTypeString) } <${nodeTypeString}> is not allowed on ${ getIndefiniteArticle(attachedToTypeString, false) } <${attachedToTypeString}>`;
818
- }
819
-
820
- function isEmptyString(value) {
821
- return isString(value) && value.trim() === '';
822
- }
823
-
824
- function isZeebeUserTask(node) {
825
- return node.get('extensionElements').get('values').some(extensionElement => {
826
- return is(extensionElement, 'zeebe:UserTask');
827
- });
828
- }
1
+ import { ERROR_TYPES } from 'bpmnlint-plugin-camunda-compat/rules/utils/element';
2
+
3
+ import { is, isAny } from 'bpmnlint-utils';
4
+
5
+ import {
6
+ every,
7
+ isArray,
8
+ isString
9
+ } from 'min-dash';
10
+
11
+ import { getTypeString } from './types';
12
+
13
+ import {
14
+ greaterOrEqual,
15
+ toSemverMinor
16
+ } from './version';
17
+
18
+ const TIMER_PROPERTIES = [
19
+ 'timeCycle',
20
+ 'timeDate',
21
+ 'timeDuration'
22
+ ];
23
+
24
+ const TIMER_PROPERTY_LABELS = {
25
+ timeCycle: 'Cycle',
26
+ timeDate: 'Date',
27
+ timeDuration: 'Duration'
28
+ };
29
+
30
+ const executionPlatformLabels = {
31
+ 'Camunda Cloud': {
32
+ 'default': 'Camunda',
33
+ '1.0': 'Camunda 8 (Zeebe 1.0)',
34
+ '1.1': 'Camunda 8 (Zeebe 1.1)',
35
+ '1.2': 'Camunda 8 (Zeebe 1.2)',
36
+ '1.3': 'Camunda 8 (Zeebe 1.3)'
37
+ }
38
+ };
39
+
40
+ export function getExecutionPlatformLabel(executionPlatform, executionPlatformVersion) {
41
+ const executionPlatformLabel = executionPlatformLabels[ executionPlatform ]
42
+ && executionPlatformLabels[ executionPlatform ][ toSemverMinor(executionPlatformVersion) ];
43
+
44
+ if (executionPlatformLabel) {
45
+ return executionPlatformLabel;
46
+ }
47
+
48
+ if (executionPlatformLabels[ executionPlatform ]
49
+ && executionPlatformLabels[ executionPlatform ][ 'default' ]) {
50
+ executionPlatform = executionPlatformLabels[ executionPlatform ][ 'default' ];
51
+ }
52
+
53
+ return `${ executionPlatform } ${ toSemverMinor(executionPlatformVersion) }`;
54
+ }
55
+
56
+ function getIndefiniteArticle(type, uppercase = true) {
57
+ if ([
58
+ 'Ad',
59
+ 'Error',
60
+ 'Escalation',
61
+ 'Event',
62
+ 'Inclusive',
63
+ 'Intermediate',
64
+ 'Undefined'
65
+ ].includes(type.split(' ')[ 0 ])) {
66
+ return uppercase ? 'An' : 'an';
67
+ }
68
+
69
+ return uppercase ? 'A' : 'a';
70
+ }
71
+
72
+ export function getErrorMessage(report, executionPlatform, executionPlatformVersion, modeler = 'desktop') {
73
+ const {
74
+ data,
75
+ message
76
+ } = report;
77
+
78
+ if (!data) {
79
+ return message;
80
+ }
81
+
82
+ const { type } = data;
83
+
84
+ if (type === ERROR_TYPES.CHILD_ELEMENT_TYPE_NOT_ALLOWED) {
85
+ return getChildElementTypeNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion);
86
+ }
87
+
88
+ if (type === ERROR_TYPES.ELEMENT_COLLAPSED_NOT_ALLOWED) {
89
+ return getElementCollapsedNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion);
90
+ }
91
+
92
+ if (type === ERROR_TYPES.ELEMENT_PROPERTY_VALUE_DUPLICATED) {
93
+ return getElementPropertyValueDuplicatedErrorMessage(report);
94
+ }
95
+
96
+ if (type === ERROR_TYPES.ELEMENT_TYPE_NOT_ALLOWED) {
97
+ return getElementTypeNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion);
98
+ }
99
+
100
+ if (type === ERROR_TYPES.EXTENSION_ELEMENT_NOT_ALLOWED) {
101
+ return getExtensionElementNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion);
102
+ }
103
+
104
+ if (type === ERROR_TYPES.EXTENSION_ELEMENT_REQUIRED) {
105
+ return getExtensionElementRequiredErrorMessage(report, executionPlatform, executionPlatformVersion);
106
+ }
107
+
108
+ if (type === ERROR_TYPES.PROPERTY_DEPENDENT_REQUIRED) {
109
+ return getPropertyDependentRequiredErrorMessage(report);
110
+ }
111
+
112
+ if (type === ERROR_TYPES.PROPERTY_NOT_ALLOWED) {
113
+ return getPropertyNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion, modeler);
114
+ }
115
+
116
+ if (type === ERROR_TYPES.PROPERTY_REQUIRED) {
117
+ return getPropertyRequiredErrorMessage(report, executionPlatform, executionPlatformVersion);
118
+ }
119
+
120
+ if (type === ERROR_TYPES.PROPERTY_VALUE_DUPLICATED) {
121
+ return getPropertyValueDuplicatedErrorMessage(report);
122
+ }
123
+
124
+ if (type === ERROR_TYPES.PROPERTY_VALUES_DUPLICATED) {
125
+ return getPropertyValuesDuplicatedErrorMessage(report);
126
+ }
127
+
128
+ if (type == ERROR_TYPES.PROPERTY_VALUE_NOT_ALLOWED) {
129
+ return getPropertyValueNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion, modeler);
130
+ }
131
+
132
+ if (type === ERROR_TYPES.PROPERTY_VALUE_REQUIRED) {
133
+ return getPropertyValueRequiredErrorMessage(report, executionPlatform, executionPlatformVersion);
134
+ }
135
+
136
+ if (type === ERROR_TYPES.EXPRESSION_REQUIRED) {
137
+ return getExpressionRequiredErrorMessage(report);
138
+ }
139
+
140
+ if (type === ERROR_TYPES.EXPRESSION_VALUE_NOT_ALLOWED) {
141
+ return getExpressionValueNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion);
142
+ }
143
+
144
+ if (type === ERROR_TYPES.EXPRESSION_NOT_ALLOWED) {
145
+ return getExpressionNotAllowedErrorMessage(report);
146
+ }
147
+
148
+ if (type === ERROR_TYPES.EVENT_BASED_GATEWAY_TARGET_NOT_ALLOWED) {
149
+ return getEventBasedGatewayTargetNotAllowedErrorMessage(report);
150
+ }
151
+
152
+ if (type === ERROR_TYPES.SECRET_EXPRESSION_FORMAT_DEPRECATED) {
153
+ return getSecretExpressionFormatDeprecatedErrorMessage(report);
154
+ }
155
+
156
+ if (type === ERROR_TYPES.LOOP_NOT_ALLOWED) {
157
+ return getLoopNotAllowedErrorMessage(report);
158
+ }
159
+
160
+ if (type === ERROR_TYPES.ATTACHED_TO_REF_ELEMENT_TYPE_NOT_ALLOWED) {
161
+ return getAttachedToRefElementTypeNotAllowed(report);
162
+ }
163
+
164
+ return message;
165
+ }
166
+
167
+ function getChildElementTypeNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion) {
168
+ const { data } = report;
169
+
170
+ const {
171
+ allowedVersion,
172
+ node,
173
+ parent
174
+ } = data;
175
+
176
+ const typeString = getTypeString(node),
177
+ parentTypeString = getTypeString(parent);
178
+
179
+ return getSupportedMessage(
180
+ `${ getIndefiniteArticle(typeString) } <${ typeString }> in ${ getIndefiniteArticle(parentTypeString, false) } <${ parentTypeString }>`,
181
+ executionPlatform,
182
+ executionPlatformVersion,
183
+ allowedVersion
184
+ );
185
+ }
186
+
187
+ function getElementCollapsedNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion) {
188
+ const {
189
+ data,
190
+ message
191
+ } = report;
192
+
193
+ const { allowedVersion, node } = data;
194
+
195
+ const typeString = getTypeString(node);
196
+
197
+ if (is(node, 'bpmn:SubProcess')) {
198
+ return getSupportedMessage(`A collapsed <${typeString}>`, executionPlatform, executionPlatformVersion, allowedVersion);
199
+ }
200
+
201
+ return message;
202
+ }
203
+
204
+ function getElementTypeNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion) {
205
+ const { data } = report;
206
+
207
+ const {
208
+ allowedVersion,
209
+ node
210
+ } = data;
211
+
212
+ const typeString = getTypeString(node);
213
+
214
+ return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }>`, executionPlatform, executionPlatformVersion, allowedVersion);
215
+ }
216
+
217
+ function getPropertyValueDuplicatedErrorMessage(report) {
218
+ const {
219
+ data,
220
+ message
221
+ } = report;
222
+
223
+ const {
224
+ node,
225
+ parentNode,
226
+ duplicatedPropertyValue,
227
+ properties
228
+ } = data;
229
+
230
+ const typeString = getTypeString(parentNode || node);
231
+
232
+ if (is(node, 'zeebe:TaskHeaders') && every(properties, property => is(property, 'zeebe:Header'))) {
233
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with two or more <Headers> with the same <Key> (${ duplicatedPropertyValue }) is not supported`;
234
+ }
235
+
236
+ return message;
237
+ }
238
+
239
+ function getPropertyValuesDuplicatedErrorMessage(report) {
240
+ const {
241
+ data,
242
+ message
243
+ } = report;
244
+
245
+ const {
246
+ node,
247
+ parentNode,
248
+ duplicatedProperties,
249
+ properties
250
+ } = data;
251
+
252
+ const {
253
+ eventType,
254
+ type
255
+ } = duplicatedProperties;
256
+
257
+ const typeString = getTypeString(parentNode || node);
258
+
259
+ if (is(node, 'zeebe:ExecutionListeners') && every(properties, property => is(property, 'zeebe:ExecutionListener'))) {
260
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with two or more <Execution Listeners> with the same <Event Type> (${ eventType }) and <Type> (${ type }) is not supported`;
261
+ }
262
+
263
+ return message;
264
+ }
265
+
266
+ function getPropertyValueRequiredErrorMessage(report, executionPlatform, executionPlatformVersion) {
267
+ const {
268
+ data,
269
+ message
270
+ } = report;
271
+
272
+ const {
273
+ allowedVersion,
274
+ node,
275
+ property,
276
+ parentNode
277
+ } = data;
278
+
279
+ if (is(node, 'bpmn:Process') && property === 'isExecutable') {
280
+ if (parentNode && is(parentNode, 'bpmn:Participant')) {
281
+ return 'One <Process> must be <Executable>';
282
+ } else {
283
+ return 'A <Process> must be <Executable>';
284
+ }
285
+ }
286
+
287
+ const typeString = getTypeString(parentNode || node);
288
+
289
+ if (is(node, 'bpmn:CompensateEventDefinition') && property === 'waitForCompletion') {
290
+ return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Wait for completion> disabled`, executionPlatform, executionPlatformVersion, allowedVersion);
291
+ }
292
+
293
+ return message;
294
+ }
295
+
296
+ function getExtensionElementNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion) {
297
+ const {
298
+ data,
299
+ message
300
+ } = report;
301
+
302
+ const {
303
+ allowedVersion,
304
+ node,
305
+ parentNode,
306
+ extensionElement
307
+ } = data;
308
+
309
+ const typeString = getTypeString(parentNode || node);
310
+
311
+ if (is(node, 'bpmn:BusinessRuleTask') && is(extensionElement, 'zeebe:CalledDecision')) {
312
+ return getSupportedMessage('A <Business Rule Task> with <Implementation: DMN decision>', executionPlatform, executionPlatformVersion, allowedVersion);
313
+ }
314
+
315
+ if (is(extensionElement, 'zeebe:Properties')) {
316
+ return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Extension properties>`, executionPlatform, executionPlatformVersion, allowedVersion);
317
+ }
318
+
319
+ if (is(extensionElement, 'zeebe:UserTask')) {
320
+ return getSupportedMessage('A <User Task> with <Implementation: Camunda user task>', executionPlatform, executionPlatformVersion, allowedVersion);
321
+ }
322
+
323
+ if (is(node, 'bpmn:ScriptTask') && is(extensionElement, 'zeebe:Script')) {
324
+ return getSupportedMessage('A <Script Task> with <Implementation: FEEL expression>', executionPlatform, executionPlatformVersion, allowedVersion);
325
+ }
326
+
327
+ if (is(node, 'bpmn:UserTask') && is(extensionElement, 'zeebe:TaskSchedule')) {
328
+ return getSupportedMessage('A <User Task> with <Due date> or <Follow up date>', executionPlatform, executionPlatformVersion, allowedVersion);
329
+ }
330
+
331
+ if (is(node, 'bpmn:UserTask') && is(extensionElement, 'zeebe:PriorityDefinition')) {
332
+ return getSupportedMessage('A <User Task> with <Priority>', executionPlatform, executionPlatformVersion, allowedVersion);
333
+ }
334
+
335
+ if (is(node, 'bpmn:StartEvent') && is(extensionElement, 'zeebe:FormDefinition')) {
336
+ return getSupportedMessage('A <Start Event> with <User Task Form>', executionPlatform, executionPlatformVersion, allowedVersion);
337
+ }
338
+
339
+ if (is(extensionElement, 'zeebe:ExecutionListeners')) {
340
+ return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Execution listeners>`, executionPlatform, executionPlatformVersion, allowedVersion);
341
+ }
342
+
343
+ if (is(extensionElement, 'zeebe:TaskListeners')) {
344
+ return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Task listeners>`, executionPlatform, executionPlatformVersion, allowedVersion);
345
+ }
346
+
347
+ if (is(node, 'bpmn:Process') && is(extensionElement, 'zeebe:VersionTag')) {
348
+ return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Version tag>`, executionPlatform, executionPlatformVersion, allowedVersion);
349
+ }
350
+
351
+ return message;
352
+ }
353
+
354
+ function getExtensionElementRequiredErrorMessage(report, executionPlatform, executionPlatformVersion) {
355
+ const {
356
+ data,
357
+ message
358
+ } = report;
359
+
360
+ const {
361
+ node,
362
+ parentNode,
363
+ requiredExtensionElement
364
+ } = data;
365
+
366
+ const typeString = getTypeString(parentNode || node);
367
+
368
+ if (requiredExtensionElement === 'zeebe:CalledElement') {
369
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Called element>`;
370
+ }
371
+
372
+ if (requiredExtensionElement === 'zeebe:LoopCharacteristics') {
373
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Multi-instance marker> must have a defined <Input collection>`;
374
+ }
375
+
376
+ if (requiredExtensionElement === 'zeebe:Subscription') {
377
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Message Reference> must have a defined <Subscription correlation key>`;
378
+ }
379
+
380
+ if (requiredExtensionElement === 'zeebe:TaskDefinition') {
381
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a <Task definition type>`;
382
+ }
383
+
384
+ if (isArray(requiredExtensionElement) && requiredExtensionElement.includes('zeebe:CalledDecision')) {
385
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Implementation>`;
386
+ }
387
+
388
+ if (isArray(requiredExtensionElement) && requiredExtensionElement.includes('zeebe:Script')) {
389
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Implementation>`;
390
+ }
391
+
392
+ if (requiredExtensionElement === 'zeebe:FormDefinition') {
393
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> should have a defined <Form>`;
394
+ }
395
+
396
+ if (requiredExtensionElement === 'zeebe:UserTask') {
397
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Implementation: Job worker> managed by Camunda is deprecated. Consider migrating to <Implementation: Camunda user task>.`;
398
+ }
399
+
400
+ return message;
401
+ }
402
+
403
+ function getPropertyDependentRequiredErrorMessage(report) {
404
+ const {
405
+ data,
406
+ message
407
+ } = report;
408
+
409
+ const {
410
+ node,
411
+ parentNode,
412
+ property,
413
+ dependentRequiredProperty
414
+ } = data;
415
+
416
+ const typeString = getTypeString(parentNode || node);
417
+
418
+ if (is(node, 'zeebe:LoopCharacteristics') && property === 'outputCollection' && dependentRequiredProperty === 'outputElement') {
419
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Multi-instance marker> and defined <Output collection> must have a defined <Output element>`;
420
+ }
421
+
422
+ if (is(node, 'zeebe:LoopCharacteristics') && property === 'outputElement' && dependentRequiredProperty === 'outputCollection') {
423
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Multi-instance marker> and defined <Output element> must have a defined <Output collection>`;
424
+ }
425
+
426
+ return message;
427
+ }
428
+
429
+ function getPropertyNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion, modeler = 'desktop') {
430
+ const {
431
+ data,
432
+ message
433
+ } = report;
434
+
435
+ const {
436
+ allowedVersion,
437
+ node,
438
+ parentNode,
439
+ property
440
+ } = data;
441
+
442
+ const typeString = getTypeString(parentNode || node);
443
+
444
+ if (property === 'modelerTemplate') {
445
+ if (modeler === 'desktop') {
446
+ return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <Template ${ typeString }>`, executionPlatform, executionPlatformVersion, allowedVersion);
447
+ } else if (modeler === 'web') {
448
+ return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <Connector ${ typeString }>`, executionPlatform, executionPlatformVersion, allowedVersion);
449
+ }
450
+ }
451
+
452
+ if (is(node, 'bpmn:InclusiveGateway') && property === 'incoming') {
453
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with more than one incoming <Sequence Flow> is not supported by ${ getExecutionPlatformLabel(executionPlatform, executionPlatformVersion) }`;
454
+ }
455
+
456
+ if (is(node, 'zeebe:AssignmentDefinition') && property === 'candidateUsers') {
457
+ return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Candidate users>`, executionPlatform, executionPlatformVersion, allowedVersion);
458
+ }
459
+
460
+ if (is(node, 'bpmn:SequenceFlow') && property === 'conditionExpression') {
461
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Condition expression> is only supported if the source is an <Exclusive Gateway> or <Inclusive Gateway>`;
462
+ }
463
+
464
+ if (is(node, 'bpmn:TimerEventDefinition') && TIMER_PROPERTIES.includes(property)) {
465
+ return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <${ TIMER_PROPERTY_LABELS[ property ] }>`, executionPlatform, executionPlatformVersion, allowedVersion);
466
+ }
467
+
468
+ if (is(node, 'zeebe:FormDefinition') && property === 'formId') {
469
+ return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Form type: Camunda form (linked)>`, executionPlatform, executionPlatformVersion, allowedVersion);
470
+ }
471
+
472
+ return message;
473
+ }
474
+
475
+
476
+ function getPropertyRequiredErrorMessage(report, executionPlatform, executionPlatformVersion) {
477
+ const {
478
+ data,
479
+ message
480
+ } = report;
481
+
482
+ const {
483
+ allowedVersion,
484
+ node,
485
+ parentNode,
486
+ requiredProperty
487
+ } = data;
488
+
489
+ function isRequiredProperty(requiredPropertyToLookUp) {
490
+ return requiredProperty === requiredPropertyToLookUp || (isArray(requiredProperty) && requiredProperty.includes(requiredPropertyToLookUp));
491
+ }
492
+
493
+ const typeString = getTypeString(parentNode || node);
494
+
495
+ if (parentNode && is(parentNode, 'bpmn:BusinessRuleTask') && is(node, 'zeebe:CalledDecision') && requiredProperty === 'decisionId') {
496
+ return 'A <Business Rule Task> with <Implementation: DMN decision> must have a defined <Called decision ID>';
497
+ }
498
+
499
+ if (parentNode && is(parentNode, 'bpmn:BusinessRuleTask') && is(node, 'zeebe:CalledDecision') && requiredProperty === 'resultVariable') {
500
+ return 'A <Business Rule Task> with <Implementation: DMN decision> must have a defined <Result variable>';
501
+ }
502
+
503
+ if (parentNode && is(parentNode, 'bpmn:ScriptTask') && is(node, 'zeebe:Script') && requiredProperty === 'expression') {
504
+ return 'A <Script Task> with <Implementation: FEEL expression> must have a defined <FEEL expression>';
505
+ }
506
+
507
+ if (parentNode && is(parentNode, 'bpmn:ScriptTask') && is(node, 'zeebe:Script') && requiredProperty === 'resultVariable') {
508
+ return 'A <Script Task> with <Implementation: FEEL expression> must have a defined <Result variable>';
509
+ }
510
+
511
+ if (parentNode && isAny(parentNode, [ 'bpmn:BusinessRuleTask', 'bpmn:ScriptTask' ]) && is(node, 'zeebe:TaskDefinition') && requiredProperty === 'type') {
512
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Implementation: Job worker> must have a defined <Task definition type>`;
513
+ }
514
+
515
+ if (is(node, 'zeebe:CalledElement') && requiredProperty === 'processId') {
516
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Called element>`;
517
+ }
518
+
519
+ if (is(node, 'bpmn:Error') && requiredProperty === 'errorCode') {
520
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Error Reference> must have a defined <Error code>`;
521
+ }
522
+
523
+ if (is(node, 'bpmn:Escalation') && requiredProperty === 'escalationCode') {
524
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Escalation Reference> must have a defined <Escalation code>`;
525
+ }
526
+
527
+ if (is(node, 'zeebe:LoopCharacteristics') && requiredProperty === 'inputCollection') {
528
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Multi-instance marker> must have a defined <Input collection>`;
529
+ }
530
+
531
+ if (is(node, 'bpmn:Message') && requiredProperty === 'name') {
532
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Message Reference> must have a defined <Name>`;
533
+ }
534
+
535
+ if (is(node, 'bpmn:Signal') && requiredProperty === 'name') {
536
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Signal Reference> must have a defined <Name>`;
537
+ }
538
+
539
+ if (is(node, 'zeebe:Subscription') && requiredProperty === 'correlationKey') {
540
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Message Reference> must have a defined <Subscription correlation key>`;
541
+ }
542
+
543
+ if (is(node, 'zeebe:TaskDefinition') && requiredProperty === 'type') {
544
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Implementation: Job worker> must have a defined <Task definition type>`;
545
+ }
546
+
547
+ if (is(node, 'zeebe:ExecutionListener') && requiredProperty === 'type') {
548
+ return 'An <Execution Listener> must have a defined <Type>';
549
+ }
550
+
551
+ if (is(node, 'zeebe:TaskListener') && requiredProperty === 'type') {
552
+ return 'A <Task Listener> must have a defined <Type>';
553
+ }
554
+
555
+ if (requiredProperty === 'errorRef') {
556
+
557
+ if (parentNode && is(parentNode, 'bpmn:CatchEvent')) {
558
+ return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> without defined <Error Reference>`, executionPlatform, executionPlatformVersion, allowedVersion);
559
+ } else if (parentNode && is(parentNode, 'bpmn:ThrowEvent')) {
560
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Error Reference>`;
561
+ }
562
+
563
+ }
564
+
565
+ if (requiredProperty === 'messageRef') {
566
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Message Reference>`;
567
+ }
568
+
569
+ if (requiredProperty === 'signalRef') {
570
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Signal Reference>`;
571
+ }
572
+
573
+ if (is(node, 'zeebe:FormDefinition')
574
+ && (
575
+ requiredProperty === 'formKey'
576
+ || (isArray(requiredProperty) && requiredProperty.includes('formKey') && isEmptyString(node.get('formKey')))
577
+ )) {
578
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Form type: Custom form key> must have a defined <Form key>`;
579
+ }
580
+
581
+ // Camunda User Task
582
+ if (is(node, 'zeebe:FormDefinition') && isZeebeUserTask(parentNode)) {
583
+ if (isRequiredProperty('externalReference') && isEmptyString(node.get('externalReference'))) {
584
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Form type: External reference> must have a defined <External reference>`;
585
+ } else if (isRequiredProperty('formId') && isEmptyString(node.get('formId'))) {
586
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Form type: Camunda Form> must have a defined <Form ID>`;
587
+ }
588
+ }
589
+
590
+ if (is(node, 'zeebe:FormDefinition') && isRequiredProperty('formId') && isEmptyString(node.get('formId'))) {
591
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Form type: Camunda form (linked)> must have a defined <Form ID>`;
592
+ }
593
+
594
+ if (is(node, 'zeebe:UserTaskForm') && requiredProperty === 'body') {
595
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Form type: Camunda form (embedded)> must have a defined <Form JSON configuration>`;
596
+ }
597
+
598
+ if (is(node, 'bpmn:SequenceFlow') && requiredProperty === 'conditionExpression') {
599
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Condition expression> or be the default <Sequence Flow>`;
600
+ }
601
+
602
+ if (is(node, 'bpmn:TimerEventDefinition')
603
+ && isArray(requiredProperty)
604
+ && TIMER_PROPERTIES.some(property => requiredProperty.includes(property))
605
+ ) {
606
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Timer type>`;
607
+ }
608
+
609
+ if (is(node, 'bpmn:Process') && requiredProperty === 'historyTimeToLive') {
610
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <History time to live>`;
611
+ }
612
+
613
+ if (is(node, 'bpmn:LinkEventDefinition') && requiredProperty === 'name') {
614
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Name>`;
615
+ }
616
+
617
+ if (isAny(node, [
618
+ 'zeebe:CalledDecision',
619
+ 'zeebe:CalledElement',
620
+ 'zeebe:FormDefinition'
621
+ ]) && requiredProperty === 'versionTag') {
622
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Binding: version tag> must have a defined <Version tag>`;
623
+ }
624
+
625
+ return message;
626
+ }
627
+
628
+ function getExpressionRequiredErrorMessage(report) {
629
+ const {
630
+ data,
631
+ message
632
+ } = report;
633
+
634
+ const {
635
+ node,
636
+ parentNode,
637
+ property
638
+ } = data;
639
+
640
+ const typeString = getTypeString(parentNode || node);
641
+
642
+ if (is(node, 'bpmn:FormalExpression') && TIMER_PROPERTIES.includes(property)) {
643
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Timer value>`;
644
+ }
645
+
646
+ return message;
647
+ }
648
+
649
+ function getExpressionValueNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion) {
650
+ const {
651
+ data,
652
+ message
653
+ } = report;
654
+
655
+ const {
656
+ node,
657
+ parentNode,
658
+ property
659
+ } = data;
660
+
661
+ const typeString = getTypeString(parentNode || node);
662
+
663
+ if (is(node, 'bpmn:FormalExpression') && property === 'timeCycle') {
664
+ if (!greaterOrEqual(executionPlatformVersion, '8.1')) {
665
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> <Time cycle> must be an expression, an ISO 8601 repeating interval, or a cron expression (cron only supported by Camunda 8.1 or newer)`;
666
+ } else {
667
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> <Time cycle> must be an expression, an ISO 8601 repeating interval, or a cron expression`;
668
+ }
669
+ }
670
+
671
+ if (is(node, 'bpmn:FormalExpression') && property === 'timeDate') {
672
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> <Time date> must be an expression, or an ISO 8601 date`;
673
+ }
674
+
675
+ if (is(node, 'bpmn:FormalExpression') && property === 'timeDuration') {
676
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> <Time duration> must be an expression, or an ISO 8601 interval`;
677
+ }
678
+
679
+ if (is(node, 'zeebe:TaskSchedule') && property === 'dueDate') {
680
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> <Due date> must be an ISO 8601 date`;
681
+ }
682
+
683
+ if (is(node, 'zeebe:TaskSchedule') && property === 'followUpDate') {
684
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> <Follow up date> must be an ISO 8601 date`;
685
+ }
686
+
687
+ if (is(node, 'zeebe:PriorityDefinition') && property === 'priority') {
688
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> <Priority> must be an expression, or an integer between 0 and 100`;
689
+ }
690
+
691
+ return message;
692
+ }
693
+
694
+ function getSupportedMessage(prefix, executionPlatform, executionPlatformVersion, allowedVersion) {
695
+ if (allowedVersion) {
696
+ return `${ prefix } is only supported by ${ getExecutionPlatformLabel(executionPlatform, allowedVersion) } or newer`;
697
+ }
698
+
699
+ return `${ prefix } is not supported by ${ getExecutionPlatformLabel(executionPlatform, executionPlatformVersion) }`;
700
+ }
701
+
702
+ function getExpressionNotAllowedErrorMessage(report) {
703
+ const {
704
+ data
705
+ } = report;
706
+
707
+ const {
708
+ node,
709
+ parentNode,
710
+ property
711
+ } = data;
712
+
713
+ if (is(node, 'bpmn:Escalation') && property === 'escalationCode' && is(parentNode, 'bpmn:CatchEvent')) {
714
+ return 'Escalation code used in a catch event must be a static value';
715
+ } else if (is(node, 'bpmn:Error') && property === 'errorCode' && is(parentNode, 'bpmn:CatchEvent')) {
716
+ return 'Error code used in a catch event must be a static value';
717
+ }
718
+
719
+ return report.message;
720
+ }
721
+
722
+ function getEventBasedGatewayTargetNotAllowedErrorMessage(report) {
723
+ const { data } = report;
724
+
725
+ const { node } = data;
726
+
727
+ if (is(node, 'bpmn:ReceiveTask')) {
728
+ return 'A <Receive Task> cannot be the target of an <Event-Based Gateway>';
729
+ }
730
+
731
+ return report.message;
732
+ }
733
+
734
+ function getPropertyValueNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion, modeler = 'desktop') {
735
+ const {
736
+ data,
737
+ message
738
+ } = report;
739
+
740
+ const {
741
+ allowedVersion,
742
+ node,
743
+ parentNode,
744
+ property
745
+ } = data;
746
+
747
+ const typeString = getTypeString(parentNode || node);
748
+
749
+ if (is(node, 'zeebe:CalledElement') && property === 'propagateAllParentVariables') {
750
+ return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Propagate all variables> disabled`, executionPlatform, executionPlatformVersion, allowedVersion);
751
+ }
752
+
753
+ if (isAny(node, [
754
+ 'zeebe:CalledDecision',
755
+ 'zeebe:CalledElement',
756
+ 'zeebe:FormDefinition'
757
+ ]) && property === 'bindingType') {
758
+ const bindingType = node.get('bindingType');
759
+
760
+ let bindingTypeString = bindingType;
761
+
762
+ if (bindingType === 'versionTag') {
763
+ bindingTypeString = 'version tag';
764
+ }
765
+
766
+ return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Binding: ${ bindingTypeString }>`, executionPlatform, executionPlatformVersion, allowedVersion);
767
+ }
768
+
769
+ return message;
770
+ }
771
+
772
+ function getSecretExpressionFormatDeprecatedErrorMessage(report) {
773
+ const { data } = report;
774
+
775
+ const { property } = data;
776
+
777
+ return `Property <${ property }> uses deprecated secret expression format secrets.SECRET, use {{secrets.SECRET}} instead`;
778
+ }
779
+
780
+ function getElementPropertyValueDuplicatedErrorMessage(report) {
781
+ const {
782
+ data,
783
+ message
784
+ } = report;
785
+
786
+ const {
787
+ node,
788
+ parentNode,
789
+ duplicatedProperty
790
+ } = data;
791
+
792
+ const typeString = getTypeString(parentNode || node);
793
+
794
+ if (is(node, 'bpmn:LinkEventDefinition') && duplicatedProperty === 'name') {
795
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a unique <Name>`;
796
+ }
797
+
798
+ return message;
799
+ }
800
+
801
+ function getLoopNotAllowedErrorMessage(report) {
802
+ const { data } = report;
803
+
804
+ const { elements } = data;
805
+
806
+ return `A <Process> is not allowed to contain a straight-through processing loop: ${ elements.map(element => `<${ element }>`).join(', ') }`;
807
+ }
808
+
809
+ function getAttachedToRefElementTypeNotAllowed(report) {
810
+ const { data } = report;
811
+
812
+ const { node , attachedToRef } = data;
813
+
814
+ const nodeTypeString = getTypeString(node);
815
+ const attachedToTypeString = getTypeString(attachedToRef);
816
+
817
+ return `${ getIndefiniteArticle(nodeTypeString) } <${nodeTypeString}> is not allowed on ${ getIndefiniteArticle(attachedToTypeString, false) } <${attachedToTypeString}>`;
818
+ }
819
+
820
+ function isEmptyString(value) {
821
+ return isString(value) && value.trim() === '';
822
+ }
823
+
824
+ function isZeebeUserTask(node) {
825
+ return node.get('extensionElements').get('values').some(extensionElement => {
826
+ return is(extensionElement, 'zeebe:UserTask');
827
+ });
828
+ }