bpmnlint-plugin-camunda-compat 0.6.3 → 0.8.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,148 +1,25 @@
1
1
  const {
2
2
  isArray,
3
- isObject,
4
- isString,
3
+ isDefined,
5
4
  some
6
5
  } = require('min-dash');
7
6
 
8
- const {
9
- is,
10
- isAny
11
- } = require('bpmnlint-utils');
7
+ const { isAny } = require('bpmnlint-utils');
12
8
 
13
9
  const { getPath } = require('@philippfromme/moddle-helpers');
14
10
 
15
- const ERROR_TYPES = Object.freeze({
16
- ELEMENT_TYPE: 'elementType',
17
- EXTENSION_ELEMENT_REQUIRED: 'extensionElementRequired',
18
- PROPERTY_DEPENDEND_REQUIRED: 'propertyDependendRequired',
19
- PROPERTY_REQUIRED: 'propertyRequired',
20
- PROPERTY_TYPE: 'propertyType'
21
- });
11
+ const { ERROR_TYPES } = require('./error-types');
22
12
 
23
13
  module.exports.ERROR_TYPES = ERROR_TYPES;
24
14
 
25
- /**
26
- * @param {ModdleElement} node
27
- *
28
- * @returns {boolean|string}
29
- */
30
- function hasNoEventDefinition(node) {
31
- const eventDefinitions = node.get('eventDefinitions');
32
-
33
- return !eventDefinitions
34
- || !eventDefinitions.length
35
- || getElementNotSupportedError(node.$type, eventDefinitions[ 0 ].$type, [ 'eventDefinitions', 0 ]);
36
- }
37
-
38
- module.exports.hasNoEventDefinition = hasNoEventDefinition;
39
-
40
- /**
41
- * @param {ModdleElement} node
42
- * @param {string[]} types
43
- *
44
- * @returns {boolean|string}
45
- */
46
- function hasEventDefinitionOfType(node, types) {
47
- if (!isArray(types)) {
48
- types = [ types ];
49
- }
50
-
15
+ module.exports.getEventDefinition = function(node) {
51
16
  const eventDefinitions = node.get('eventDefinitions');
52
17
 
53
- if (!eventDefinitions || eventDefinitions.length !== 1) {
54
- return getElementNotSupportedError(node.$type, null);
55
- }
56
-
57
- const eventDefinition = eventDefinitions[ 0 ];
58
-
59
- return isAny(eventDefinition, types)
60
- || getElementNotSupportedError(node.$type, eventDefinition.$type, [ 'eventDefinitions', 0 ]);
61
- }
62
-
63
- /**
64
- * @param {string[]} types
65
- *
66
- * @returns {Function}
67
- */
68
- module.exports.hasEventDefinitionOfType = function(types) {
69
- return function(node) {
70
- return hasEventDefinitionOfType(node, types);
71
- };
72
- };
73
-
74
- /**
75
- * @param {string[]} types
76
- *
77
- * @returns {Function}
78
- */
79
- module.exports.hasEventDefinitionOfTypeOrNone = function(types) {
80
- return function(node) {
81
- const results = [
82
- hasNoEventDefinition(node),
83
- hasEventDefinitionOfType(node, types)
84
- ];
85
-
86
- return some(results, result => result === true)
87
- || results.find(result => isArray(result) || isObject(result) || isString(result));
88
- };
89
- };
90
-
91
- module.exports.hasLoopCharacteristics = function(node) {
92
- return !!node.get('loopCharacteristics');
93
- };
94
-
95
- /**
96
- * @param {string[]} types
97
- *
98
- * @returns {boolean|string}
99
- */
100
- module.exports.hasLoopCharacteristicsOfTypeOrNone = function(type) {
101
- return function(node) {
102
- const loopCharacteristics = node.get('loopCharacteristics');
103
-
104
- if (!loopCharacteristics) {
105
- return true;
106
- }
107
-
108
- return is(loopCharacteristics, type)
109
- || getElementNotSupportedError(node.$type, loopCharacteristics.$type, [ 'loopCharacteristics' ]);
110
- };
111
- };
112
-
113
- /**
114
- * @param {ModdleElement} node
115
- *
116
- * @returns {boolean|Object|Object[]}
117
- */
118
- module.exports.hasMultiInstanceLoopCharacteristics = function(node) {
119
- const results = checkProperties(node, {
120
- loopCharacteristics: {
121
- type: 'bpmn:MultiInstanceLoopCharacteristics'
122
- }
123
- }, node);
124
-
125
- if (results.length === 1) {
126
- return results[ 0 ];
127
- } else if (results.length > 1) {
128
- return results;
18
+ if (eventDefinitions) {
19
+ return eventDefinitions[ 0 ];
129
20
  }
130
-
131
- return true;
132
21
  };
133
22
 
134
- module.exports.isNotBpmn = function(node) {
135
- return !is(node, 'bpmn:BaseElement');
136
- };
137
-
138
- function findExtensionElement(node, types) {
139
- const extensionElements = findExtensionElements(node, types);
140
-
141
- if (extensionElements && extensionElements.length) {
142
- return extensionElements[ 0 ];
143
- }
144
- }
145
-
146
23
  function findExtensionElements(node, types) {
147
24
  const extensionElements = node.get('extensionElements');
148
25
 
@@ -163,75 +40,18 @@ function findExtensionElements(node, types) {
163
40
  return values.filter(value => isAny(value, types));
164
41
  }
165
42
 
166
- module.exports.findExtensionElement = findExtensionElement;
167
-
168
- function getElementNotSupportedError(type, propertyType, path = null) {
169
- if (propertyType) {
170
- return {
171
- message: `Element of type <${ type }> (<${ propertyType }>) not supported by {{ executionPlatform }}`,
172
- path,
173
- error: {
174
- type: ERROR_TYPES.ELEMENT_TYPE,
175
- elementType: type,
176
- propertyType
177
- }
178
- };
179
- }
180
-
181
- return {
182
- message: `Element of type <${ type }> not supported by {{ executionPlatform }}`,
183
- path,
184
- error: {
185
- type: ERROR_TYPES.ELEMENT_TYPE,
186
- elementType: type
187
- }
188
- };
189
- }
190
-
191
- /**
192
- * @param {string|Object} type
193
- *
194
- * @returns {string}
195
- */
196
- function getType(type) {
197
- if (isObject(type)) {
198
- return type.type;
199
- }
200
-
201
- return type;
202
- }
43
+ function findExtensionElement(node, types) {
44
+ const extensionElements = findExtensionElements(node, types);
203
45
 
204
- /**
205
- * @param {string|Object} type
206
- *
207
- * @returns {string|Object}
208
- */
209
- function getProperties(type) {
210
- if (isObject(type)) {
211
- return type.properties;
46
+ if (extensionElements && extensionElements.length) {
47
+ return extensionElements[ 0 ];
212
48
  }
213
49
  }
214
50
 
215
- /**
216
- * @param {Function} check
217
- * @param {Function} ifFn
218
- * @param {*} [elseReturnValue]
219
- *
220
- * @returns {Function}
221
- */
222
- module.exports.checkIf = function(check, ifFn, elseReturnValue = true) {
223
- return function(node) {
224
- if (ifFn(node) === true) {
225
- return check(node);
226
- }
227
-
228
- return elseReturnValue;
229
- };
230
- };
51
+ module.exports.findExtensionElement = findExtensionElement;
231
52
 
232
53
  function formatTypes(types, exclusive = false) {
233
54
  return types.reduce((string, type, index) => {
234
- type = getType(type);
235
55
 
236
56
  // first
237
57
  if (index === 0) {
@@ -249,7 +69,7 @@ function formatTypes(types, exclusive = false) {
249
69
 
250
70
  module.exports.formatTypes = formatTypes;
251
71
 
252
- function checkProperties(node, properties, parentNode) {
72
+ module.exports.hasProperties = function(node, properties, parentNode = null) {
253
73
  return Object.entries(properties).reduce((results, property) => {
254
74
  const [ propertyName, propertyChecks ] = property;
255
75
 
@@ -267,6 +87,8 @@ function checkProperties(node, properties, parentNode) {
267
87
  : [ propertyName ],
268
88
  error: {
269
89
  type: ERROR_TYPES.PROPERTY_REQUIRED,
90
+ node,
91
+ parentNode: parentNode == node ? null : parentNode,
270
92
  requiredProperty: propertyName
271
93
  }
272
94
  }
@@ -286,6 +108,9 @@ function checkProperties(node, properties, parentNode) {
286
108
  : [ propertyName ],
287
109
  error: {
288
110
  type: ERROR_TYPES.PROPERTY_DEPENDEND_REQUIRED,
111
+ node,
112
+ parentNode: parentNode == node ? null : parentNode,
113
+ property: propertyChecks.dependendRequired,
289
114
  dependendRequiredProperty: propertyName
290
115
  }
291
116
  }
@@ -293,17 +118,46 @@ function checkProperties(node, properties, parentNode) {
293
118
  }
294
119
  }
295
120
 
296
- if (propertyChecks.type && propertyValue && (!propertyValue.$instanceOf || !propertyValue.$instanceOf(propertyChecks.type))) {
121
+ if (
122
+ propertyChecks.type
123
+ && propertyValue
124
+ && (
125
+ !propertyValue.$instanceOf
126
+ || (!isArray(propertyChecks.type) && !propertyValue.$instanceOf(propertyChecks.type))
127
+ || (isArray(propertyChecks.type) && !some(propertyChecks.type, type => propertyValue.$instanceOf(type)))
128
+ )
129
+ ) {
130
+ return [
131
+ ...results,
132
+ {
133
+ message: `Property <${ propertyName }> of type <${ propertyValue.$type }> not allowed`,
134
+ path: path
135
+ ? [ ...path, propertyName ]
136
+ : [ propertyName ],
137
+ error: {
138
+ type: ERROR_TYPES.PROPERTY_TYPE_NOT_ALLOWED,
139
+ node,
140
+ parentNode: parentNode == node ? null : parentNode,
141
+ property: propertyName,
142
+ allowedPropertyType: propertyChecks.type
143
+ }
144
+ }
145
+ ];
146
+ }
147
+
148
+ if (propertyChecks.allowed === false && isDefined(propertyValue)) {
297
149
  return [
298
150
  ...results,
299
151
  {
300
- message: `Element of type <${ node.$type }> must have property <${ propertyName }> of type <${ propertyChecks.type }>`,
152
+ message: `Property <${ propertyName }> not allowed`,
301
153
  path: path
302
154
  ? [ ...path, propertyName ]
303
155
  : [ propertyName ],
304
156
  error: {
305
- type: ERROR_TYPES.PROPERTY_TYPE,
306
- propertyType: propertyChecks.type
157
+ type: ERROR_TYPES.PROPERTY_NOT_ALLOWED,
158
+ node,
159
+ parentNode: parentNode == node ? null : parentNode,
160
+ property: propertyName
307
161
  }
308
162
  }
309
163
  ];
@@ -311,349 +165,77 @@ function checkProperties(node, properties, parentNode) {
311
165
 
312
166
  return results;
313
167
  }, []);
314
- }
168
+ };
169
+
170
+ module.exports.hasExtensionElementsOfTypes = function(node, types, parentNode = null, exclusive = false) {
171
+ const extensionElements = findExtensionElements(node, types);
315
172
 
316
- module.exports.checkProperties = checkProperties;
317
-
318
- /**
319
- * @example
320
- *
321
- * const check = hasExtensionElementsOfTypes([ 'zeebe:CalledDecision', 'zeebe:TaskDefinition' ]);
322
- *
323
- * check(node, parentNode);
324
- *
325
- * @example
326
- *
327
- * const check = hasExtensionElementsOfTypes([
328
- * {
329
- * type: 'zeebe:CalledDecision',
330
- * properties: {
331
- * decisionId: { required: true },
332
- * resultVariable: { required: true }
333
- * }
334
- * },
335
- * {
336
- * type: 'zeebe:TaskDefinition',
337
- * properties: {
338
- * type: { required: true }
339
- * }
340
- * }
341
- * ]);
342
- *
343
- * check(node, parentNode);
344
- *
345
- * @param {string[]|Object[]} types
346
- *
347
- * @returns {Function}
348
- */
349
- module.exports.hasExtensionElementsOfTypes = function(types, exclusive = false) {
350
- return function(node, parentNode) {
351
- const extensionElements = findExtensionElements(node, types.map(type => getType(type)));
352
-
353
- if (!extensionElements || !extensionElements.length) {
354
- return {
355
- message: `Element of type <${ node.$type }> must have one or many extension elements of type ${ formatTypes(types, true) }`,
173
+ if (!extensionElements || !extensionElements.length) {
174
+ return [
175
+ {
176
+ message: exclusive
177
+ ? `Element of type <${ node.$type }> must have one extension element of type ${ formatTypes(types, true) }`
178
+ : `Element of type <${ node.$type }> must have one or many extension elements of type ${ formatTypes(types, true) }`,
356
179
  path: getPath(node, parentNode),
357
180
  error: {
358
181
  type: ERROR_TYPES.EXTENSION_ELEMENT_REQUIRED,
359
- requiredExtensionElement: getType(types[ 0 ])
182
+ node,
183
+ parentNode: parentNode == node ? null : parentNode,
184
+ requiredExtensionElement: types,
185
+ exclusive
360
186
  }
361
- };
362
- }
363
-
364
- if (exclusive && extensionElements.length > 1) {
365
- return {
366
- message: `Element of type <${ node.$type }> must have one extension element of type ${ formatTypes(types, true) }`,
367
- path: getPath(node, parentNode)
368
- };
369
- }
370
-
371
- const results = extensionElements.reduce((errors, extensionElement) => {
372
- const type = types.find(type => is(extensionElement, getType(type)));
373
-
374
- const properties = getProperties(type);
375
-
376
- if (properties) {
377
- return [
378
- ...errors,
379
- ...checkProperties(extensionElement, properties, parentNode)
380
- ];
381
187
  }
188
+ ];
189
+ }
382
190
 
383
- return errors;
384
- }, []);
385
-
386
- if (results.length === 1) {
387
- return results[ 0 ];
388
- } else if (results.length > 1) {
389
- return results;
390
- }
391
-
392
- return true;
393
- };
394
- };
395
-
396
- /**
397
- * @example
398
- *
399
- * const check = hasExtensionElementOfType('zeebe:TaskDefinition');
400
- *
401
- * check(node, parentNode);
402
- *
403
- * @example
404
- *
405
- * const check = hasExtensionElementOfType(
406
- * {
407
- * type: 'zeebe:TaskDefinition',
408
- * properties: {
409
- * type: { required: true }
410
- * }
411
- * }
412
- * );
413
- *
414
- * check(node, parentNode);
415
- *
416
- * @param {string[]|Object[]} types
417
- *
418
- * @returns {Function}
419
- */
420
- module.exports.hasExtensionElementOfType = function(type) {
421
- return function(node, parentNode) {
422
- const extensionElement = findExtensionElement(node, getType(type));
423
-
424
- if (!extensionElement) {
425
- return {
426
- message: `Element of type <${ node.$type }> must have extension element of type <${ getType(type) }>`,
191
+ if (exclusive && extensionElements.length > 1) {
192
+ return [
193
+ {
194
+ message: `Element of type <${ node.$type }> must have one extension element of type ${ formatTypes(types, true) }`,
427
195
  path: getPath(node, parentNode),
428
196
  error: {
429
197
  type: ERROR_TYPES.EXTENSION_ELEMENT_REQUIRED,
430
- requiredExtensionElement: getType(type)
198
+ node,
199
+ parentNode: parentNode == node ? null : parentNode,
200
+ requiredExtensionElement: types,
201
+ exclusive
431
202
  }
432
- };
433
- }
434
-
435
- const properties = getProperties(type);
436
-
437
- if (properties) {
438
- const results = checkProperties(extensionElement, properties, parentNode);
439
-
440
- if (results.length === 1) {
441
- return results[ 0 ];
442
- } else if (results.length > 1) {
443
- return results;
444
- }
445
- }
446
-
447
- return true;
448
- };
449
- };
450
-
451
- /**
452
- * @example
453
- *
454
- * const check = checkError((error) => { ... });
455
- *
456
- * check(errorEventDefinition);
457
- *
458
- * @param {Function} check
459
- *
460
- * @returns {Function}
461
- */
462
- function checkError(check) {
463
- return function(node, parentNode) {
464
- const results = checkProperties(node, {
465
- errorRef: {
466
- required: true
467
203
  }
468
- }, parentNode);
469
-
470
- if (results.length === 1) {
471
- return results[ 0 ];
472
- } else if (results.length > 1) {
473
- return results;
474
- }
475
-
476
- const error = node.get('errorRef');
477
-
478
- return check(error);
479
- };
480
- }
481
-
482
- module.exports.checkError = checkError;
483
-
484
- /**
485
- * @example
486
- *
487
- * const check = checkEventDefinition((eventDefinition, event) => { ... });
488
- *
489
- * check(startEvent);
490
- *
491
- * @param {Function} check
492
- *
493
- * @returns {Function}
494
- */
495
- module.exports.checkEventDefinition = function(check) {
496
- return function(node) {
497
- const results = checkProperties(node, {
498
- eventDefinitions: {
499
- required: true
500
- }
501
- });
502
-
503
- if (results.length === 1) {
504
- return results[ 0 ];
505
- } else if (results.length > 1) {
506
- return results;
507
- }
508
-
509
- const eventDefinitions = node.get('eventDefinitions');
510
-
511
- return check(eventDefinitions[ 0 ], node);
512
- };
513
- };
514
-
515
- /**
516
- * @example
517
- *
518
- * const check = checkFlowNode((node, parentNode) => { ... });
519
- *
520
- * check(serviceTask);
521
- *
522
- * @param {Function} check
523
- *
524
- * @returns {Function}
525
- */
526
- module.exports.checkFlowNode = function(check) {
527
- return function(node) {
528
- return check(node, node);
529
- };
530
- };
531
-
532
- /**
533
- * @example
534
- *
535
- * const check = checkMessage((message) => { ... });
536
- *
537
- * check(messageEventDefinition);
538
- *
539
- * @param {Function} check
540
- *
541
- * @returns {Function}
542
- */
543
- function checkMessage(check) {
544
- return function(node, parentNode) {
545
- const results = checkProperties(node, {
546
- messageRef: {
547
- required: true
548
- }
549
- }, parentNode);
550
-
551
- if (results.length === 1) {
552
- return results[ 0 ];
553
- } else if (results.length > 1) {
554
- return results;
555
- }
556
-
557
- const message = node.get('messageRef');
558
-
559
- return check(message);
560
- };
561
- }
562
-
563
- module.exports.checkMessage = checkMessage;
564
-
565
- /**
566
- * @example
567
- *
568
- * const check = checkLoopCharacteristics((loopCharacteristics, activity) => { ... });
569
- *
570
- * check(serviceTask);
571
- *
572
- * @param {Function} check
573
- *
574
- * @returns {Function}
575
- */
576
- module.exports.checkLoopCharacteristics = function(check) {
577
- return function(node) {
578
- const results = checkProperties(node, {
579
- loopCharacteristics: {
580
- required: true
581
- }
582
- });
583
-
584
- if (results.length === 1) {
585
- return results[ 0 ];
586
- } else if (results.length > 1) {
587
- return results;
588
- }
589
-
590
- const loopCharacteristics = node.get('loopCharacteristics');
204
+ ];
205
+ }
591
206
 
592
- return check(loopCharacteristics, node);
593
- };
207
+ return [];
594
208
  };
595
209
 
596
- module.exports.hasErrorReference = checkError(
597
- (node) => {
598
- const results = checkProperties(node, {
599
- errorCode: {
600
- required: true
601
- }
602
- });
210
+ module.exports.hasExtensionElementOfType = function(node, type, parentNode = null) {
211
+ const extensionElement = findExtensionElement(node, type);
603
212
 
604
- if (results.length === 1) {
605
- return results[ 0 ];
606
- } else if (results.length > 1) {
607
- return results;
608
- }
609
-
610
- return true;
611
- }
612
- );
613
-
614
- module.exports.hasMessageReference = checkMessage(
615
- (node) => {
616
- const results = checkProperties(node, {
617
- name: {
618
- required: true
213
+ if (!extensionElement) {
214
+ return [
215
+ {
216
+ message: `Element of type <${ node.$type }> must have extension element of type <${ type }>`,
217
+ path: getPath(node, parentNode),
218
+ error: {
219
+ type: ERROR_TYPES.EXTENSION_ELEMENT_REQUIRED,
220
+ node,
221
+ parentNode: parentNode == node ? null : parentNode,
222
+ requiredExtensionElement: type
223
+ }
619
224
  }
620
- });
621
-
622
- if (results.length === 1) {
623
- return results[ 0 ];
624
- } else if (results.length > 1) {
625
- return results;
626
- }
627
-
628
- return true;
225
+ ];
629
226
  }
630
- );
631
227
 
632
- function translate(result, translations) {
633
- if (isString(result)) {
634
- return translations[result] || result;
635
- }
228
+ return [];
229
+ };
636
230
 
637
- const { message } = result;
231
+ function isExactly(node, type) {
232
+ const { $model } = node;
638
233
 
639
- return {
640
- ...result,
641
- message: translations[message] || message
642
- };
234
+ return $model.getType(node.$type) === $model.getType(type);
643
235
  }
644
236
 
645
- module.exports.withTranslations = function(check, translations) {
646
- return function(node) {
647
- const results = check(node);
237
+ module.exports.isExactly = isExactly;
648
238
 
649
- if (isObject(results) || isString(results)) {
650
- return translate(results, translations);
651
- }
652
-
653
- if (isArray(results)) {
654
- return results.map((result) => translate(result, translations));
655
- }
656
-
657
- return results;
658
- };
239
+ module.exports.isAnyExactly = function(node, types) {
240
+ return some(types, (type) => isExactly(node, type));
659
241
  };
@@ -0,0 +1,9 @@
1
+ module.exports.ERROR_TYPES = Object.freeze({
2
+ ELEMENT_TYPE_NOT_ALLOWED: 'elementTypeNotAllowed',
3
+ EXTENSION_ELEMENT_NOT_ALLOWED: 'extensionElementNotAllowed',
4
+ EXTENSION_ELEMENT_REQUIRED: 'extensionElementRequired',
5
+ PROPERTY_DEPENDEND_REQUIRED: 'propertyDependendRequired',
6
+ PROPERTY_NOT_ALLOWED: 'propertyNotAllowed',
7
+ PROPERTY_REQUIRED: 'propertyRequired',
8
+ PROPERTY_TYPE_NOT_ALLOWED: 'propertyTypeNotAllowed'
9
+ });