bpmnlint-plugin-camunda-compat 0.6.1 → 0.7.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,148 +1,24 @@
1
1
  const {
2
2
  isArray,
3
- isObject,
4
- isString,
5
3
  some
6
4
  } = require('min-dash');
7
5
 
8
- const {
9
- is,
10
- isAny
11
- } = require('bpmnlint-utils');
6
+ const { isAny } = require('bpmnlint-utils');
12
7
 
13
8
  const { getPath } = require('@philippfromme/moddle-helpers');
14
9
 
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
- });
10
+ const { ERROR_TYPES } = require('./error-types');
22
11
 
23
12
  module.exports.ERROR_TYPES = ERROR_TYPES;
24
13
 
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
-
14
+ module.exports.getEventDefinition = function(node) {
51
15
  const eventDefinitions = node.get('eventDefinitions');
52
16
 
53
- if (!eventDefinitions || eventDefinitions.length !== 1) {
54
- return getElementNotSupportedError(node.$type, null);
17
+ if (eventDefinitions) {
18
+ return eventDefinitions[ 0 ];
55
19
  }
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
20
  };
90
21
 
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;
129
- }
130
-
131
- return true;
132
- };
133
-
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
22
  function findExtensionElements(node, types) {
147
23
  const extensionElements = node.get('extensionElements');
148
24
 
@@ -163,75 +39,18 @@ function findExtensionElements(node, types) {
163
39
  return values.filter(value => isAny(value, types));
164
40
  }
165
41
 
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
- }
42
+ function findExtensionElement(node, types) {
43
+ const extensionElements = findExtensionElements(node, types);
203
44
 
204
- /**
205
- * @param {string|Object} type
206
- *
207
- * @returns {string|Object}
208
- */
209
- function getProperties(type) {
210
- if (isObject(type)) {
211
- return type.properties;
45
+ if (extensionElements && extensionElements.length) {
46
+ return extensionElements[ 0 ];
212
47
  }
213
48
  }
214
49
 
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
- };
50
+ module.exports.findExtensionElement = findExtensionElement;
231
51
 
232
52
  function formatTypes(types, exclusive = false) {
233
53
  return types.reduce((string, type, index) => {
234
- type = getType(type);
235
54
 
236
55
  // first
237
56
  if (index === 0) {
@@ -249,7 +68,7 @@ function formatTypes(types, exclusive = false) {
249
68
 
250
69
  module.exports.formatTypes = formatTypes;
251
70
 
252
- function checkProperties(node, properties, parentNode) {
71
+ module.exports.hasProperties = function(node, properties, parentNode = null) {
253
72
  return Object.entries(properties).reduce((results, property) => {
254
73
  const [ propertyName, propertyChecks ] = property;
255
74
 
@@ -267,6 +86,8 @@ function checkProperties(node, properties, parentNode) {
267
86
  : [ propertyName ],
268
87
  error: {
269
88
  type: ERROR_TYPES.PROPERTY_REQUIRED,
89
+ node,
90
+ parentNode: parentNode == node ? null : parentNode,
270
91
  requiredProperty: propertyName
271
92
  }
272
93
  }
@@ -286,6 +107,9 @@ function checkProperties(node, properties, parentNode) {
286
107
  : [ propertyName ],
287
108
  error: {
288
109
  type: ERROR_TYPES.PROPERTY_DEPENDEND_REQUIRED,
110
+ node,
111
+ parentNode: parentNode == node ? null : parentNode,
112
+ property: propertyChecks.dependendRequired,
289
113
  dependendRequiredProperty: propertyName
290
114
  }
291
115
  }
@@ -293,17 +117,28 @@ function checkProperties(node, properties, parentNode) {
293
117
  }
294
118
  }
295
119
 
296
- if (propertyChecks.type && propertyValue && (!propertyValue.$instanceOf || !propertyValue.$instanceOf(propertyChecks.type))) {
120
+ if (
121
+ propertyChecks.type
122
+ && propertyValue
123
+ && (
124
+ !propertyValue.$instanceOf
125
+ || (!isArray(propertyChecks.type) && !propertyValue.$instanceOf(propertyChecks.type))
126
+ || (isArray(propertyChecks.type) && !some(propertyChecks.type, type => propertyValue.$instanceOf(type)))
127
+ )
128
+ ) {
297
129
  return [
298
130
  ...results,
299
131
  {
300
- message: `Element of type <${ node.$type }> must have property <${ propertyName }> of type <${ propertyChecks.type }>`,
132
+ message: `Property <${ propertyName }> of type <${ propertyValue.$type }> not allowed`,
301
133
  path: path
302
134
  ? [ ...path, propertyName ]
303
135
  : [ propertyName ],
304
136
  error: {
305
- type: ERROR_TYPES.PROPERTY_TYPE,
306
- propertyType: propertyChecks.type
137
+ type: ERROR_TYPES.PROPERTY_TYPE_NOT_ALLOWED,
138
+ node,
139
+ parentNode: parentNode == node ? null : parentNode,
140
+ property: propertyName,
141
+ allowedPropertyType: propertyChecks.type
307
142
  }
308
143
  }
309
144
  ];
@@ -311,349 +146,77 @@ function checkProperties(node, properties, parentNode) {
311
146
 
312
147
  return results;
313
148
  }, []);
314
- }
149
+ };
150
+
151
+ module.exports.hasExtensionElementsOfTypes = function(node, types, parentNode = null, exclusive = false) {
152
+ const extensionElements = findExtensionElements(node, types);
315
153
 
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) }`,
154
+ if (!extensionElements || !extensionElements.length) {
155
+ return [
156
+ {
157
+ message: exclusive
158
+ ? `Element of type <${ node.$type }> must have one extension element of type ${ formatTypes(types, true) }`
159
+ : `Element of type <${ node.$type }> must have one or many extension elements of type ${ formatTypes(types, true) }`,
356
160
  path: getPath(node, parentNode),
357
161
  error: {
358
162
  type: ERROR_TYPES.EXTENSION_ELEMENT_REQUIRED,
359
- requiredExtensionElement: getType(types[ 0 ])
163
+ node,
164
+ parentNode: parentNode == node ? null : parentNode,
165
+ requiredExtensionElement: types,
166
+ exclusive
360
167
  }
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
168
  }
169
+ ];
170
+ }
382
171
 
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) }>`,
172
+ if (exclusive && extensionElements.length > 1) {
173
+ return [
174
+ {
175
+ message: `Element of type <${ node.$type }> must have one extension element of type ${ formatTypes(types, true) }`,
427
176
  path: getPath(node, parentNode),
428
177
  error: {
429
178
  type: ERROR_TYPES.EXTENSION_ELEMENT_REQUIRED,
430
- requiredExtensionElement: getType(type)
179
+ node,
180
+ parentNode: parentNode == node ? null : parentNode,
181
+ requiredExtensionElement: types,
182
+ exclusive
431
183
  }
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
184
  }
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
- }
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');
185
+ ];
186
+ }
591
187
 
592
- return check(loopCharacteristics, node);
593
- };
188
+ return [];
594
189
  };
595
190
 
596
- module.exports.hasErrorReference = checkError(
597
- (node) => {
598
- const results = checkProperties(node, {
599
- errorCode: {
600
- required: true
601
- }
602
- });
603
-
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
- );
191
+ module.exports.hasExtensionElementOfType = function(node, type, parentNode = null) {
192
+ const extensionElement = findExtensionElement(node, type);
613
193
 
614
- module.exports.hasMessageReference = checkMessage(
615
- (node) => {
616
- const results = checkProperties(node, {
617
- name: {
618
- required: true
194
+ if (!extensionElement) {
195
+ return [
196
+ {
197
+ message: `Element of type <${ node.$type }> must have extension element of type <${ type }>`,
198
+ path: getPath(node, parentNode),
199
+ error: {
200
+ type: ERROR_TYPES.EXTENSION_ELEMENT_REQUIRED,
201
+ node,
202
+ parentNode: parentNode == node ? null : parentNode,
203
+ requiredExtensionElement: type
204
+ }
619
205
  }
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;
206
+ ];
629
207
  }
630
- );
631
208
 
632
- function translate(result, translations) {
633
- if (isString(result)) {
634
- return translations[result] || result;
635
- }
209
+ return [];
210
+ };
636
211
 
637
- const { message } = result;
212
+ function isExactly(node, type) {
213
+ const { $model } = node;
638
214
 
639
- return {
640
- ...result,
641
- message: translations[message] || message
642
- };
215
+ return $model.getType(node.$type) === $model.getType(type);
643
216
  }
644
217
 
645
- module.exports.withTranslations = function(check, translations) {
646
- return function(node) {
647
- const results = check(node);
648
-
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
- }
218
+ module.exports.isExactly = isExactly;
656
219
 
657
- return results;
658
- };
220
+ module.exports.isAnyExactly = function(node, types) {
221
+ return some(types, (type) => isExactly(node, type));
659
222
  };
@@ -0,0 +1,8 @@
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_REQUIRED: 'propertyRequired',
7
+ PROPERTY_TYPE_NOT_ALLOWED: 'propertyTypeNotAllowed'
8
+ });
@@ -0,0 +1,11 @@
1
+ const { isArray } = require('min-dash');
2
+
3
+ module.exports.reportErrors = function(node, reporter, errors) {
4
+ if (!isArray(errors)) {
5
+ errors = [ errors ];
6
+ }
7
+
8
+ errors.forEach(({ message, ...options }) => {
9
+ reporter.report(node.get('id'), message, options);
10
+ });
11
+ };