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