bpmnlint-plugin-camunda-compat 0.2.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
 
14
- module.exports.createRule = function(ruleExecutionPlatform, ruleExecutionPlatformVersion, checks) {
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
+ */
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,161 +44,208 @@ 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 ${ 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 ${ 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
 
46
82
  /**
83
+ * Create no-op rule that always returns false resulting in early return.
84
+ *
85
+ * @returns {Function}
86
+ */
87
+ module.exports.createNoopRule = function() {
88
+ return () => {
89
+ return {
90
+ check: () => false
91
+ };
92
+ };
93
+ };
94
+
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
+ *
47
99
  * @param {ModdleElement} node
48
100
  * @param {Array<Function>} checks
49
101
  *
50
- * @returns boolean|String
102
+ * @returns {boolean|Object|Object[]|string|string[]}
51
103
  */
52
104
  function checkNode(node, checks) {
53
- return checks.reduce((previousResult, check) => {
54
- if (previousResult === true) {
55
- return previousResult;
56
- }
105
+ const results = checks.map((check) => {
57
106
 
58
107
  // (1) check using type only
59
108
  if (isString(check)) {
60
- return is(node, check) || previousResult;
109
+ return is(node, check);
61
110
  }
62
111
 
63
112
  const { type } = check;
64
113
 
65
114
  // (2) check using function only
66
115
  if (!type) {
67
- return check.check(node) || previousResult;
116
+ return check.check(node);
68
117
  }
69
118
 
70
119
  // (3) check using type and function
71
120
  if (!is(node, type)) {
72
- return previousResult;
121
+ return false;
73
122
  }
74
123
 
75
- return check.check(node) || previousResult;
76
- }, false);
124
+ return check.check(node);
125
+ });
126
+
127
+ return results.find((result) => result === true) || getErrors(results);
77
128
  }
78
129
 
130
+ module.exports.checkNode = checkNode;
131
+
79
132
  /**
80
- * If every check returns true return true.
81
- * 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.
82
135
  *
83
136
  * @param {Array<Function>} checks
84
137
  *
85
- * @returns {boolean|String}
138
+ * @returns {boolean|Object|Object[]|string|string[]}
86
139
  */
87
140
  module.exports.checkEvery = function(...checks) {
88
141
  return function(node) {
89
- return checks.reduce((previousResult, check) => {
90
- if (!isNil(previousResult) && previousResult !== true) {
91
- return previousResult;
92
- }
93
-
94
- const result = check(node);
142
+ const results = checks.map((check) => check(node));
95
143
 
96
- return result;
97
- }, null);
144
+ return every(results, result => result === true) || getErrors(results);
98
145
  };
99
- }
146
+ };
100
147
 
101
148
  /**
102
- * If some check returns true return true.
103
- * 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.
104
151
  *
105
152
  * @param {Array<Function>} checks
106
153
  *
107
- * @returns {boolean|String}
154
+ * @returns {boolean|Object|Object[]|string|string[]}
108
155
  */
109
156
  module.exports.checkSome = function(...checks) {
110
157
  return function(node) {
111
- return checks.reduce((previousResult, check) => {
112
- if (previousResult === true) {
113
- return previousResult;
114
- }
158
+ const results = checks.map((check) => check(node));
115
159
 
116
- const result = check(node);
117
-
118
- if (isNil(previousResult) || result === true) {
119
- return result;
120
- }
121
-
122
- return previousResult;
123
- }, null);
160
+ return some(results, result => result === true) || getErrors(results);
124
161
  };
125
- }
162
+ };
126
163
 
127
- module.exports.hasEventDefinition = function(node) {
128
- const eventDefinitions = node.get('eventDefinitions');
129
-
130
- return eventDefinitions && eventDefinitions.length === 1;
131
- }
132
-
133
- module.exports.hasNoEventDefinition = function(node) {
134
- const eventDefinitions = node.get('eventDefinitions');
135
-
136
- return !eventDefinitions || !eventDefinitions.length || `${ node.$type} (${ eventDefinitions[ 0 ].$type })`;
137
- }
138
-
139
- module.exports.hasEventDefinitionOfType = function(types) {
140
- return function(node) {
141
- if (!isArray(types)) {
142
- 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
143
178
  }
179
+ ]);
180
+ };
144
181
 
145
- 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);
146
186
 
147
- if (!eventDefinitions || eventDefinitions.length !== 1) {
148
- return false;
187
+ if (replacement) {
188
+ return {
189
+ check: replacement.check,
190
+ type: check
191
+ };
192
+ }
149
193
  }
150
194
 
151
- const eventDefinition = eventDefinitions[ 0 ];
152
-
153
- return isAny(eventDefinition, types) || `${ node.$type} (${ eventDefinition.$type })`;
154
- };
155
- }
156
-
157
- module.exports.hasLoopCharacteristics = function(node) {
158
- const loopCharacteristics = node.get('loopCharacteristics');
159
-
160
- return !!loopCharacteristics;
161
- }
195
+ if (check.type) {
196
+ const replacement = replacements.find((replacement) => check.type === replacement.type);
162
197
 
163
- module.exports.hasNoLoopCharacteristics = function(node) {
164
- const loopCharacteristics = node.get('loopCharacteristics');
198
+ if (replacement) {
199
+ return {
200
+ ...check,
201
+ check: replacement.check
202
+ };
203
+ }
204
+ }
165
205
 
166
- return !loopCharacteristics || `${ node.$type} (${ loopCharacteristics.$type })`;
206
+ return check;
207
+ });
167
208
  }
168
209
 
169
- module.exports.hasNoLanes = function(node) {
170
- const laneSets = node.get('laneSets');
210
+ module.exports.replaceChecks = replaceChecks;
171
211
 
172
- 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);
173
216
  }
174
217
 
175
- module.exports.hasLoopCharacteristicsOfType = function(type) {
176
- return function(node) {
177
- 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
+ }
178
233
 
179
- if (!loopCharacteristics) {
180
- return false;
234
+ if (isObject(result) || isString(result)) {
235
+ return [
236
+ ...errors,
237
+ result
238
+ ];
181
239
  }
182
240
 
183
- return is(loopCharacteristics, type) || `${ node.$type} (${ loopCharacteristics.$type })`;
184
- };
185
- }
241
+ return errors;
242
+ }, []);
243
+
244
+ if (errors.length === 1) {
245
+ return errors[ 0 ];
246
+ } else if (errors.length > 1) {
247
+ return errors;
248
+ }
186
249
 
187
- module.exports.isNotBpmn = function(node) {
188
- return !is(node, 'bpmn:BaseElement');
250
+ return false;
189
251
  }