bpmnlint-plugin-camunda-compat 0.4.0 → 0.5.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,7 +1,9 @@
1
1
  const {
2
+ every,
2
3
  isArray,
3
- isNil,
4
+ isObject,
4
5
  isString,
6
+ some
5
7
  } = require('min-dash');
6
8
 
7
9
  const {
@@ -11,13 +13,26 @@ const {
11
13
 
12
14
  const { toSemverMinor } = require('./engine-profile');
13
15
 
16
+ /**
17
+ * Factory function for rules. Returns a rule for a given execution platform,
18
+ * execution platform version and an array of checks. Must be run on
19
+ * bpmn:Definitions node. Returns early without traversing further if execution
20
+ * platform or execution platform version doesn't match. Returns early if node
21
+ * is not a bpmn:FlowElement or bpmn:FlowElementContainer.
22
+ *
23
+ * @param {string} ruleExecutionPlatform
24
+ * @param {string} ruleExecutionPlatformVersion
25
+ * @param {(Object|string)[]} checks
26
+ *
27
+ * @returns {Function}
28
+ */
14
29
  module.exports.createRule = function(ruleExecutionPlatform, ruleExecutionPlatformVersion, checks, executionPlatformLabel) {
15
30
  return () => {
16
31
  return {
17
32
  check: (node, reporter) => {
18
33
  if (is(node, 'bpmn:Definitions')) {
19
- executionPlatform = node.get('modeler:executionPlatform');
20
- executionPlatformVersion = node.get('modeler:executionPlatformVersion');
34
+ const executionPlatform = node.get('modeler:executionPlatform');
35
+ const executionPlatformVersion = node.get('modeler:executionPlatformVersion');
21
36
 
22
37
  if (!executionPlatform
23
38
  || executionPlatform !== ruleExecutionPlatform
@@ -29,20 +44,46 @@ module.exports.createRule = function(ruleExecutionPlatform, ruleExecutionPlatfor
29
44
  return;
30
45
  }
31
46
 
32
- const result = checkNode(node, checks);
47
+ let results = checkNode(node, checks);
33
48
 
34
- if (result === false) {
35
- reporter.report(node.get('id') || '', `Element of type <${ node.$type }> not supported by ${ executionPlatformLabel || ruleExecutionPlatform } ${ toSemverMinor(ruleExecutionPlatformVersion) }`);
49
+ if (results === true) {
50
+ return;
36
51
  }
37
52
 
38
- if (isString(result)) {
39
- reporter.report(node.get('id') || '', `Element of type <${ result }> not supported by ${ executionPlatformLabel || ruleExecutionPlatform } ${ toSemverMinor(ruleExecutionPlatformVersion) }`);
53
+ const id = node.get('id') || '';
54
+
55
+ if (results === false) {
56
+ reporter.report(id, `Element of type <${ node.$type }> not supported by ${ executionPlatformLabel || ruleExecutionPlatform } ${ toSemverMinor(ruleExecutionPlatformVersion) }`);
57
+ } else {
58
+ if (!isArray(results)) {
59
+ results = [ results ];
60
+ }
61
+
62
+ results.forEach((result) => {
63
+ if (isString(result)) {
64
+ result = { message: result };
65
+ }
66
+
67
+ let {
68
+ message,
69
+ ...rest
70
+ } = result;
71
+
72
+ message = addExecutionPlatform(message, executionPlatformLabel || ruleExecutionPlatform, toSemverMinor(ruleExecutionPlatformVersion));
73
+
74
+ reporter.report(id, message, rest);
75
+ });
40
76
  }
41
77
  }
42
78
  };
43
79
  };
44
80
  };
45
81
 
82
+ /**
83
+ * Create no-op rule that always returns false resulting in early return.
84
+ *
85
+ * @returns {Function}
86
+ */
46
87
  module.exports.createNoopRule = function() {
47
88
  return () => {
48
89
  return {
@@ -52,146 +93,159 @@ module.exports.createNoopRule = function() {
52
93
  };
53
94
 
54
95
  /**
96
+ * Run checks on a node. Return true if at least one of the checks returns true.
97
+ * Otherwise return all errors or false.
98
+ *
55
99
  * @param {ModdleElement} node
56
100
  * @param {Array<Function>} checks
57
101
  *
58
- * @returns boolean|String
102
+ * @returns {boolean|Object|Object[]|string|string[]}
59
103
  */
60
104
  function checkNode(node, checks) {
61
- return checks.reduce((previousResult, check) => {
62
- if (previousResult === true) {
63
- return previousResult;
64
- }
105
+ const results = checks.map((check) => {
65
106
 
66
107
  // (1) check using type only
67
108
  if (isString(check)) {
68
- return is(node, check) || previousResult;
109
+ return is(node, check);
69
110
  }
70
111
 
71
112
  const { type } = check;
72
113
 
73
114
  // (2) check using function only
74
115
  if (!type) {
75
- return check.check(node) || previousResult;
116
+ return check.check(node);
76
117
  }
77
118
 
78
119
  // (3) check using type and function
79
120
  if (!is(node, type)) {
80
- return previousResult;
121
+ return false;
81
122
  }
82
123
 
83
- return check.check(node) || previousResult;
84
- }, false);
124
+ return check.check(node);
125
+ });
126
+
127
+ return results.find((result) => result === true) || getErrors(results);
85
128
  }
86
129
 
130
+ module.exports.checkNode = checkNode;
131
+
87
132
  /**
88
- * If every check returns true return true.
89
- * Otherwise return the first false or string returned by a check.
133
+ * Create function that runs checks on a node. Return true if all checks return
134
+ * true. Otherwise return all errors or false.
90
135
  *
91
136
  * @param {Array<Function>} checks
92
137
  *
93
- * @returns {boolean|String}
138
+ * @returns {boolean|Object|Object[]|string|string[]}
94
139
  */
95
140
  module.exports.checkEvery = function(...checks) {
96
141
  return function(node) {
97
- return checks.reduce((previousResult, check) => {
98
- if (!isNil(previousResult) && previousResult !== true) {
99
- return previousResult;
100
- }
142
+ const results = checks.map((check) => check(node));
101
143
 
102
- const result = check(node);
103
-
104
- return result;
105
- }, null);
144
+ return every(results, result => result === true) || getErrors(results);
106
145
  };
107
- }
146
+ };
108
147
 
109
148
  /**
110
- * If some check returns true return true.
111
- * Otherwise return the first false or string returned by a check.
149
+ * Create function that runs checks on a node. Return true if at least one of
150
+ * the checks returns true. Otherwise return all errors or false.
112
151
  *
113
152
  * @param {Array<Function>} checks
114
153
  *
115
- * @returns {boolean|String}
154
+ * @returns {boolean|Object|Object[]|string|string[]}
116
155
  */
117
156
  module.exports.checkSome = function(...checks) {
118
157
  return function(node) {
119
- return checks.reduce((previousResult, check) => {
120
- if (previousResult === true) {
121
- return previousResult;
122
- }
158
+ const results = checks.map((check) => check(node));
123
159
 
124
- const result = check(node);
125
-
126
- if (isNil(previousResult) || result === true) {
127
- return result;
128
- }
129
-
130
- return previousResult;
131
- }, null);
160
+ return some(results, result => result === true) || getErrors(results);
132
161
  };
133
- }
134
-
135
- module.exports.hasEventDefinition = function(node) {
136
- const eventDefinitions = node.get('eventDefinitions');
137
-
138
- return eventDefinitions && eventDefinitions.length === 1;
139
- }
140
-
141
- module.exports.hasNoEventDefinition = function(node) {
142
- const eventDefinitions = node.get('eventDefinitions');
143
-
144
- return !eventDefinitions || !eventDefinitions.length || `${ node.$type} (${ eventDefinitions[ 0 ].$type })`;
145
- }
162
+ };
146
163
 
147
- module.exports.hasEventDefinitionOfType = function(types) {
148
- return function(node) {
149
- if (!isArray(types)) {
150
- types = [ types ];
164
+ /**
165
+ * Replace check for element of type.
166
+ *
167
+ * @param {(Object|string)[]} checks
168
+ * @param {string} type
169
+ * @param {Function} check
170
+ *
171
+ * @returns {(Object|string)[]}
172
+ */
173
+ module.exports.replaceCheck = function(checks, type, check) {
174
+ return replaceChecks(checks, [
175
+ {
176
+ type,
177
+ check
151
178
  }
179
+ ]);
180
+ };
152
181
 
153
- const eventDefinitions = node.get('eventDefinitions');
182
+ function replaceChecks(checks, replacements) {
183
+ return checks.map((check) => {
184
+ if (isString(check)) {
185
+ const replacement = replacements.find((replacement) => check === replacement.type);
154
186
 
155
- if (!eventDefinitions || eventDefinitions.length !== 1) {
156
- return false;
187
+ if (replacement) {
188
+ return {
189
+ check: replacement.check,
190
+ type: check
191
+ };
192
+ }
157
193
  }
158
194
 
159
- const eventDefinition = eventDefinitions[ 0 ];
160
-
161
- return isAny(eventDefinition, types) || `${ node.$type} (${ eventDefinition.$type })`;
162
- };
163
- }
195
+ if (check.type) {
196
+ const replacement = replacements.find((replacement) => check.type === replacement.type);
164
197
 
165
- module.exports.hasLoopCharacteristics = function(node) {
166
- const loopCharacteristics = node.get('loopCharacteristics');
167
-
168
- return !!loopCharacteristics;
169
- }
170
-
171
- module.exports.hasNoLoopCharacteristics = function(node) {
172
- const loopCharacteristics = node.get('loopCharacteristics');
198
+ if (replacement) {
199
+ return {
200
+ ...check,
201
+ check: replacement.check
202
+ };
203
+ }
204
+ }
173
205
 
174
- return !loopCharacteristics || `${ node.$type} (${ loopCharacteristics.$type })`;
206
+ return check;
207
+ });
175
208
  }
176
209
 
177
- module.exports.hasNoLanes = function(node) {
178
- const laneSets = node.get('laneSets');
210
+ module.exports.replaceChecks = replaceChecks;
179
211
 
180
- return !laneSets || !laneSets.length || `${ node.$type} (bpmn:LaneSet)`;
212
+ function addExecutionPlatform(string, executionPlatform, executionPlatformVersion) {
213
+ return string
214
+ .replace('{{ executionPlatform }}', executionPlatform)
215
+ .replace('{{ executionPlatformVersion }}', executionPlatformVersion);
181
216
  }
182
217
 
183
- module.exports.hasLoopCharacteristicsOfType = function(type) {
184
- return function(node) {
185
- const loopCharacteristics = node.get('loopCharacteristics');
218
+ /**
219
+ * Return all errors or false.
220
+ *
221
+ * @param {(boolean|Object|string)[]} result
222
+ *
223
+ * @returns {boolean|(Object|string)[]}
224
+ */
225
+ function getErrors(results) {
226
+ const errors = results.reduce((errors, result) => {
227
+ if (isArray(result)) {
228
+ return [
229
+ ...errors,
230
+ ...result
231
+ ];
232
+ }
186
233
 
187
- if (!loopCharacteristics) {
188
- return false;
234
+ if (isObject(result) || isString(result)) {
235
+ return [
236
+ ...errors,
237
+ result
238
+ ];
189
239
  }
190
240
 
191
- return is(loopCharacteristics, type) || `${ node.$type} (${ loopCharacteristics.$type })`;
192
- };
193
- }
241
+ return errors;
242
+ }, []);
243
+
244
+ if (errors.length === 1) {
245
+ return errors[ 0 ];
246
+ } else if (errors.length > 1) {
247
+ return errors;
248
+ }
194
249
 
195
- module.exports.isNotBpmn = function(node) {
196
- return !is(node, 'bpmn:BaseElement');
250
+ return false;
197
251
  }