bpmnlint-plugin-camunda-compat 2.21.1 → 2.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +20 -20
- package/README.md +39 -39
- package/index.js +237 -224
- package/package.json +53 -53
- package/rules/camunda-cloud/called-element.js +42 -42
- package/rules/camunda-cloud/collapsed-subprocess.js +40 -40
- package/rules/camunda-cloud/connector-properties/config.js +90 -90
- package/rules/camunda-cloud/connector-properties/index.js +47 -47
- package/rules/camunda-cloud/duplicate-execution-listeners.js +33 -0
- package/rules/camunda-cloud/duplicate-task-headers.js +58 -58
- package/rules/camunda-cloud/element-type/config.js +66 -66
- package/rules/camunda-cloud/element-type/index.js +133 -133
- package/rules/camunda-cloud/error-reference.js +71 -71
- package/rules/camunda-cloud/escalation-boundary-event-attached-to-ref.js +48 -48
- package/rules/camunda-cloud/escalation-reference.js +66 -66
- package/rules/camunda-cloud/event-based-gateway-target.js +38 -38
- package/rules/camunda-cloud/executable-process.js +61 -61
- package/rules/camunda-cloud/execution-listener.js +34 -0
- package/rules/camunda-cloud/feel.js +82 -82
- package/rules/camunda-cloud/implementation/config.js +16 -16
- package/rules/camunda-cloud/implementation/index.js +218 -218
- package/rules/camunda-cloud/inclusive-gateway.js +35 -35
- package/rules/camunda-cloud/link-event.js +142 -142
- package/rules/camunda-cloud/loop-characteristics.js +66 -66
- package/rules/camunda-cloud/message-reference.js +60 -60
- package/rules/camunda-cloud/no-binding-type.js +44 -0
- package/rules/camunda-cloud/no-candidate-users.js +38 -38
- package/rules/camunda-cloud/no-execution-listeners.js +21 -0
- package/rules/camunda-cloud/no-expression.js +173 -173
- package/rules/camunda-cloud/no-loop.js +316 -316
- package/rules/camunda-cloud/no-multiple-none-start-events.js +41 -41
- package/rules/camunda-cloud/no-propagate-all-parent-variables.js +44 -44
- package/rules/camunda-cloud/no-signal-event-sub-process.js +45 -45
- package/rules/camunda-cloud/no-task-schedule.js +18 -18
- package/rules/camunda-cloud/no-template.js +23 -23
- package/rules/camunda-cloud/no-zeebe-properties.js +18 -18
- package/rules/camunda-cloud/no-zeebe-user-task.js +27 -27
- package/rules/camunda-cloud/secrets.js +119 -119
- package/rules/camunda-cloud/sequence-flow-condition.js +56 -56
- package/rules/camunda-cloud/signal-reference.js +64 -64
- package/rules/camunda-cloud/start-event-form.js +97 -97
- package/rules/camunda-cloud/subscription.js +65 -65
- package/rules/camunda-cloud/task-schedule.js +67 -67
- package/rules/camunda-cloud/timer/config.js +46 -46
- package/rules/camunda-cloud/timer/index.js +183 -183
- package/rules/camunda-cloud/user-task-definition.js +24 -24
- package/rules/camunda-cloud/user-task-form.js +142 -142
- package/rules/camunda-cloud/wait-for-completion.js +46 -46
- package/rules/camunda-platform/history-time-to-live.js +19 -19
- package/rules/utils/cron.js +95 -95
- package/rules/utils/element.js +533 -484
- package/rules/utils/error-types.js +25 -24
- package/rules/utils/iso8601.js +52 -52
- package/rules/utils/reporter.js +37 -37
- package/rules/utils/rule.js +46 -46
- package/rules/utils/version.js +4 -4
package/rules/utils/element.js
CHANGED
@@ -1,485 +1,534 @@
|
|
1
|
-
const {
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
const {
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
module.exports.
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
}
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
module.exports.
|
93
|
-
|
94
|
-
|
95
|
-
const
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
const
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
:
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
}
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
}
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
function
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
1
|
+
const {
|
2
|
+
filter,
|
3
|
+
isArray,
|
4
|
+
isDefined,
|
5
|
+
isFunction,
|
6
|
+
isNil,
|
7
|
+
isObject,
|
8
|
+
isString,
|
9
|
+
isUndefined,
|
10
|
+
matchPattern,
|
11
|
+
some
|
12
|
+
} = require('min-dash');
|
13
|
+
|
14
|
+
const {
|
15
|
+
is,
|
16
|
+
isAny
|
17
|
+
} = require('bpmnlint-utils');
|
18
|
+
|
19
|
+
const { getPath } = require('@bpmn-io/moddle-utils');
|
20
|
+
|
21
|
+
const { ERROR_TYPES } = require('./error-types');
|
22
|
+
|
23
|
+
module.exports.ERROR_TYPES = ERROR_TYPES;
|
24
|
+
|
25
|
+
function getEventDefinition(node) {
|
26
|
+
const eventDefinitions = node.get('eventDefinitions');
|
27
|
+
|
28
|
+
if (eventDefinitions) {
|
29
|
+
return eventDefinitions[ 0 ];
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
module.exports.getEventDefinition = getEventDefinition;
|
34
|
+
|
35
|
+
module.exports.getMessageEventDefinition = function(node) {
|
36
|
+
if (is(node, 'bpmn:ReceiveTask')) {
|
37
|
+
return node;
|
38
|
+
}
|
39
|
+
|
40
|
+
return getEventDefinition(node);
|
41
|
+
};
|
42
|
+
|
43
|
+
function findExtensionElements(node, types) {
|
44
|
+
const extensionElements = node.get('extensionElements');
|
45
|
+
|
46
|
+
if (!extensionElements) {
|
47
|
+
return;
|
48
|
+
}
|
49
|
+
|
50
|
+
const values = extensionElements.get('values');
|
51
|
+
|
52
|
+
if (!values || !values.length) {
|
53
|
+
return;
|
54
|
+
}
|
55
|
+
|
56
|
+
if (!isArray(types)) {
|
57
|
+
types = [ types ];
|
58
|
+
}
|
59
|
+
|
60
|
+
return values.filter(value => isAny(value, types));
|
61
|
+
}
|
62
|
+
|
63
|
+
module.exports.findExtensionElements = findExtensionElements;
|
64
|
+
|
65
|
+
function findExtensionElement(node, types) {
|
66
|
+
const extensionElements = findExtensionElements(node, types);
|
67
|
+
|
68
|
+
if (extensionElements && extensionElements.length) {
|
69
|
+
return extensionElements[ 0 ];
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
73
|
+
module.exports.findExtensionElement = findExtensionElement;
|
74
|
+
|
75
|
+
function formatNames(names, exclusive = false) {
|
76
|
+
return names.reduce((string, name, index) => {
|
77
|
+
|
78
|
+
// first
|
79
|
+
if (index === 0) {
|
80
|
+
return `<${ name }>`;
|
81
|
+
}
|
82
|
+
|
83
|
+
// last
|
84
|
+
if (index === names.length - 1) {
|
85
|
+
return `${ string } ${ exclusive ? 'or' : 'and' } <${ name }>`;
|
86
|
+
}
|
87
|
+
|
88
|
+
return `${ string }, <${ name }>`;
|
89
|
+
}, '');
|
90
|
+
}
|
91
|
+
|
92
|
+
module.exports.formatNames = formatNames;
|
93
|
+
|
94
|
+
module.exports.hasDuplicatedPropertyValues = function(node, propertiesName, propertyName, parentNode = null) {
|
95
|
+
const properties = node.get(propertiesName);
|
96
|
+
|
97
|
+
const propertyValues = properties.map(property => property.get(propertyName));
|
98
|
+
|
99
|
+
// (1) find duplicates
|
100
|
+
const duplicates = propertyValues.reduce((duplicates, propertyValue, index) => {
|
101
|
+
if (propertyValues.indexOf(propertyValue) !== index && !duplicates.includes(propertyValue)) {
|
102
|
+
return [
|
103
|
+
...duplicates,
|
104
|
+
propertyValue
|
105
|
+
];
|
106
|
+
}
|
107
|
+
|
108
|
+
return duplicates;
|
109
|
+
}, []);
|
110
|
+
|
111
|
+
// (2) report error for each duplicate
|
112
|
+
if (duplicates.length) {
|
113
|
+
return duplicates.map(duplicate => {
|
114
|
+
|
115
|
+
// (3) find properties with duplicate
|
116
|
+
const duplicateProperties = properties.filter(property => property.get(propertyName) === duplicate);
|
117
|
+
|
118
|
+
// (4) report error
|
119
|
+
return {
|
120
|
+
message: `Properties of type <${ duplicateProperties[ 0 ].$type }> have property <${ propertyName }> with duplicate value of <${ duplicate }>`,
|
121
|
+
path: null,
|
122
|
+
data: {
|
123
|
+
type: ERROR_TYPES.PROPERTY_VALUE_DUPLICATED,
|
124
|
+
node,
|
125
|
+
parentNode: parentNode == node ? null : parentNode,
|
126
|
+
duplicatedProperty: propertyName,
|
127
|
+
duplicatedPropertyValue: duplicate,
|
128
|
+
properties: duplicateProperties,
|
129
|
+
propertiesName
|
130
|
+
}
|
131
|
+
};
|
132
|
+
});
|
133
|
+
}
|
134
|
+
|
135
|
+
return [];
|
136
|
+
};
|
137
|
+
|
138
|
+
// @TODO(@barmac): use tree algorithm to reduce complexity
|
139
|
+
module.exports.hasDuplicatedPropertiesValues = function(node, containerPropertyName, propertiesNames, parentNode = null) {
|
140
|
+
const properties = node.get(containerPropertyName);
|
141
|
+
|
142
|
+
// (1) find duplicates
|
143
|
+
const duplicates = properties.reduce((foundDuplicates, property, index) => {
|
144
|
+
const previous = properties.slice(0, index);
|
145
|
+
const isDuplicate = previous.find(p => propertiesNames.every(propertyName => p.get(propertyName) === property.get(propertyName)));
|
146
|
+
|
147
|
+
if (isDuplicate) {
|
148
|
+
return foundDuplicates.concat(property);
|
149
|
+
}
|
150
|
+
|
151
|
+
return foundDuplicates;
|
152
|
+
}, []);
|
153
|
+
|
154
|
+
// (2) report error for each duplicate
|
155
|
+
if (duplicates.length) {
|
156
|
+
return duplicates.map(duplicate => {
|
157
|
+
const propertiesMap = {};
|
158
|
+
for (const property of propertiesNames) {
|
159
|
+
propertiesMap[property] = duplicate.get(property);
|
160
|
+
}
|
161
|
+
|
162
|
+
// (3) find properties with duplicate
|
163
|
+
const duplicateProperties = filter(properties, matchPattern(propertiesMap));
|
164
|
+
const duplicatesSummary = propertiesNames.map(propertyName => `property <${ propertyName }> with duplicate value of <${ propertiesMap[propertyName] }>`).join(', ');
|
165
|
+
|
166
|
+
// (4) report error
|
167
|
+
return {
|
168
|
+
message: `Properties of type <${ duplicate.$type }> have properties with duplicate values (${ duplicatesSummary })`,
|
169
|
+
path: null,
|
170
|
+
data: {
|
171
|
+
type: ERROR_TYPES.PROPERTY_VALUES_DUPLICATED,
|
172
|
+
node,
|
173
|
+
parentNode: parentNode == node ? null : parentNode,
|
174
|
+
duplicatedProperties: propertiesMap,
|
175
|
+
properties: duplicateProperties,
|
176
|
+
propertiesName: containerPropertyName
|
177
|
+
}
|
178
|
+
};
|
179
|
+
});
|
180
|
+
}
|
181
|
+
|
182
|
+
return [];
|
183
|
+
};
|
184
|
+
|
185
|
+
module.exports.hasProperties = function(node, properties, parentNode = null) {
|
186
|
+
return Object.entries(properties).reduce((results, property) => {
|
187
|
+
const [ propertyName, propertyChecks ] = property;
|
188
|
+
|
189
|
+
const { allowedVersion = null } = propertyChecks;
|
190
|
+
|
191
|
+
const path = getPath(node, parentNode);
|
192
|
+
|
193
|
+
const propertyValue = node.get(propertyName);
|
194
|
+
|
195
|
+
if (propertyChecks.required && isEmptyValue(propertyValue)) {
|
196
|
+
return [
|
197
|
+
...results,
|
198
|
+
{
|
199
|
+
message: allowedVersion
|
200
|
+
? `Element of type <${ node.$type }> without property <${ propertyName }> only allowed by Camunda ${ allowedVersion } or newer`
|
201
|
+
: `Element of type <${ node.$type }> must have property <${ propertyName }>`,
|
202
|
+
path: path
|
203
|
+
? [ ...path, propertyName ]
|
204
|
+
: [ propertyName ],
|
205
|
+
data: addAllowedVersion({
|
206
|
+
type: ERROR_TYPES.PROPERTY_REQUIRED,
|
207
|
+
node,
|
208
|
+
parentNode: parentNode == node ? null : parentNode,
|
209
|
+
requiredProperty: propertyName
|
210
|
+
}, allowedVersion)
|
211
|
+
}
|
212
|
+
];
|
213
|
+
}
|
214
|
+
|
215
|
+
if (propertyChecks.dependentRequired) {
|
216
|
+
const dependency = node.get(propertyChecks.dependentRequired);
|
217
|
+
|
218
|
+
if (dependency && isEmptyValue(propertyValue)) {
|
219
|
+
return [
|
220
|
+
...results,
|
221
|
+
{
|
222
|
+
message: `Element of type <${ node.$type }> must have property <${ propertyName }> if it has property <${ propertyChecks.dependentRequired }>`,
|
223
|
+
path: path
|
224
|
+
? [ ...path, propertyName ]
|
225
|
+
: [ propertyName ],
|
226
|
+
data: {
|
227
|
+
type: ERROR_TYPES.PROPERTY_DEPENDENT_REQUIRED,
|
228
|
+
node,
|
229
|
+
parentNode: parentNode == node ? null : parentNode,
|
230
|
+
property: propertyChecks.dependentRequired,
|
231
|
+
dependentRequiredProperty: propertyName
|
232
|
+
}
|
233
|
+
}
|
234
|
+
];
|
235
|
+
}
|
236
|
+
}
|
237
|
+
|
238
|
+
if (
|
239
|
+
propertyChecks.type
|
240
|
+
&& propertyValue
|
241
|
+
&& (
|
242
|
+
!propertyValue.$instanceOf
|
243
|
+
|| (!isArray(propertyChecks.type) && !propertyValue.$instanceOf(propertyChecks.type))
|
244
|
+
|| (isArray(propertyChecks.type) && !some(propertyChecks.type, type => propertyValue.$instanceOf(type)))
|
245
|
+
)
|
246
|
+
) {
|
247
|
+
return [
|
248
|
+
...results,
|
249
|
+
{
|
250
|
+
message: allowedVersion
|
251
|
+
? `Property <${ propertyName }> of type <${ propertyValue.$type }> only allowed by Camunda ${ allowedVersion } or newer`
|
252
|
+
: `Property <${ propertyName }> of type <${ propertyValue.$type }> not allowed`,
|
253
|
+
path: path
|
254
|
+
? [ ...path, propertyName ]
|
255
|
+
: [ propertyName ],
|
256
|
+
data: addAllowedVersion({
|
257
|
+
type: ERROR_TYPES.PROPERTY_TYPE_NOT_ALLOWED,
|
258
|
+
node,
|
259
|
+
parentNode: parentNode == node ? null : parentNode,
|
260
|
+
property: propertyName,
|
261
|
+
allowedPropertyType: propertyChecks.type
|
262
|
+
}, allowedVersion)
|
263
|
+
}
|
264
|
+
];
|
265
|
+
}
|
266
|
+
|
267
|
+
if ('value' in propertyChecks && propertyChecks.value !== propertyValue) {
|
268
|
+
return [
|
269
|
+
...results,
|
270
|
+
{
|
271
|
+
message: `Property <${ propertyName }> must have value of <${ propertyChecks.value }>`,
|
272
|
+
path: path
|
273
|
+
? [ ...path, propertyName ]
|
274
|
+
: [ propertyName ],
|
275
|
+
data: {
|
276
|
+
type: ERROR_TYPES.PROPERTY_VALUE_REQUIRED,
|
277
|
+
node,
|
278
|
+
parentNode: parentNode == node ? null : parentNode,
|
279
|
+
property: propertyName,
|
280
|
+
requiredValue: propertyChecks.value
|
281
|
+
}
|
282
|
+
}
|
283
|
+
];
|
284
|
+
}
|
285
|
+
|
286
|
+
if (propertyChecks.allowed === false && isDefined(propertyValue) && !isNil(propertyValue)) {
|
287
|
+
return [
|
288
|
+
...results,
|
289
|
+
{
|
290
|
+
message: allowedVersion
|
291
|
+
? `Property <${ propertyName }> only allowed by Camunda ${ allowedVersion } or newer`
|
292
|
+
: `Property <${ propertyName }> not allowed`,
|
293
|
+
path: path
|
294
|
+
? [ ...path, propertyName ]
|
295
|
+
: [ propertyName ],
|
296
|
+
data: addAllowedVersion({
|
297
|
+
type: ERROR_TYPES.PROPERTY_NOT_ALLOWED,
|
298
|
+
node,
|
299
|
+
parentNode: parentNode == node ? null : parentNode,
|
300
|
+
property: propertyName
|
301
|
+
}, allowedVersion)
|
302
|
+
}
|
303
|
+
];
|
304
|
+
}
|
305
|
+
|
306
|
+
if (isFunction(propertyChecks.allowed) && !propertyChecks.allowed(propertyValue)) {
|
307
|
+
return [
|
308
|
+
...results,
|
309
|
+
{
|
310
|
+
message: allowedVersion
|
311
|
+
? `Property value of <${ truncate(propertyValue) }> only allowed by Camunda ${ allowedVersion } or newer`
|
312
|
+
: `Property value of <${ truncate(propertyValue) }> not allowed`,
|
313
|
+
path: path
|
314
|
+
? [ ...path, propertyName ]
|
315
|
+
: [ propertyName ],
|
316
|
+
data: addAllowedVersion({
|
317
|
+
type: ERROR_TYPES.PROPERTY_VALUE_NOT_ALLOWED,
|
318
|
+
node,
|
319
|
+
parentNode: parentNode == node ? null : parentNode,
|
320
|
+
property: propertyName
|
321
|
+
}, allowedVersion)
|
322
|
+
}
|
323
|
+
];
|
324
|
+
}
|
325
|
+
|
326
|
+
return results;
|
327
|
+
}, []);
|
328
|
+
};
|
329
|
+
|
330
|
+
module.exports.hasProperty = function(node, propertyNames, parentNode = null) {
|
331
|
+
propertyNames = isArray(propertyNames) ? propertyNames : [ propertyNames ];
|
332
|
+
|
333
|
+
const properties = findProperties(node, propertyNames);
|
334
|
+
|
335
|
+
if (properties.length !== 1) {
|
336
|
+
return [
|
337
|
+
{
|
338
|
+
message: `Element of type <${ node.$type }> must have property ${ formatNames(propertyNames, true) }`,
|
339
|
+
path: getPath(node, parentNode),
|
340
|
+
data: {
|
341
|
+
type: ERROR_TYPES.PROPERTY_REQUIRED,
|
342
|
+
node,
|
343
|
+
parentNode: parentNode == node ? null : parentNode,
|
344
|
+
requiredProperty: propertyNames
|
345
|
+
}
|
346
|
+
}
|
347
|
+
];
|
348
|
+
}
|
349
|
+
|
350
|
+
return [];
|
351
|
+
};
|
352
|
+
|
353
|
+
function findProperties(node, propertyNames) {
|
354
|
+
const properties = [];
|
355
|
+
|
356
|
+
for (const propertyName of propertyNames) {
|
357
|
+
const propertyValue = node.get(propertyName);
|
358
|
+
|
359
|
+
if (!isEmptyValue(propertyValue)) {
|
360
|
+
properties.push(node.get(propertyName));
|
361
|
+
}
|
362
|
+
}
|
363
|
+
|
364
|
+
return properties;
|
365
|
+
}
|
366
|
+
|
367
|
+
module.exports.hasExtensionElement = function(node, types, parentNode = null) {
|
368
|
+
const typesArray = isArray(types) ? types : [ types ];
|
369
|
+
|
370
|
+
const extensionElements = findExtensionElements(node, typesArray);
|
371
|
+
|
372
|
+
if (!extensionElements || extensionElements.length !== 1) {
|
373
|
+
return [
|
374
|
+
{
|
375
|
+
message: `Element of type <${ node.$type }> must have one extension element of type ${ formatNames(typesArray, true) }`,
|
376
|
+
path: getPath(node, parentNode),
|
377
|
+
data: {
|
378
|
+
type: ERROR_TYPES.EXTENSION_ELEMENT_REQUIRED,
|
379
|
+
node,
|
380
|
+
parentNode: parentNode == node ? null : parentNode,
|
381
|
+
requiredExtensionElement: types
|
382
|
+
}
|
383
|
+
}
|
384
|
+
];
|
385
|
+
}
|
386
|
+
|
387
|
+
return [];
|
388
|
+
};
|
389
|
+
|
390
|
+
module.exports.hasNoExtensionElement = function(node, type, parentNode = null, allowedVersion = null) {
|
391
|
+
const extensionElement = findExtensionElement(node, type);
|
392
|
+
|
393
|
+
if (extensionElement) {
|
394
|
+
return [
|
395
|
+
{
|
396
|
+
message: allowedVersion
|
397
|
+
? `Extension element of type <${ type }> only allowed by Camunda ${ allowedVersion }`
|
398
|
+
: `Extension element of type <${ type }> not allowed`,
|
399
|
+
path: getPath(extensionElement, parentNode),
|
400
|
+
data: addAllowedVersion({
|
401
|
+
type: ERROR_TYPES.EXTENSION_ELEMENT_NOT_ALLOWED,
|
402
|
+
node,
|
403
|
+
parentNode: parentNode == node ? null : parentNode,
|
404
|
+
extensionElement
|
405
|
+
}, allowedVersion)
|
406
|
+
}
|
407
|
+
];
|
408
|
+
}
|
409
|
+
|
410
|
+
return [];
|
411
|
+
};
|
412
|
+
|
413
|
+
module.exports.hasExpression = function(node, propertyName, check, parentNode = null) {
|
414
|
+
const expression = node.get(propertyName);
|
415
|
+
|
416
|
+
if (!expression) {
|
417
|
+
throw new Error('Expression not found');
|
418
|
+
}
|
419
|
+
|
420
|
+
let propertyValue = expression;
|
421
|
+
|
422
|
+
if (is(expression, 'bpmn:Expression')) {
|
423
|
+
propertyValue = expression.get('body');
|
424
|
+
}
|
425
|
+
|
426
|
+
const path = getPath(node, parentNode);
|
427
|
+
|
428
|
+
if (!propertyValue) {
|
429
|
+
if (check.required !== false) {
|
430
|
+
return [
|
431
|
+
{
|
432
|
+
message: `Property <${ propertyName }> must have expression value`,
|
433
|
+
path: path
|
434
|
+
? [ ...path, propertyName ]
|
435
|
+
: null,
|
436
|
+
data: {
|
437
|
+
type: ERROR_TYPES.EXPRESSION_REQUIRED,
|
438
|
+
node: is(expression, 'bpmn:Expression') ? expression : node,
|
439
|
+
parentNode,
|
440
|
+
property: propertyName
|
441
|
+
}
|
442
|
+
}
|
443
|
+
];
|
444
|
+
}
|
445
|
+
|
446
|
+
return [];
|
447
|
+
}
|
448
|
+
|
449
|
+
const allowed = check.allowed(propertyValue);
|
450
|
+
|
451
|
+
if (allowed !== true) {
|
452
|
+
let allowedVersion = null;
|
453
|
+
|
454
|
+
if (isObject(allowed)) {
|
455
|
+
({ allowedVersion } = allowed);
|
456
|
+
}
|
457
|
+
|
458
|
+
return [
|
459
|
+
{
|
460
|
+
message: allowedVersion
|
461
|
+
? `Expression value of <${ propertyValue }> only allowed by Camunda ${ allowedVersion }`
|
462
|
+
: `Expression value of <${ propertyValue }> not allowed`,
|
463
|
+
path: path
|
464
|
+
? [ ...path, propertyName ]
|
465
|
+
: null,
|
466
|
+
data: addAllowedVersion({
|
467
|
+
type: ERROR_TYPES.EXPRESSION_VALUE_NOT_ALLOWED,
|
468
|
+
node: is(expression, 'bpmn:Expression') ? expression : node,
|
469
|
+
parentNode,
|
470
|
+
property: propertyName
|
471
|
+
}, allowedVersion)
|
472
|
+
}
|
473
|
+
];
|
474
|
+
}
|
475
|
+
|
476
|
+
return [];
|
477
|
+
};
|
478
|
+
|
479
|
+
function isExactly(node, type) {
|
480
|
+
const { $model } = node;
|
481
|
+
|
482
|
+
return $model.getType(node.$type) === $model.getType(type);
|
483
|
+
}
|
484
|
+
|
485
|
+
module.exports.isExactly = isExactly;
|
486
|
+
|
487
|
+
module.exports.isAnyExactly = function(node, types) {
|
488
|
+
return some(types, (type) => isExactly(node, type));
|
489
|
+
};
|
490
|
+
|
491
|
+
function truncate(string, maxLength = 10) {
|
492
|
+
const stringified = `${ string }`;
|
493
|
+
|
494
|
+
return stringified.length > maxLength ? `${ stringified.slice(0, maxLength) }...` : stringified;
|
495
|
+
}
|
496
|
+
|
497
|
+
function addAllowedVersion(data, allowedVersion) {
|
498
|
+
if (!allowedVersion) {
|
499
|
+
return data;
|
500
|
+
}
|
501
|
+
|
502
|
+
return {
|
503
|
+
...data,
|
504
|
+
allowedVersion
|
505
|
+
};
|
506
|
+
}
|
507
|
+
|
508
|
+
function findParent(node, type) {
|
509
|
+
if (!node) {
|
510
|
+
return null;
|
511
|
+
}
|
512
|
+
|
513
|
+
const parent = node.$parent;
|
514
|
+
|
515
|
+
if (!parent) {
|
516
|
+
return node;
|
517
|
+
}
|
518
|
+
|
519
|
+
if (is(parent, type)) {
|
520
|
+
return parent;
|
521
|
+
}
|
522
|
+
|
523
|
+
return findParent(parent, type);
|
524
|
+
}
|
525
|
+
|
526
|
+
module.exports.findParent = findParent;
|
527
|
+
|
528
|
+
function isEmptyString(value) {
|
529
|
+
return isString(value) && value.trim() === '';
|
530
|
+
}
|
531
|
+
|
532
|
+
function isEmptyValue(value) {
|
533
|
+
return isUndefined(value) || isNil(value) || isEmptyString(value);
|
485
534
|
}
|