@camunda/linting 3.25.0 → 3.26.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,777 +1,797 @@
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);
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
- return message;
161
- }
162
-
163
- function getChildElementTypeNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion) {
164
- const { data } = report;
165
-
166
- const {
167
- allowedVersion,
168
- node,
169
- parent
170
- } = data;
171
-
172
- const typeString = getTypeString(node),
173
- parentTypeString = getTypeString(parent);
174
-
175
- return getSupportedMessage(
176
- `${ getIndefiniteArticle(typeString) } <${ typeString }> in ${ getIndefiniteArticle(parentTypeString, false) } <${ parentTypeString }>`,
177
- executionPlatform,
178
- executionPlatformVersion,
179
- allowedVersion
180
- );
181
- }
182
-
183
- function getElementCollapsedNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion) {
184
- const {
185
- data,
186
- message
187
- } = report;
188
-
189
- const { allowedVersion, node } = data;
190
-
191
- const typeString = getTypeString(node);
192
-
193
- if (is(node, 'bpmn:SubProcess')) {
194
- return getSupportedMessage(`A collapsed <${typeString}>`, executionPlatform, executionPlatformVersion, allowedVersion);
195
- }
196
-
197
- return message;
198
- }
199
-
200
- function getElementTypeNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion) {
201
- const { data } = report;
202
-
203
- const {
204
- allowedVersion,
205
- node
206
- } = data;
207
-
208
- const typeString = getTypeString(node);
209
-
210
- return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }>`, executionPlatform, executionPlatformVersion, allowedVersion);
211
- }
212
-
213
- function getPropertyValueDuplicatedErrorMessage(report) {
214
- const {
215
- data,
216
- message
217
- } = report;
218
-
219
- const {
220
- node,
221
- parentNode,
222
- duplicatedPropertyValue,
223
- properties
224
- } = data;
225
-
226
- const typeString = getTypeString(parentNode || node);
227
-
228
- if (is(node, 'zeebe:TaskHeaders') && every(properties, property => is(property, 'zeebe:Header'))) {
229
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with two or more <Headers> with the same <Key> (${ duplicatedPropertyValue }) is not supported`;
230
- }
231
-
232
- return message;
233
- }
234
-
235
- function getPropertyValuesDuplicatedErrorMessage(report) {
236
- const {
237
- data,
238
- message
239
- } = report;
240
-
241
- const {
242
- node,
243
- parentNode,
244
- duplicatedProperties,
245
- properties
246
- } = data;
247
-
248
- const {
249
- eventType,
250
- type
251
- } = duplicatedProperties;
252
-
253
- const typeString = getTypeString(parentNode || node);
254
-
255
- if (is(node, 'zeebe:ExecutionListeners') && every(properties, property => is(property, 'zeebe:ExecutionListener'))) {
256
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with two or more <Execution Listeners> with the same <Event Type> (${ eventType }) and <Type> (${ type }) is not supported`;
257
- }
258
-
259
- return message;
260
- }
261
-
262
- function getPropertyValueRequiredErrorMessage(report, executionPlatform, executionPlatformVersion) {
263
- const {
264
- data,
265
- message
266
- } = report;
267
-
268
- const {
269
- allowedVersion,
270
- node,
271
- property,
272
- parentNode
273
- } = data;
274
-
275
- if (is(node, 'bpmn:Process') && property === 'isExecutable') {
276
- if (parentNode && is(parentNode, 'bpmn:Participant')) {
277
- return 'One <Process> must be <Executable>';
278
- } else {
279
- return 'A <Process> must be <Executable>';
280
- }
281
- }
282
-
283
- const typeString = getTypeString(parentNode || node);
284
-
285
- if (is(node, 'bpmn:CompensateEventDefinition') && property === 'waitForCompletion') {
286
- return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Wait for completion> disabled`, executionPlatform, executionPlatformVersion, allowedVersion);
287
- }
288
-
289
- return message;
290
- }
291
-
292
- function getExtensionElementNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion) {
293
- const {
294
- data,
295
- message
296
- } = report;
297
-
298
- const {
299
- allowedVersion,
300
- node,
301
- parentNode,
302
- extensionElement
303
- } = data;
304
-
305
- const typeString = getTypeString(parentNode || node);
306
-
307
- if (is(node, 'bpmn:BusinessRuleTask') && is(extensionElement, 'zeebe:CalledDecision')) {
308
- return getSupportedMessage('A <Business Rule Task> with <Implementation: DMN decision>', executionPlatform, executionPlatformVersion, allowedVersion);
309
- }
310
-
311
- if (is(extensionElement, 'zeebe:Properties')) {
312
- return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Extension properties>`, executionPlatform, executionPlatformVersion, allowedVersion);
313
- }
314
-
315
- if (is(extensionElement, 'zeebe:UserTask')) {
316
- return getSupportedMessage('A <User Task> with <Implementation: Zeebe user task>', executionPlatform, executionPlatformVersion, allowedVersion);
317
- }
318
-
319
- if (is(node, 'bpmn:ScriptTask') && is(extensionElement, 'zeebe:Script')) {
320
- return getSupportedMessage('A <Script Task> with <Implementation: FEEL expression>', executionPlatform, executionPlatformVersion, allowedVersion);
321
- }
322
-
323
- if (is(node, 'bpmn:UserTask') && is(extensionElement, 'zeebe:TaskSchedule')) {
324
- return getSupportedMessage('A <User Task> with <Due date> or <Follow up date>', executionPlatform, executionPlatformVersion, allowedVersion);
325
- }
326
-
327
- if (is(node, 'bpmn:UserTask') && is(extensionElement, 'zeebe:PriorityDefinition')) {
328
- return getSupportedMessage('A <User Task> with <Priority>', executionPlatform, executionPlatformVersion, allowedVersion);
329
- }
330
-
331
- if (is(node, 'bpmn:StartEvent') && is(extensionElement, 'zeebe:FormDefinition')) {
332
- return getSupportedMessage('A <Start Event> with <User Task Form>', executionPlatform, executionPlatformVersion, allowedVersion);
333
- }
334
-
335
- if (is(extensionElement, 'zeebe:ExecutionListeners')) {
336
- return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Execution listeners>`, executionPlatform, executionPlatformVersion, allowedVersion);
337
- }
338
-
339
- return message;
340
- }
341
-
342
- function getExtensionElementRequiredErrorMessage(report) {
343
- const {
344
- data,
345
- message
346
- } = report;
347
-
348
- const {
349
- node,
350
- parentNode,
351
- requiredExtensionElement
352
- } = data;
353
-
354
- const typeString = getTypeString(parentNode || node);
355
-
356
- if (requiredExtensionElement === 'zeebe:CalledElement') {
357
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Called element>`;
358
- }
359
-
360
- if (requiredExtensionElement === 'zeebe:LoopCharacteristics') {
361
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Multi-instance marker> must have a defined <Input collection>`;
362
- }
363
-
364
- if (requiredExtensionElement === 'zeebe:Subscription') {
365
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Message Reference> must have a defined <Subscription correlation key>`;
366
- }
367
-
368
- if (requiredExtensionElement === 'zeebe:TaskDefinition') {
369
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a <Task definition type>`;
370
- }
371
-
372
- if (isArray(requiredExtensionElement) && requiredExtensionElement.includes('zeebe:CalledDecision')) {
373
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Implementation>`;
374
- }
375
-
376
- if (isArray(requiredExtensionElement) && requiredExtensionElement.includes('zeebe:Script')) {
377
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Implementation>`;
378
- }
379
-
380
- if (requiredExtensionElement === 'zeebe:FormDefinition') {
381
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> should have a defined <Form>`;
382
- }
383
-
384
- return message;
385
- }
386
-
387
- function getPropertyDependentRequiredErrorMessage(report) {
388
- const {
389
- data,
390
- message
391
- } = report;
392
-
393
- const {
394
- node,
395
- parentNode,
396
- property,
397
- dependentRequiredProperty
398
- } = data;
399
-
400
- const typeString = getTypeString(parentNode || node);
401
-
402
- if (is(node, 'zeebe:LoopCharacteristics') && property === 'outputCollection' && dependentRequiredProperty === 'outputElement') {
403
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Multi-instance marker> and defined <Output collection> must have a defined <Output element>`;
404
- }
405
-
406
- if (is(node, 'zeebe:LoopCharacteristics') && property === 'outputElement' && dependentRequiredProperty === 'outputCollection') {
407
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Multi-instance marker> and defined <Output element> must have a defined <Output collection>`;
408
- }
409
-
410
- return message;
411
- }
412
-
413
- function getPropertyNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion, modeler = 'desktop') {
414
- const {
415
- data,
416
- message
417
- } = report;
418
-
419
- const {
420
- allowedVersion,
421
- node,
422
- parentNode,
423
- property
424
- } = data;
425
-
426
- const typeString = getTypeString(parentNode || node);
427
-
428
- if (property === 'modelerTemplate') {
429
- if (modeler === 'desktop') {
430
- return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <Template ${ typeString }>`, executionPlatform, executionPlatformVersion, allowedVersion);
431
- } else if (modeler === 'web') {
432
- return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <Connector ${ typeString }>`, executionPlatform, executionPlatformVersion, allowedVersion);
433
- }
434
- }
435
-
436
- if (is(node, 'bpmn:InclusiveGateway') && property === 'incoming') {
437
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with more than one incoming <Sequence Flow> is not supported by ${ getExecutionPlatformLabel(executionPlatform, executionPlatformVersion) }`;
438
- }
439
-
440
- if (is(node, 'zeebe:AssignmentDefinition') && property === 'candidateUsers') {
441
- return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with defined <Candidate users>`, executionPlatform, executionPlatformVersion, allowedVersion);
442
- }
443
-
444
- if (is(node, 'bpmn:SequenceFlow') && property === 'conditionExpression') {
445
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Condition expression> is only supported if the source is an <Exclusive Gateway> or <Inclusive Gateway>`;
446
- }
447
-
448
- if (is(node, 'bpmn:TimerEventDefinition') && TIMER_PROPERTIES.includes(property)) {
449
- return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <${ TIMER_PROPERTY_LABELS[ property ] }>`, executionPlatform, executionPlatformVersion, allowedVersion);
450
- }
451
-
452
- if (is(node, 'zeebe:FormDefinition') && property === 'formId') {
453
- return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Form type: Camunda form (linked)>`, executionPlatform, executionPlatformVersion, allowedVersion);
454
- }
455
-
456
- return message;
457
- }
458
-
459
-
460
- function getPropertyRequiredErrorMessage(report, executionPlatform, executionPlatformVersion) {
461
- const {
462
- data,
463
- message
464
- } = report;
465
-
466
- const {
467
- allowedVersion,
468
- node,
469
- parentNode,
470
- requiredProperty
471
- } = data;
472
-
473
- const typeString = getTypeString(parentNode || node);
474
-
475
- if (parentNode && is(parentNode, 'bpmn:BusinessRuleTask') && is(node, 'zeebe:CalledDecision') && requiredProperty === 'decisionId') {
476
- return 'A <Business Rule Task> with <Implementation: DMN decision> must have a defined <Called decision ID>';
477
- }
478
-
479
- if (parentNode && is(parentNode, 'bpmn:BusinessRuleTask') && is(node, 'zeebe:CalledDecision') && requiredProperty === 'resultVariable') {
480
- return 'A <Business Rule Task> with <Implementation: DMN decision> must have a defined <Result variable>';
481
- }
482
-
483
- if (parentNode && is(parentNode, 'bpmn:ScriptTask') && is(node, 'zeebe:Script') && requiredProperty === 'expression') {
484
- return 'A <Script Task> with <Implementation: FEEL expression> must have a defined <FEEL expression>';
485
- }
486
-
487
- if (parentNode && is(parentNode, 'bpmn:ScriptTask') && is(node, 'zeebe:Script') && requiredProperty === 'resultVariable') {
488
- return 'A <Script Task> with <Implementation: FEEL expression> must have a defined <Result variable>';
489
- }
490
-
491
- if (parentNode && isAny(parentNode, [ 'bpmn:BusinessRuleTask', 'bpmn:ScriptTask' ]) && is(node, 'zeebe:TaskDefinition') && requiredProperty === 'type') {
492
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Implementation: Job worker> must have a defined <Task definition type>`;
493
- }
494
-
495
- if (is(node, 'zeebe:CalledElement') && requiredProperty === 'processId') {
496
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Called element>`;
497
- }
498
-
499
- if (is(node, 'bpmn:Error') && requiredProperty === 'errorCode') {
500
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Error Reference> must have a defined <Error code>`;
501
- }
502
-
503
- if (is(node, 'bpmn:Escalation') && requiredProperty === 'escalationCode') {
504
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Escalation Reference> must have a defined <Escalation code>`;
505
- }
506
-
507
- if (is(node, 'zeebe:LoopCharacteristics') && requiredProperty === 'inputCollection') {
508
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Multi-instance marker> must have a defined <Input collection>`;
509
- }
510
-
511
- if (is(node, 'bpmn:Message') && requiredProperty === 'name') {
512
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Message Reference> must have a defined <Name>`;
513
- }
514
-
515
- if (is(node, 'bpmn:Signal') && requiredProperty === 'name') {
516
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Signal Reference> must have a defined <Name>`;
517
- }
518
-
519
- if (is(node, 'zeebe:Subscription') && requiredProperty === 'correlationKey') {
520
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Message Reference> must have a defined <Subscription correlation key>`;
521
- }
522
-
523
- if (is(node, 'zeebe:TaskDefinition') && requiredProperty === 'type') {
524
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Implementation: Job worker> must have a defined <Task definition type>`;
525
- }
526
-
527
- if (is(node, 'zeebe:ExecutionListener') && requiredProperty === 'type') {
528
- return 'An <Execution Listener> must have a defined <Type>';
529
- }
530
-
531
- if (requiredProperty === 'errorRef') {
532
-
533
- if (parentNode && is(parentNode, 'bpmn:CatchEvent')) {
534
- return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> without defined <Error Reference>`, executionPlatform, executionPlatformVersion, allowedVersion);
535
- } else if (parentNode && is(parentNode, 'bpmn:ThrowEvent')) {
536
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Error Reference>`;
537
- }
538
-
539
- }
540
-
541
- if (requiredProperty === 'messageRef') {
542
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Message Reference>`;
543
- }
544
-
545
- if (requiredProperty === 'signalRef') {
546
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Signal Reference>`;
547
- }
548
-
549
- if (is(node, 'zeebe:FormDefinition')
550
- && (
551
- requiredProperty === 'formKey'
552
- || (isArray(requiredProperty) && requiredProperty.includes('formKey') && isEmptyString(node.get('formKey')))
553
- )) {
554
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Form type: Custom form key> must have a defined <Form key>`;
555
- }
556
-
557
- // Zeebe User Task
558
- if (is(node, 'zeebe:FormDefinition') && isZeebeUserTask(parentNode)) {
559
- if (isEmptyString(node.get('externalReference'))) {
560
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Form type: External reference> must have a defined <External reference>`;
561
- } else if (isEmptyString(node.get('formId'))) {
562
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Form type: Camunda Form> must have a defined <Form ID>`;
563
- }
564
- }
565
-
566
- if (is(node, 'zeebe:FormDefinition') && isArray(requiredProperty) && requiredProperty.includes('formId') && isEmptyString(node.get('formId'))) {
567
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Form type: Camunda form (linked)> must have a defined <Form ID>`;
568
- }
569
-
570
- if (is(node, 'zeebe:UserTaskForm') && requiredProperty === 'body') {
571
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Form type: Camunda form (embedded)> must have a defined <Form JSON configuration>`;
572
- }
573
-
574
- if (is(node, 'bpmn:SequenceFlow') && requiredProperty === 'conditionExpression') {
575
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Condition expression> or be the default <Sequence Flow>`;
576
- }
577
-
578
- if (is(node, 'bpmn:TimerEventDefinition')
579
- && isArray(requiredProperty)
580
- && TIMER_PROPERTIES.some(property => requiredProperty.includes(property))
581
- ) {
582
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Timer type>`;
583
- }
584
-
585
- if (is(node, 'bpmn:Process') && requiredProperty === 'historyTimeToLive') {
586
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <History time to live>`;
587
- }
588
-
589
- if (is(node, 'bpmn:LinkEventDefinition') && requiredProperty === 'name') {
590
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Name>`;
591
- }
592
-
593
- return message;
594
- }
595
-
596
- function getExpressionRequiredErrorMessage(report) {
597
- const {
598
- data,
599
- message
600
- } = report;
601
-
602
- const {
603
- node,
604
- parentNode,
605
- property
606
- } = data;
607
-
608
- const typeString = getTypeString(parentNode || node);
609
-
610
- if (is(node, 'bpmn:FormalExpression') && TIMER_PROPERTIES.includes(property)) {
611
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Timer value>`;
612
- }
613
-
614
- return message;
615
- }
616
-
617
- function getExpressionValueNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion) {
618
- const {
619
- data,
620
- message
621
- } = report;
622
-
623
- const {
624
- node,
625
- parentNode,
626
- property
627
- } = data;
628
-
629
- const typeString = getTypeString(parentNode || node);
630
-
631
- if (is(node, 'bpmn:FormalExpression') && property === 'timeCycle') {
632
- if (!greaterOrEqual(executionPlatformVersion, '8.1')) {
633
- 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)`;
634
- } else {
635
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> <Time cycle> must be an expression, an ISO 8601 repeating interval, or a cron expression`;
636
- }
637
- }
638
-
639
- if (is(node, 'bpmn:FormalExpression') && property === 'timeDate') {
640
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> <Time date> must be an expression, or an ISO 8601 date`;
641
- }
642
-
643
- if (is(node, 'bpmn:FormalExpression') && property === 'timeDuration') {
644
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> <Time duration> must be an expression, or an ISO 8601 interval`;
645
- }
646
-
647
- if (is(node, 'zeebe:TaskSchedule') && property === 'dueDate') {
648
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> <Due date> must be an ISO 8601 date`;
649
- }
650
-
651
- if (is(node, 'zeebe:TaskSchedule') && property === 'followUpDate') {
652
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> <Follow up date> must be an ISO 8601 date`;
653
- }
654
-
655
- if (is(node, 'zeebe:PriorityDefinition') && property === 'priority') {
656
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> <Priority> must be an expression, or an integer between 0 and 100`;
657
- }
658
-
659
- return message;
660
- }
661
-
662
- function getSupportedMessage(prefix, executionPlatform, executionPlatformVersion, allowedVersion) {
663
- if (allowedVersion) {
664
- return `${ prefix } is only supported by ${ getExecutionPlatformLabel(executionPlatform, allowedVersion) } or newer`;
665
- }
666
-
667
- return `${ prefix } is not supported by ${ getExecutionPlatformLabel(executionPlatform, executionPlatformVersion) }`;
668
- }
669
-
670
- function getExpressionNotAllowedErrorMessage(report) {
671
- const {
672
- data
673
- } = report;
674
-
675
- const {
676
- node,
677
- parentNode,
678
- property
679
- } = data;
680
-
681
- if (is(node, 'bpmn:Escalation') && property === 'escalationCode' && is(parentNode, 'bpmn:CatchEvent')) {
682
- return 'Escalation code used in a catch event must be a static value';
683
- } else if (is(node, 'bpmn:Error') && property === 'errorCode' && is(parentNode, 'bpmn:CatchEvent')) {
684
- return 'Error code used in a catch event must be a static value';
685
- }
686
-
687
- return report.message;
688
- }
689
-
690
- function getEventBasedGatewayTargetNotAllowedErrorMessage(report) {
691
- const { data } = report;
692
-
693
- const { node } = data;
694
-
695
- if (is(node, 'bpmn:ReceiveTask')) {
696
- return 'A <Receive Task> cannot be the target of an <Event-Based Gateway>';
697
- }
698
-
699
- return report.message;
700
- }
701
-
702
- function getPropertyValueNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion, modeler = 'desktop') {
703
- const {
704
- data,
705
- message
706
- } = report;
707
-
708
- const {
709
- allowedVersion,
710
- node,
711
- parentNode,
712
- property
713
- } = data;
714
-
715
- const typeString = getTypeString(parentNode || node);
716
-
717
- if (is(node, 'zeebe:CalledElement') && property === 'propagateAllParentVariables') {
718
- return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Propagate all variables> disabled`, executionPlatform, executionPlatformVersion, allowedVersion);
719
- }
720
-
721
- if (isAny(node, [
722
- 'zeebe:CalledDecision',
723
- 'zeebe:CalledElement',
724
- 'zeebe:FormDefinition'
725
- ]) && property === 'bindingType') {
726
- return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Binding: deployment>`, executionPlatform, executionPlatformVersion, allowedVersion);
727
- }
728
-
729
- return message;
730
- }
731
-
732
- function getSecretExpressionFormatDeprecatedErrorMessage(report) {
733
- const { data } = report;
734
-
735
- const { property } = data;
736
-
737
- return `Property <${ property }> uses deprecated secret expression format secrets.SECRET, use {{secrets.SECRET}} instead`;
738
- }
739
-
740
- function getElementPropertyValueDuplicatedErrorMessage(report) {
741
- const {
742
- data,
743
- message
744
- } = report;
745
-
746
- const {
747
- node,
748
- parentNode,
749
- duplicatedProperty
750
- } = data;
751
-
752
- const typeString = getTypeString(parentNode || node);
753
-
754
- if (is(node, 'bpmn:LinkEventDefinition') && duplicatedProperty === 'name') {
755
- return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a unique <Name>`;
756
- }
757
-
758
- return message;
759
- }
760
-
761
- function getLoopNotAllowedErrorMessage(report) {
762
- const { data } = report;
763
-
764
- const { elements } = data;
765
-
766
- return `A <Process> is not allowed to contain a straight-through processing loop: ${ elements.map(element => `<${ element }>`).join(', ') }`;
767
- }
768
-
769
- function isEmptyString(value) {
770
- return isString(value) && value.trim() === '';
771
- }
772
-
773
- function isZeebeUserTask(node) {
774
- return node.get('extensionElements').get('values').some(extensionElement => {
775
- return is(extensionElement, 'zeebe:UserTask');
776
- });
777
- }
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);
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
+ return message;
161
+ }
162
+
163
+ function getChildElementTypeNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion) {
164
+ const { data } = report;
165
+
166
+ const {
167
+ allowedVersion,
168
+ node,
169
+ parent
170
+ } = data;
171
+
172
+ const typeString = getTypeString(node),
173
+ parentTypeString = getTypeString(parent);
174
+
175
+ return getSupportedMessage(
176
+ `${ getIndefiniteArticle(typeString) } <${ typeString }> in ${ getIndefiniteArticle(parentTypeString, false) } <${ parentTypeString }>`,
177
+ executionPlatform,
178
+ executionPlatformVersion,
179
+ allowedVersion
180
+ );
181
+ }
182
+
183
+ function getElementCollapsedNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion) {
184
+ const {
185
+ data,
186
+ message
187
+ } = report;
188
+
189
+ const { allowedVersion, node } = data;
190
+
191
+ const typeString = getTypeString(node);
192
+
193
+ if (is(node, 'bpmn:SubProcess')) {
194
+ return getSupportedMessage(`A collapsed <${typeString}>`, executionPlatform, executionPlatformVersion, allowedVersion);
195
+ }
196
+
197
+ return message;
198
+ }
199
+
200
+ function getElementTypeNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion) {
201
+ const { data } = report;
202
+
203
+ const {
204
+ allowedVersion,
205
+ node
206
+ } = data;
207
+
208
+ const typeString = getTypeString(node);
209
+
210
+ return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }>`, executionPlatform, executionPlatformVersion, allowedVersion);
211
+ }
212
+
213
+ function getPropertyValueDuplicatedErrorMessage(report) {
214
+ const {
215
+ data,
216
+ message
217
+ } = report;
218
+
219
+ const {
220
+ node,
221
+ parentNode,
222
+ duplicatedPropertyValue,
223
+ properties
224
+ } = data;
225
+
226
+ const typeString = getTypeString(parentNode || node);
227
+
228
+ if (is(node, 'zeebe:TaskHeaders') && every(properties, property => is(property, 'zeebe:Header'))) {
229
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with two or more <Headers> with the same <Key> (${ duplicatedPropertyValue }) is not supported`;
230
+ }
231
+
232
+ return message;
233
+ }
234
+
235
+ function getPropertyValuesDuplicatedErrorMessage(report) {
236
+ const {
237
+ data,
238
+ message
239
+ } = report;
240
+
241
+ const {
242
+ node,
243
+ parentNode,
244
+ duplicatedProperties,
245
+ properties
246
+ } = data;
247
+
248
+ const {
249
+ eventType,
250
+ type
251
+ } = duplicatedProperties;
252
+
253
+ const typeString = getTypeString(parentNode || node);
254
+
255
+ if (is(node, 'zeebe:ExecutionListeners') && every(properties, property => is(property, 'zeebe:ExecutionListener'))) {
256
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with two or more <Execution Listeners> with the same <Event Type> (${ eventType }) and <Type> (${ type }) is not supported`;
257
+ }
258
+
259
+ return message;
260
+ }
261
+
262
+ function getPropertyValueRequiredErrorMessage(report, executionPlatform, executionPlatformVersion) {
263
+ const {
264
+ data,
265
+ message
266
+ } = report;
267
+
268
+ const {
269
+ allowedVersion,
270
+ node,
271
+ property,
272
+ parentNode
273
+ } = data;
274
+
275
+ if (is(node, 'bpmn:Process') && property === 'isExecutable') {
276
+ if (parentNode && is(parentNode, 'bpmn:Participant')) {
277
+ return 'One <Process> must be <Executable>';
278
+ } else {
279
+ return 'A <Process> must be <Executable>';
280
+ }
281
+ }
282
+
283
+ const typeString = getTypeString(parentNode || node);
284
+
285
+ if (is(node, 'bpmn:CompensateEventDefinition') && property === 'waitForCompletion') {
286
+ return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Wait for completion> disabled`, executionPlatform, executionPlatformVersion, allowedVersion);
287
+ }
288
+
289
+ return message;
290
+ }
291
+
292
+ function getExtensionElementNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion) {
293
+ const {
294
+ data,
295
+ message
296
+ } = report;
297
+
298
+ const {
299
+ allowedVersion,
300
+ node,
301
+ parentNode,
302
+ extensionElement
303
+ } = data;
304
+
305
+ const typeString = getTypeString(parentNode || node);
306
+
307
+ if (is(node, 'bpmn:BusinessRuleTask') && is(extensionElement, 'zeebe:CalledDecision')) {
308
+ return getSupportedMessage('A <Business Rule Task> with <Implementation: DMN decision>', executionPlatform, executionPlatformVersion, allowedVersion);
309
+ }
310
+
311
+ if (is(extensionElement, 'zeebe:Properties')) {
312
+ return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Extension properties>`, executionPlatform, executionPlatformVersion, allowedVersion);
313
+ }
314
+
315
+ if (is(extensionElement, 'zeebe:UserTask')) {
316
+ return getSupportedMessage('A <User Task> with <Implementation: Zeebe user task>', executionPlatform, executionPlatformVersion, allowedVersion);
317
+ }
318
+
319
+ if (is(node, 'bpmn:ScriptTask') && is(extensionElement, 'zeebe:Script')) {
320
+ return getSupportedMessage('A <Script Task> with <Implementation: FEEL expression>', executionPlatform, executionPlatformVersion, allowedVersion);
321
+ }
322
+
323
+ if (is(node, 'bpmn:UserTask') && is(extensionElement, 'zeebe:TaskSchedule')) {
324
+ return getSupportedMessage('A <User Task> with <Due date> or <Follow up date>', executionPlatform, executionPlatformVersion, allowedVersion);
325
+ }
326
+
327
+ if (is(node, 'bpmn:UserTask') && is(extensionElement, 'zeebe:PriorityDefinition')) {
328
+ return getSupportedMessage('A <User Task> with <Priority>', executionPlatform, executionPlatformVersion, allowedVersion);
329
+ }
330
+
331
+ if (is(node, 'bpmn:StartEvent') && is(extensionElement, 'zeebe:FormDefinition')) {
332
+ return getSupportedMessage('A <Start Event> with <User Task Form>', executionPlatform, executionPlatformVersion, allowedVersion);
333
+ }
334
+
335
+ if (is(extensionElement, 'zeebe:ExecutionListeners')) {
336
+ return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Execution listeners>`, executionPlatform, executionPlatformVersion, allowedVersion);
337
+ }
338
+
339
+ if (is(node, 'bpmn:Process') && is(extensionElement, 'zeebe:VersionTag')) {
340
+ return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Version tag>`, executionPlatform, executionPlatformVersion, allowedVersion);
341
+ }
342
+
343
+ return message;
344
+ }
345
+
346
+ function getExtensionElementRequiredErrorMessage(report) {
347
+ const {
348
+ data,
349
+ message
350
+ } = report;
351
+
352
+ const {
353
+ node,
354
+ parentNode,
355
+ requiredExtensionElement
356
+ } = data;
357
+
358
+ const typeString = getTypeString(parentNode || node);
359
+
360
+ if (requiredExtensionElement === 'zeebe:CalledElement') {
361
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Called element>`;
362
+ }
363
+
364
+ if (requiredExtensionElement === 'zeebe:LoopCharacteristics') {
365
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Multi-instance marker> must have a defined <Input collection>`;
366
+ }
367
+
368
+ if (requiredExtensionElement === 'zeebe:Subscription') {
369
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Message Reference> must have a defined <Subscription correlation key>`;
370
+ }
371
+
372
+ if (requiredExtensionElement === 'zeebe:TaskDefinition') {
373
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a <Task definition type>`;
374
+ }
375
+
376
+ if (isArray(requiredExtensionElement) && requiredExtensionElement.includes('zeebe:CalledDecision')) {
377
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Implementation>`;
378
+ }
379
+
380
+ if (isArray(requiredExtensionElement) && requiredExtensionElement.includes('zeebe:Script')) {
381
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Implementation>`;
382
+ }
383
+
384
+ if (requiredExtensionElement === 'zeebe:FormDefinition') {
385
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> should have a defined <Form>`;
386
+ }
387
+
388
+ return message;
389
+ }
390
+
391
+ function getPropertyDependentRequiredErrorMessage(report) {
392
+ const {
393
+ data,
394
+ message
395
+ } = report;
396
+
397
+ const {
398
+ node,
399
+ parentNode,
400
+ property,
401
+ dependentRequiredProperty
402
+ } = data;
403
+
404
+ const typeString = getTypeString(parentNode || node);
405
+
406
+ if (is(node, 'zeebe:LoopCharacteristics') && property === 'outputCollection' && dependentRequiredProperty === 'outputElement') {
407
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Multi-instance marker> and defined <Output collection> must have a defined <Output element>`;
408
+ }
409
+
410
+ if (is(node, 'zeebe:LoopCharacteristics') && property === 'outputElement' && dependentRequiredProperty === 'outputCollection') {
411
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Multi-instance marker> and defined <Output element> must have a defined <Output collection>`;
412
+ }
413
+
414
+ return message;
415
+ }
416
+
417
+ function getPropertyNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion, modeler = 'desktop') {
418
+ const {
419
+ data,
420
+ message
421
+ } = report;
422
+
423
+ const {
424
+ allowedVersion,
425
+ node,
426
+ parentNode,
427
+ property
428
+ } = data;
429
+
430
+ const typeString = getTypeString(parentNode || node);
431
+
432
+ if (property === 'modelerTemplate') {
433
+ if (modeler === 'desktop') {
434
+ return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <Template ${ typeString }>`, executionPlatform, executionPlatformVersion, allowedVersion);
435
+ } else if (modeler === 'web') {
436
+ return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <Connector ${ typeString }>`, executionPlatform, executionPlatformVersion, allowedVersion);
437
+ }
438
+ }
439
+
440
+ if (is(node, 'bpmn:InclusiveGateway') && property === 'incoming') {
441
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with more than one incoming <Sequence Flow> is not supported by ${ getExecutionPlatformLabel(executionPlatform, executionPlatformVersion) }`;
442
+ }
443
+
444
+ if (is(node, 'zeebe:AssignmentDefinition') && property === 'candidateUsers') {
445
+ return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Candidate users>`, executionPlatform, executionPlatformVersion, allowedVersion);
446
+ }
447
+
448
+ if (is(node, 'bpmn:SequenceFlow') && property === 'conditionExpression') {
449
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Condition expression> is only supported if the source is an <Exclusive Gateway> or <Inclusive Gateway>`;
450
+ }
451
+
452
+ if (is(node, 'bpmn:TimerEventDefinition') && TIMER_PROPERTIES.includes(property)) {
453
+ return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <${ TIMER_PROPERTY_LABELS[ property ] }>`, executionPlatform, executionPlatformVersion, allowedVersion);
454
+ }
455
+
456
+ if (is(node, 'zeebe:FormDefinition') && property === 'formId') {
457
+ return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Form type: Camunda form (linked)>`, executionPlatform, executionPlatformVersion, allowedVersion);
458
+ }
459
+
460
+ if (isAny(node, [
461
+ 'zeebe:CalledDecision',
462
+ 'zeebe:CalledElement',
463
+ 'zeebe:FormDefinition'
464
+ ]) && property === 'versionTag') {
465
+ return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Version tag>`, executionPlatform, executionPlatformVersion, allowedVersion);
466
+ }
467
+
468
+ return message;
469
+ }
470
+
471
+
472
+ function getPropertyRequiredErrorMessage(report, executionPlatform, executionPlatformVersion) {
473
+ const {
474
+ data,
475
+ message
476
+ } = report;
477
+
478
+ const {
479
+ allowedVersion,
480
+ node,
481
+ parentNode,
482
+ requiredProperty
483
+ } = data;
484
+
485
+ const typeString = getTypeString(parentNode || node);
486
+
487
+ if (parentNode && is(parentNode, 'bpmn:BusinessRuleTask') && is(node, 'zeebe:CalledDecision') && requiredProperty === 'decisionId') {
488
+ return 'A <Business Rule Task> with <Implementation: DMN decision> must have a defined <Called decision ID>';
489
+ }
490
+
491
+ if (parentNode && is(parentNode, 'bpmn:BusinessRuleTask') && is(node, 'zeebe:CalledDecision') && requiredProperty === 'resultVariable') {
492
+ return 'A <Business Rule Task> with <Implementation: DMN decision> must have a defined <Result variable>';
493
+ }
494
+
495
+ if (parentNode && is(parentNode, 'bpmn:ScriptTask') && is(node, 'zeebe:Script') && requiredProperty === 'expression') {
496
+ return 'A <Script Task> with <Implementation: FEEL expression> must have a defined <FEEL expression>';
497
+ }
498
+
499
+ if (parentNode && is(parentNode, 'bpmn:ScriptTask') && is(node, 'zeebe:Script') && requiredProperty === 'resultVariable') {
500
+ return 'A <Script Task> with <Implementation: FEEL expression> must have a defined <Result variable>';
501
+ }
502
+
503
+ if (parentNode && isAny(parentNode, [ 'bpmn:BusinessRuleTask', 'bpmn:ScriptTask' ]) && is(node, 'zeebe:TaskDefinition') && requiredProperty === 'type') {
504
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Implementation: Job worker> must have a defined <Task definition type>`;
505
+ }
506
+
507
+ if (is(node, 'zeebe:CalledElement') && requiredProperty === 'processId') {
508
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Called element>`;
509
+ }
510
+
511
+ if (is(node, 'bpmn:Error') && requiredProperty === 'errorCode') {
512
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Error Reference> must have a defined <Error code>`;
513
+ }
514
+
515
+ if (is(node, 'bpmn:Escalation') && requiredProperty === 'escalationCode') {
516
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Escalation Reference> must have a defined <Escalation code>`;
517
+ }
518
+
519
+ if (is(node, 'zeebe:LoopCharacteristics') && requiredProperty === 'inputCollection') {
520
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Multi-instance marker> must have a defined <Input collection>`;
521
+ }
522
+
523
+ if (is(node, 'bpmn:Message') && requiredProperty === 'name') {
524
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Message Reference> must have a defined <Name>`;
525
+ }
526
+
527
+ if (is(node, 'bpmn:Signal') && requiredProperty === 'name') {
528
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Signal Reference> must have a defined <Name>`;
529
+ }
530
+
531
+ if (is(node, 'zeebe:Subscription') && requiredProperty === 'correlationKey') {
532
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Message Reference> must have a defined <Subscription correlation key>`;
533
+ }
534
+
535
+ if (is(node, 'zeebe:TaskDefinition') && requiredProperty === 'type') {
536
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Implementation: Job worker> must have a defined <Task definition type>`;
537
+ }
538
+
539
+ if (is(node, 'zeebe:ExecutionListener') && requiredProperty === 'type') {
540
+ return 'An <Execution Listener> must have a defined <Type>';
541
+ }
542
+
543
+ if (requiredProperty === 'errorRef') {
544
+
545
+ if (parentNode && is(parentNode, 'bpmn:CatchEvent')) {
546
+ return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> without defined <Error Reference>`, executionPlatform, executionPlatformVersion, allowedVersion);
547
+ } else if (parentNode && is(parentNode, 'bpmn:ThrowEvent')) {
548
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Error Reference>`;
549
+ }
550
+
551
+ }
552
+
553
+ if (requiredProperty === 'messageRef') {
554
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Message Reference>`;
555
+ }
556
+
557
+ if (requiredProperty === 'signalRef') {
558
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Signal Reference>`;
559
+ }
560
+
561
+ if (is(node, 'zeebe:FormDefinition')
562
+ && (
563
+ requiredProperty === 'formKey'
564
+ || (isArray(requiredProperty) && requiredProperty.includes('formKey') && isEmptyString(node.get('formKey')))
565
+ )) {
566
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Form type: Custom form key> must have a defined <Form key>`;
567
+ }
568
+
569
+ // Zeebe User Task
570
+ if (is(node, 'zeebe:FormDefinition') && isZeebeUserTask(parentNode)) {
571
+ if (isEmptyString(node.get('externalReference'))) {
572
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Form type: External reference> must have a defined <External reference>`;
573
+ } else if (isEmptyString(node.get('formId'))) {
574
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Form type: Camunda Form> must have a defined <Form ID>`;
575
+ }
576
+ }
577
+
578
+ if (is(node, 'zeebe:FormDefinition') && isArray(requiredProperty) && requiredProperty.includes('formId') && isEmptyString(node.get('formId'))) {
579
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Form type: Camunda form (linked)> must have a defined <Form ID>`;
580
+ }
581
+
582
+ if (is(node, 'zeebe:UserTaskForm') && requiredProperty === 'body') {
583
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Form type: Camunda form (embedded)> must have a defined <Form JSON configuration>`;
584
+ }
585
+
586
+ if (is(node, 'bpmn:SequenceFlow') && requiredProperty === 'conditionExpression') {
587
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Condition expression> or be the default <Sequence Flow>`;
588
+ }
589
+
590
+ if (is(node, 'bpmn:TimerEventDefinition')
591
+ && isArray(requiredProperty)
592
+ && TIMER_PROPERTIES.some(property => requiredProperty.includes(property))
593
+ ) {
594
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Timer type>`;
595
+ }
596
+
597
+ if (is(node, 'bpmn:Process') && requiredProperty === 'historyTimeToLive') {
598
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <History time to live>`;
599
+ }
600
+
601
+ if (is(node, 'bpmn:LinkEventDefinition') && requiredProperty === 'name') {
602
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Name>`;
603
+ }
604
+
605
+ return message;
606
+ }
607
+
608
+ function getExpressionRequiredErrorMessage(report) {
609
+ const {
610
+ data,
611
+ message
612
+ } = report;
613
+
614
+ const {
615
+ node,
616
+ parentNode,
617
+ property
618
+ } = data;
619
+
620
+ const typeString = getTypeString(parentNode || node);
621
+
622
+ if (is(node, 'bpmn:FormalExpression') && TIMER_PROPERTIES.includes(property)) {
623
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a defined <Timer value>`;
624
+ }
625
+
626
+ return message;
627
+ }
628
+
629
+ function getExpressionValueNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion) {
630
+ const {
631
+ data,
632
+ message
633
+ } = report;
634
+
635
+ const {
636
+ node,
637
+ parentNode,
638
+ property
639
+ } = data;
640
+
641
+ const typeString = getTypeString(parentNode || node);
642
+
643
+ if (is(node, 'bpmn:FormalExpression') && property === 'timeCycle') {
644
+ if (!greaterOrEqual(executionPlatformVersion, '8.1')) {
645
+ 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)`;
646
+ } else {
647
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> <Time cycle> must be an expression, an ISO 8601 repeating interval, or a cron expression`;
648
+ }
649
+ }
650
+
651
+ if (is(node, 'bpmn:FormalExpression') && property === 'timeDate') {
652
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> <Time date> must be an expression, or an ISO 8601 date`;
653
+ }
654
+
655
+ if (is(node, 'bpmn:FormalExpression') && property === 'timeDuration') {
656
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> <Time duration> must be an expression, or an ISO 8601 interval`;
657
+ }
658
+
659
+ if (is(node, 'zeebe:TaskSchedule') && property === 'dueDate') {
660
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> <Due date> must be an ISO 8601 date`;
661
+ }
662
+
663
+ if (is(node, 'zeebe:TaskSchedule') && property === 'followUpDate') {
664
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> <Follow up date> must be an ISO 8601 date`;
665
+ }
666
+
667
+ if (is(node, 'zeebe:PriorityDefinition') && property === 'priority') {
668
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> <Priority> must be an expression, or an integer between 0 and 100`;
669
+ }
670
+
671
+ return message;
672
+ }
673
+
674
+ function getSupportedMessage(prefix, executionPlatform, executionPlatformVersion, allowedVersion) {
675
+ if (allowedVersion) {
676
+ return `${ prefix } is only supported by ${ getExecutionPlatformLabel(executionPlatform, allowedVersion) } or newer`;
677
+ }
678
+
679
+ return `${ prefix } is not supported by ${ getExecutionPlatformLabel(executionPlatform, executionPlatformVersion) }`;
680
+ }
681
+
682
+ function getExpressionNotAllowedErrorMessage(report) {
683
+ const {
684
+ data
685
+ } = report;
686
+
687
+ const {
688
+ node,
689
+ parentNode,
690
+ property
691
+ } = data;
692
+
693
+ if (is(node, 'bpmn:Escalation') && property === 'escalationCode' && is(parentNode, 'bpmn:CatchEvent')) {
694
+ return 'Escalation code used in a catch event must be a static value';
695
+ } else if (is(node, 'bpmn:Error') && property === 'errorCode' && is(parentNode, 'bpmn:CatchEvent')) {
696
+ return 'Error code used in a catch event must be a static value';
697
+ }
698
+
699
+ return report.message;
700
+ }
701
+
702
+ function getEventBasedGatewayTargetNotAllowedErrorMessage(report) {
703
+ const { data } = report;
704
+
705
+ const { node } = data;
706
+
707
+ if (is(node, 'bpmn:ReceiveTask')) {
708
+ return 'A <Receive Task> cannot be the target of an <Event-Based Gateway>';
709
+ }
710
+
711
+ return report.message;
712
+ }
713
+
714
+ function getPropertyValueNotAllowedErrorMessage(report, executionPlatform, executionPlatformVersion, modeler = 'desktop') {
715
+ const {
716
+ data,
717
+ message
718
+ } = report;
719
+
720
+ const {
721
+ allowedVersion,
722
+ node,
723
+ parentNode,
724
+ property
725
+ } = data;
726
+
727
+ const typeString = getTypeString(parentNode || node);
728
+
729
+ if (is(node, 'zeebe:CalledElement') && property === 'propagateAllParentVariables') {
730
+ return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Propagate all variables> disabled`, executionPlatform, executionPlatformVersion, allowedVersion);
731
+ }
732
+
733
+ if (isAny(node, [
734
+ 'zeebe:CalledDecision',
735
+ 'zeebe:CalledElement',
736
+ 'zeebe:FormDefinition'
737
+ ]) && property === 'bindingType') {
738
+ const bindingType = node.get('bindingType');
739
+
740
+ let bindingTypeString = bindingType;
741
+
742
+ if (bindingType === 'versionTag') {
743
+ bindingTypeString = 'version tag';
744
+ }
745
+
746
+ return getSupportedMessage(`${ getIndefiniteArticle(typeString) } <${ typeString }> with <Binding: ${ bindingTypeString }>`, executionPlatform, executionPlatformVersion, allowedVersion);
747
+ }
748
+
749
+ return message;
750
+ }
751
+
752
+ function getSecretExpressionFormatDeprecatedErrorMessage(report) {
753
+ const { data } = report;
754
+
755
+ const { property } = data;
756
+
757
+ return `Property <${ property }> uses deprecated secret expression format secrets.SECRET, use {{secrets.SECRET}} instead`;
758
+ }
759
+
760
+ function getElementPropertyValueDuplicatedErrorMessage(report) {
761
+ const {
762
+ data,
763
+ message
764
+ } = report;
765
+
766
+ const {
767
+ node,
768
+ parentNode,
769
+ duplicatedProperty
770
+ } = data;
771
+
772
+ const typeString = getTypeString(parentNode || node);
773
+
774
+ if (is(node, 'bpmn:LinkEventDefinition') && duplicatedProperty === 'name') {
775
+ return `${ getIndefiniteArticle(typeString) } <${ typeString }> must have a unique <Name>`;
776
+ }
777
+
778
+ return message;
779
+ }
780
+
781
+ function getLoopNotAllowedErrorMessage(report) {
782
+ const { data } = report;
783
+
784
+ const { elements } = data;
785
+
786
+ return `A <Process> is not allowed to contain a straight-through processing loop: ${ elements.map(element => `<${ element }>`).join(', ') }`;
787
+ }
788
+
789
+ function isEmptyString(value) {
790
+ return isString(value) && value.trim() === '';
791
+ }
792
+
793
+ function isZeebeUserTask(node) {
794
+ return node.get('extensionElements').get('values').some(extensionElement => {
795
+ return is(extensionElement, 'zeebe:UserTask');
796
+ });
797
+ }