bpmnlint-plugin-camunda-compat 0.3.0 → 0.6.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.
- package/CHANGELOG.md +26 -0
- package/index.js +4 -4
- package/package.json +12 -4
- package/rules/camunda-cloud-1-0-checks.js +189 -41
- package/rules/camunda-cloud-1-0.js +1 -1
- package/rules/camunda-cloud-1-1-checks.js +62 -17
- package/rules/camunda-cloud-1-1.js +1 -1
- package/rules/camunda-cloud-1-2-checks.js +56 -15
- package/rules/camunda-cloud-1-2.js +1 -1
- package/rules/camunda-cloud-1-3-checks.js +33 -1
- package/rules/camunda-cloud-1-3.js +1 -1
- package/rules/{camunda-cloud-1-4-checks.js → camunda-cloud-8-0-checks.js} +0 -0
- package/rules/camunda-cloud-8-0.js +5 -0
- package/rules/utils/cloud/element.js +105 -0
- package/rules/utils/element.js +667 -0
- package/rules/utils/engine-profile.js +1 -1
- package/rules/utils/rule.js +212 -85
- package/rules/utils/type.js +47 -0
- package/rules/camunda-cloud-1-4.js +0 -5
package/rules/utils/rule.js
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
const {
|
2
|
+
every,
|
2
3
|
isArray,
|
3
|
-
|
4
|
+
isObject,
|
4
5
|
isString,
|
6
|
+
some
|
5
7
|
} = require('min-dash');
|
6
8
|
|
7
9
|
const {
|
@@ -11,13 +13,31 @@ const {
|
|
11
13
|
|
12
14
|
const { toSemverMinor } = require('./engine-profile');
|
13
15
|
|
14
|
-
|
16
|
+
const { ERROR_TYPES } = require('./element');
|
17
|
+
|
18
|
+
const { getTypeString } = require('./type');
|
19
|
+
|
20
|
+
/**
|
21
|
+
* Factory function for rules. Returns a rule for a given execution platform,
|
22
|
+
* execution platform version and an array of checks. Must be run on
|
23
|
+
* bpmn:Definitions node. Returns early without traversing further if execution
|
24
|
+
* platform or execution platform version doesn't match. Returns early if node
|
25
|
+
* is not a bpmn:FlowElement or bpmn:FlowElementContainer.
|
26
|
+
*
|
27
|
+
* @param {string} ruleExecutionPlatform
|
28
|
+
* @param {string} ruleExecutionPlatformVersion
|
29
|
+
* @param {(Object|string)[]} checks
|
30
|
+
* @param {string} executionPlatformLabel
|
31
|
+
*
|
32
|
+
* @returns {Function}
|
33
|
+
*/
|
34
|
+
module.exports.createRule = function(ruleExecutionPlatform, ruleExecutionPlatformVersion, checks, executionPlatformLabel) {
|
15
35
|
return () => {
|
16
36
|
return {
|
17
37
|
check: (node, reporter) => {
|
18
38
|
if (is(node, 'bpmn:Definitions')) {
|
19
|
-
executionPlatform = node.get('modeler:executionPlatform');
|
20
|
-
executionPlatformVersion = node.get('modeler:executionPlatformVersion');
|
39
|
+
const executionPlatform = node.get('modeler:executionPlatform');
|
40
|
+
const executionPlatformVersion = node.get('modeler:executionPlatformVersion');
|
21
41
|
|
22
42
|
if (!executionPlatform
|
23
43
|
|| executionPlatform !== ruleExecutionPlatform
|
@@ -29,20 +49,75 @@ module.exports.createRule = function(ruleExecutionPlatform, ruleExecutionPlatfor
|
|
29
49
|
return;
|
30
50
|
}
|
31
51
|
|
32
|
-
|
52
|
+
let results = checkNode(node, checks);
|
33
53
|
|
34
|
-
if (
|
35
|
-
|
54
|
+
if (results === true) {
|
55
|
+
return;
|
36
56
|
}
|
37
57
|
|
38
|
-
|
39
|
-
|
58
|
+
const id = node.get('id') || '';
|
59
|
+
|
60
|
+
const label = getLabel(node);
|
61
|
+
|
62
|
+
if (results === false) {
|
63
|
+
const message = getMessage(node, ruleExecutionPlatform, ruleExecutionPlatformVersion, executionPlatformLabel);
|
64
|
+
|
65
|
+
let options = {
|
66
|
+
error: {
|
67
|
+
type: ERROR_TYPES.ELEMENT_TYPE,
|
68
|
+
element: node.$type
|
69
|
+
}
|
70
|
+
};
|
71
|
+
|
72
|
+
if (label) {
|
73
|
+
options = {
|
74
|
+
...options,
|
75
|
+
label
|
76
|
+
};
|
77
|
+
}
|
78
|
+
|
79
|
+
reporter.report(id, message, options);
|
80
|
+
} else {
|
81
|
+
if (!isArray(results)) {
|
82
|
+
results = [ results ];
|
83
|
+
}
|
84
|
+
|
85
|
+
results.forEach((result) => {
|
86
|
+
if (isString(result)) {
|
87
|
+
result = { message: result };
|
88
|
+
}
|
89
|
+
|
90
|
+
let {
|
91
|
+
message,
|
92
|
+
...rest
|
93
|
+
} = result;
|
94
|
+
|
95
|
+
message = addExecutionPlatform(message, executionPlatformLabel || `${ ruleExecutionPlatform } ${ toSemverMinor(ruleExecutionPlatformVersion) }`);
|
96
|
+
|
97
|
+
let options = {
|
98
|
+
...rest
|
99
|
+
};
|
100
|
+
|
101
|
+
if (label) {
|
102
|
+
options = {
|
103
|
+
...options,
|
104
|
+
label
|
105
|
+
};
|
106
|
+
}
|
107
|
+
|
108
|
+
reporter.report(id, message, options);
|
109
|
+
});
|
40
110
|
}
|
41
111
|
}
|
42
112
|
};
|
43
113
|
};
|
44
114
|
};
|
45
115
|
|
116
|
+
/**
|
117
|
+
* Create no-op rule that always returns false resulting in early return.
|
118
|
+
*
|
119
|
+
* @returns {Function}
|
120
|
+
*/
|
46
121
|
module.exports.createNoopRule = function() {
|
47
122
|
return () => {
|
48
123
|
return {
|
@@ -52,146 +127,198 @@ module.exports.createNoopRule = function() {
|
|
52
127
|
};
|
53
128
|
|
54
129
|
/**
|
130
|
+
* Run checks on a node. Return true if at least one of the checks returns true.
|
131
|
+
* Otherwise return all errors or false.
|
132
|
+
*
|
55
133
|
* @param {ModdleElement} node
|
56
134
|
* @param {Array<Function>} checks
|
57
135
|
*
|
58
|
-
* @returns boolean|
|
136
|
+
* @returns {boolean|Object|Object[]|string|string[]}
|
59
137
|
*/
|
60
138
|
function checkNode(node, checks) {
|
61
|
-
|
62
|
-
if (previousResult === true) {
|
63
|
-
return previousResult;
|
64
|
-
}
|
139
|
+
const results = checks.map((check) => {
|
65
140
|
|
66
141
|
// (1) check using type only
|
67
142
|
if (isString(check)) {
|
68
|
-
return
|
143
|
+
return isExactly(node, check);
|
69
144
|
}
|
70
145
|
|
71
146
|
const { type } = check;
|
72
147
|
|
73
148
|
// (2) check using function only
|
74
149
|
if (!type) {
|
75
|
-
return check.check(node)
|
150
|
+
return check.check(node);
|
76
151
|
}
|
77
152
|
|
78
153
|
// (3) check using type and function
|
79
|
-
if (!
|
80
|
-
return
|
154
|
+
if (!isExactly(node, type)) {
|
155
|
+
return false;
|
81
156
|
}
|
82
157
|
|
83
|
-
return check.check(node)
|
84
|
-
}
|
158
|
+
return check.check(node);
|
159
|
+
});
|
160
|
+
|
161
|
+
return results.find((result) => result === true) || getErrors(results);
|
85
162
|
}
|
86
163
|
|
164
|
+
module.exports.checkNode = checkNode;
|
165
|
+
|
87
166
|
/**
|
88
|
-
*
|
89
|
-
* Otherwise return
|
167
|
+
* Create function that runs checks on a node. Return true if all checks return
|
168
|
+
* true. Otherwise return all errors or false.
|
90
169
|
*
|
91
170
|
* @param {Array<Function>} checks
|
92
171
|
*
|
93
|
-
* @returns {boolean|
|
172
|
+
* @returns {boolean|Object|Object[]|string|string[]}
|
94
173
|
*/
|
95
174
|
module.exports.checkEvery = function(...checks) {
|
96
175
|
return function(node) {
|
97
|
-
|
98
|
-
if (!isNil(previousResult) && previousResult !== true) {
|
99
|
-
return previousResult;
|
100
|
-
}
|
176
|
+
const results = checks.map((check) => check(node));
|
101
177
|
|
102
|
-
|
103
|
-
|
104
|
-
return result;
|
105
|
-
}, null);
|
178
|
+
return every(results, result => result === true) || getErrors(results);
|
106
179
|
};
|
107
|
-
}
|
180
|
+
};
|
108
181
|
|
109
182
|
/**
|
110
|
-
*
|
111
|
-
*
|
183
|
+
* Create function that runs checks on a node. Return true if at least one of
|
184
|
+
* the checks returns true. Otherwise return all errors or false.
|
112
185
|
*
|
113
186
|
* @param {Array<Function>} checks
|
114
187
|
*
|
115
|
-
* @returns {boolean|
|
188
|
+
* @returns {boolean|Object|Object[]|string|string[]}
|
116
189
|
*/
|
117
190
|
module.exports.checkSome = function(...checks) {
|
118
191
|
return function(node) {
|
119
|
-
|
120
|
-
if (previousResult === true) {
|
121
|
-
return previousResult;
|
122
|
-
}
|
192
|
+
const results = checks.map((check) => check(node));
|
123
193
|
|
124
|
-
|
194
|
+
return some(results, result => result === true) || getErrors(results);
|
195
|
+
};
|
196
|
+
};
|
197
|
+
|
198
|
+
/**
|
199
|
+
* Replace check for element of type.
|
200
|
+
*
|
201
|
+
* @param {(Object|string)[]} checks
|
202
|
+
* @param {string} type
|
203
|
+
* @param {Function} check
|
204
|
+
*
|
205
|
+
* @returns {(Object|string)[]}
|
206
|
+
*/
|
207
|
+
module.exports.replaceCheck = function(checks, type, check) {
|
208
|
+
return replaceChecks(checks, [
|
209
|
+
{
|
210
|
+
type,
|
211
|
+
check
|
212
|
+
}
|
213
|
+
]);
|
214
|
+
};
|
125
215
|
|
126
|
-
|
127
|
-
|
216
|
+
function replaceChecks(checks, replacements) {
|
217
|
+
return checks.map((check) => {
|
218
|
+
if (isString(check)) {
|
219
|
+
const replacement = replacements.find((replacement) => check === replacement.type);
|
220
|
+
|
221
|
+
if (replacement) {
|
222
|
+
return {
|
223
|
+
check: replacement.check,
|
224
|
+
type: check
|
225
|
+
};
|
128
226
|
}
|
227
|
+
}
|
129
228
|
|
130
|
-
|
131
|
-
|
132
|
-
};
|
133
|
-
}
|
229
|
+
if (check.type) {
|
230
|
+
const replacement = replacements.find((replacement) => check.type === replacement.type);
|
134
231
|
|
135
|
-
|
136
|
-
|
232
|
+
if (replacement) {
|
233
|
+
return {
|
234
|
+
...check,
|
235
|
+
check: replacement.check
|
236
|
+
};
|
237
|
+
}
|
238
|
+
}
|
137
239
|
|
138
|
-
|
240
|
+
return check;
|
241
|
+
});
|
139
242
|
}
|
140
243
|
|
141
|
-
module.exports.
|
142
|
-
const eventDefinitions = node.get('eventDefinitions');
|
244
|
+
module.exports.replaceChecks = replaceChecks;
|
143
245
|
|
144
|
-
|
246
|
+
function addExecutionPlatform(string, executionPlatform) {
|
247
|
+
return string
|
248
|
+
.replace('{{ executionPlatform }}', executionPlatform);
|
145
249
|
}
|
146
250
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
251
|
+
/**
|
252
|
+
* Return all errors or false.
|
253
|
+
*
|
254
|
+
* @param {(boolean|Object|string)[]} result
|
255
|
+
*
|
256
|
+
* @returns {boolean|(Object|string)[]}
|
257
|
+
*/
|
258
|
+
function getErrors(results) {
|
259
|
+
const errors = results.reduce((errors, result) => {
|
260
|
+
if (isArray(result)) {
|
261
|
+
return [
|
262
|
+
...errors,
|
263
|
+
...result
|
264
|
+
];
|
151
265
|
}
|
152
266
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
267
|
+
if (isObject(result) || isString(result)) {
|
268
|
+
return [
|
269
|
+
...errors,
|
270
|
+
result
|
271
|
+
];
|
157
272
|
}
|
158
273
|
|
159
|
-
|
160
|
-
|
161
|
-
return isAny(eventDefinition, types) || `${ node.$type} (${ eventDefinition.$type })`;
|
162
|
-
};
|
163
|
-
}
|
274
|
+
return errors;
|
275
|
+
}, []);
|
164
276
|
|
165
|
-
|
166
|
-
|
277
|
+
if (errors.length === 1) {
|
278
|
+
return errors[ 0 ];
|
279
|
+
} else if (errors.length > 1) {
|
280
|
+
return errors;
|
281
|
+
}
|
167
282
|
|
168
|
-
return
|
283
|
+
return false;
|
169
284
|
}
|
170
285
|
|
171
|
-
|
172
|
-
const
|
286
|
+
function isExactly(node, type) {
|
287
|
+
const { $model } = node;
|
173
288
|
|
174
|
-
return
|
289
|
+
return $model.getType(node.$type) === $model.getType(type);
|
175
290
|
}
|
176
291
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
292
|
+
function getIndefiniteArticle(type) {
|
293
|
+
if ([
|
294
|
+
'Error',
|
295
|
+
'Escalation',
|
296
|
+
'Event',
|
297
|
+
'Intermediate',
|
298
|
+
'Undefined'
|
299
|
+
].includes(type.split(' ')[ 0 ])) {
|
300
|
+
return 'An';
|
301
|
+
}
|
302
|
+
|
303
|
+
return 'A';
|
181
304
|
}
|
182
305
|
|
183
|
-
|
184
|
-
|
185
|
-
const loopCharacteristics = node.get('loopCharacteristics');
|
306
|
+
function getMessage(node, executionPlatform, executionPlatformVersion, label) {
|
307
|
+
const type = getTypeString(node);
|
186
308
|
|
187
|
-
|
188
|
-
return false;
|
189
|
-
}
|
309
|
+
const indefiniteArticle = getIndefiniteArticle(type);
|
190
310
|
|
191
|
-
|
192
|
-
};
|
311
|
+
return addExecutionPlatform(`${ indefiniteArticle } <${ type }> is not supported by {{ executionPlatform }}`, label || `${ executionPlatform } ${ toSemverMinor(executionPlatformVersion) }`);
|
193
312
|
}
|
194
313
|
|
195
|
-
|
196
|
-
|
314
|
+
function getLabel(node) {
|
315
|
+
if (is(node, 'bpmn:Group')) {
|
316
|
+
const categoryValueRef = node.get('categoryValueRef');
|
317
|
+
|
318
|
+
return categoryValueRef && categoryValueRef.get('value');
|
319
|
+
} else if (is(node, 'bpmn:TextAnnotation')) {
|
320
|
+
return node.get('text');
|
321
|
+
}
|
322
|
+
|
323
|
+
return node.get('name');
|
197
324
|
}
|
@@ -0,0 +1,47 @@
|
|
1
|
+
function getEventDefinition(node) {
|
2
|
+
const eventDefinitions = node.get('eventDefinitions');
|
3
|
+
|
4
|
+
return eventDefinitions && eventDefinitions[0];
|
5
|
+
}
|
6
|
+
|
7
|
+
function getEventDefinitionPrefix(eventDefinition) {
|
8
|
+
const localType = getLocalType(eventDefinition);
|
9
|
+
|
10
|
+
return localType.replace('EventDefinition', '');
|
11
|
+
}
|
12
|
+
|
13
|
+
function getLocalType(node) {
|
14
|
+
const { $descriptor } = node;
|
15
|
+
|
16
|
+
const { localName } = $descriptor.ns;
|
17
|
+
|
18
|
+
return localName;
|
19
|
+
}
|
20
|
+
|
21
|
+
function formatTypeString(string) {
|
22
|
+
return string.replace(/([a-z])([A-Z])/g, '$1 $2').trim();
|
23
|
+
}
|
24
|
+
|
25
|
+
module.exports.getTypeString = function(node) {
|
26
|
+
let type = getLocalType(node);
|
27
|
+
|
28
|
+
const eventDefinition = getEventDefinition(node);
|
29
|
+
|
30
|
+
if (eventDefinition) {
|
31
|
+
type = `${ getEventDefinitionPrefix(eventDefinition) }${ type }`;
|
32
|
+
} else if ([
|
33
|
+
'BoundaryEvent',
|
34
|
+
'EndEvent',
|
35
|
+
'IntermediateCatchEvent',
|
36
|
+
'IntermediateThrowEvent',
|
37
|
+
'StartEvent'
|
38
|
+
].includes(type)) {
|
39
|
+
type = `Undefined ${ type }`;
|
40
|
+
}
|
41
|
+
|
42
|
+
if (type === 'Task') {
|
43
|
+
type = 'Undefined Task';
|
44
|
+
}
|
45
|
+
|
46
|
+
return formatTypeString(type);
|
47
|
+
};
|