bpmnlint 11.12.0 → 11.13.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/config/all.js +1 -0
- package/config/recommended.js +1 -1
- package/package.json +9 -8
- package/rules/standard-size.js +235 -0
package/config/all.js
CHANGED
package/config/recommended.js
CHANGED
|
@@ -17,7 +17,7 @@ module.exports = {
|
|
|
17
17
|
'no-implicit-split': 'error',
|
|
18
18
|
'no-implicit-end': 'error',
|
|
19
19
|
'no-implicit-start': 'error',
|
|
20
|
-
'no-inclusive-gateway': '
|
|
20
|
+
'no-inclusive-gateway': 'warn',
|
|
21
21
|
'no-overlapping-elements': 'warn',
|
|
22
22
|
'single-blank-start-event': 'error',
|
|
23
23
|
'single-event-definition': 'error',
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bpmnlint",
|
|
3
3
|
"description": "Validate your BPMN diagrams based on configurable lint rules",
|
|
4
|
-
"version": "11.
|
|
4
|
+
"version": "11.13.0",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"bpmnlint",
|
|
@@ -41,11 +41,11 @@
|
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@bpmn-io/moddle-utils": "^0.3.0",
|
|
43
43
|
"ansi-colors": "^4.1.3",
|
|
44
|
-
"bpmn-moddle": "^10.
|
|
44
|
+
"bpmn-moddle": "^10.1.0",
|
|
45
45
|
"bpmnlint-utils": "^1.1.1",
|
|
46
46
|
"cli-table": "^0.3.11",
|
|
47
47
|
"color-support": "^1.1.3",
|
|
48
|
-
"min-dash": "^5.
|
|
48
|
+
"min-dash": "^5.1.0",
|
|
49
49
|
"mri": "^1.2.0",
|
|
50
50
|
"pluralize": "^8.0.0",
|
|
51
51
|
"tiny-glob": "^0.2.9"
|
|
@@ -53,14 +53,15 @@
|
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@bpmn-io/bpmnlint-generate-docs-images": "^1.2.0",
|
|
55
55
|
"@types/mocha": "^10.0.10",
|
|
56
|
+
"@types/node": "^24.13.3",
|
|
56
57
|
"chai": "^6.2.2",
|
|
57
|
-
"eslint": "^9.39.
|
|
58
|
-
"eslint-plugin-bpmn-io": "^2.
|
|
58
|
+
"eslint": "^9.39.5",
|
|
59
|
+
"eslint-plugin-bpmn-io": "^2.3.1",
|
|
59
60
|
"execa": "^9.6.1",
|
|
60
61
|
"install-local": "^4.1.0",
|
|
61
|
-
"mocha": "^11.
|
|
62
|
-
"npm-run-all2": "^
|
|
63
|
-
"nyc": "^
|
|
62
|
+
"mocha": "^11.8.0",
|
|
63
|
+
"npm-run-all2": "^9.0.3",
|
|
64
|
+
"nyc": "^18.0.0",
|
|
64
65
|
"strip-indent": "^4.1.1",
|
|
65
66
|
"typescript": "^5.9.3"
|
|
66
67
|
},
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
const {
|
|
2
|
+
is
|
|
3
|
+
} = require('bpmnlint-utils');
|
|
4
|
+
|
|
5
|
+
const {
|
|
6
|
+
annotateRule
|
|
7
|
+
} = require('./helper');
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Default element sizes.
|
|
12
|
+
*
|
|
13
|
+
* NOTE: Kept in sync with `bpmn-js`
|
|
14
|
+
* (`lib/util/ElementSizeUtil.js`). We intentionally copy the values
|
|
15
|
+
* here to avoid a (heavy) dependency on `bpmn-js`.
|
|
16
|
+
*
|
|
17
|
+
* @type { Record<string, { width: number, height: number }> }
|
|
18
|
+
*/
|
|
19
|
+
const DEFAULT_SIZES = {
|
|
20
|
+
'bpmn:Task': { width: 100, height: 80 },
|
|
21
|
+
'bpmn:CallActivity': { width: 100, height: 80 },
|
|
22
|
+
'bpmn:SubProcess': { width: 100, height: 80 }, // collapsed
|
|
23
|
+
'bpmn:Gateway': { width: 50, height: 50 },
|
|
24
|
+
'bpmn:Event': { width: 36, height: 36 },
|
|
25
|
+
'bpmn:DataObjectReference': { width: 36, height: 50 },
|
|
26
|
+
'bpmn:DataStoreReference': { width: 50, height: 50 },
|
|
27
|
+
'bpmn:Participant': { width: 60, height: 60 } // collapsed breadth (empty pool)
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Element types resolved through the generic size lookup, most specific first.
|
|
32
|
+
*
|
|
33
|
+
* NOTE: `bpmn:Participant` is handled separately (empty pools only).
|
|
34
|
+
*
|
|
35
|
+
* @type { string[] }
|
|
36
|
+
*/
|
|
37
|
+
const CHECKED_TYPES = [
|
|
38
|
+
'bpmn:SubProcess',
|
|
39
|
+
'bpmn:CallActivity',
|
|
40
|
+
'bpmn:Task',
|
|
41
|
+
'bpmn:Gateway',
|
|
42
|
+
'bpmn:Event',
|
|
43
|
+
'bpmn:DataObjectReference',
|
|
44
|
+
'bpmn:DataStoreReference'
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* A rule that checks that elements have a standard (default) size.
|
|
50
|
+
*
|
|
51
|
+
* Resizable containers, whose size follows their content, are excluded:
|
|
52
|
+
*
|
|
53
|
+
* * expanded sub-processes
|
|
54
|
+
* * participants (pools) with content
|
|
55
|
+
* * lanes
|
|
56
|
+
*
|
|
57
|
+
* Empty pools (no `processRef`) are only checked for their fixed dimension,
|
|
58
|
+
* i.e. the default height for horizontally modeled and the default width for
|
|
59
|
+
* vertically modeled diagrams.
|
|
60
|
+
*
|
|
61
|
+
* Standard sizes are configurable per element type:
|
|
62
|
+
*
|
|
63
|
+
* ```json
|
|
64
|
+
* {
|
|
65
|
+
* "rules": {
|
|
66
|
+
* "standard-size": [ "warn", {
|
|
67
|
+
* "bpmn:Task": { "width": 120, "height": 80 }
|
|
68
|
+
* } ]
|
|
69
|
+
* }
|
|
70
|
+
* }
|
|
71
|
+
* ```
|
|
72
|
+
*
|
|
73
|
+
* @type { import('../lib/types.js').RuleFactory }
|
|
74
|
+
*/
|
|
75
|
+
module.exports = function(config) {
|
|
76
|
+
|
|
77
|
+
const sizes = {
|
|
78
|
+
...DEFAULT_SIZES,
|
|
79
|
+
...(config || {})
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
function check(node, reporter) {
|
|
83
|
+
|
|
84
|
+
// check each shape as we traverse the DI, avoiding a separate pass;
|
|
85
|
+
// each element is validated independently based on its own bounds
|
|
86
|
+
if (!is(node, 'bpmndi:BPMNShape')) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const element = node.bpmnElement;
|
|
91
|
+
const bounds = node.bounds;
|
|
92
|
+
|
|
93
|
+
// only check shapes with a linked element and proper bounds
|
|
94
|
+
if (!element || !isValidBounds(bounds)) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const expected = getExpectedSize(element, node, sizes);
|
|
99
|
+
|
|
100
|
+
// ignore elements without an expected size or with a malformed
|
|
101
|
+
// (non-object) size configuration
|
|
102
|
+
if (!expected || typeof expected !== 'object') {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const widthMismatch = typeof expected.width === 'number' && bounds.width !== expected.width;
|
|
107
|
+
const heightMismatch = typeof expected.height === 'number' && bounds.height !== expected.height;
|
|
108
|
+
|
|
109
|
+
if (!widthMismatch && !heightMismatch) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
reporter.report(element.id, getMessage(expected));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return annotateRule('standard-size', {
|
|
117
|
+
check
|
|
118
|
+
});
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
// helpers ////////////////////////
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Determine the expected (standard) size of an element or `null` if the
|
|
126
|
+
* element must not be checked.
|
|
127
|
+
*
|
|
128
|
+
* The returned object may contain only `width` or only `height`, in which case
|
|
129
|
+
* just that dimension is checked (empty pools).
|
|
130
|
+
*
|
|
131
|
+
* @param { Object } element
|
|
132
|
+
* @param { Object } di
|
|
133
|
+
* @param { Record<string, { width: number, height: number }> } sizes
|
|
134
|
+
*
|
|
135
|
+
* @return { { width?: number, height?: number } | null }
|
|
136
|
+
*/
|
|
137
|
+
function getExpectedSize(element, di, sizes) {
|
|
138
|
+
|
|
139
|
+
// participants (pools)
|
|
140
|
+
if (is(element, 'bpmn:Participant')) {
|
|
141
|
+
|
|
142
|
+
// pools with content follow their content
|
|
143
|
+
if (element.processRef) {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const horizontal = isHorizontal(di);
|
|
148
|
+
|
|
149
|
+
// empty pools are only checked for their fixed dimension:
|
|
150
|
+
// the height for horizontal, the width for vertical pools
|
|
151
|
+
const participantSize = sizes['bpmn:Participant'] || {};
|
|
152
|
+
const value = horizontal ? participantSize.height : participantSize.width;
|
|
153
|
+
|
|
154
|
+
// ignore missing / malformed configuration
|
|
155
|
+
if (typeof value !== 'number') {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return horizontal
|
|
160
|
+
? { height: value }
|
|
161
|
+
: { width: value };
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// lanes follow their content
|
|
165
|
+
if (is(element, 'bpmn:Lane')) {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// expanded sub-processes follow their content
|
|
170
|
+
if (is(element, 'bpmn:SubProcess') && isExpanded(di)) {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const type = CHECKED_TYPES.find(type => is(element, type));
|
|
175
|
+
|
|
176
|
+
if (!type) {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return sizes[type];
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* @param { { width?: number, height?: number } } expected
|
|
185
|
+
*
|
|
186
|
+
* @return { string }
|
|
187
|
+
*/
|
|
188
|
+
function getMessage(expected) {
|
|
189
|
+
if (typeof expected.height !== 'number') {
|
|
190
|
+
return `Element has a non-standard width; expected width of ${expected.width}`;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (typeof expected.width !== 'number') {
|
|
194
|
+
return `Element has a non-standard height; expected height of ${expected.height}`;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return `Element has a non-standard size; expected ${expected.width}x${expected.height}`;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Check whether a sub-process DI is expanded.
|
|
202
|
+
*
|
|
203
|
+
* NOTE: Adapted from `bpmn-js` (`lib/util/DiUtil.js`).
|
|
204
|
+
*
|
|
205
|
+
* @param { Object } di
|
|
206
|
+
*
|
|
207
|
+
* @return { boolean }
|
|
208
|
+
*/
|
|
209
|
+
function isExpanded(di) {
|
|
210
|
+
return !!di && !!di.isExpanded;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Check whether a participant / pool DI is modeled horizontally.
|
|
215
|
+
*
|
|
216
|
+
* NOTE: Adapted from `bpmn-js` (`lib/util/DiUtil.js`).
|
|
217
|
+
*
|
|
218
|
+
* @param { Object } di
|
|
219
|
+
*
|
|
220
|
+
* @return { boolean }
|
|
221
|
+
*/
|
|
222
|
+
function isHorizontal(di) {
|
|
223
|
+
return !di || di.isHorizontal === undefined || di.isHorizontal === true;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* @param { Object } bounds
|
|
228
|
+
*
|
|
229
|
+
* @return { boolean }
|
|
230
|
+
*/
|
|
231
|
+
function isValidBounds(bounds) {
|
|
232
|
+
return !!bounds && is(bounds, 'dc:Bounds') &&
|
|
233
|
+
typeof bounds.width === 'number' &&
|
|
234
|
+
typeof bounds.height === 'number';
|
|
235
|
+
}
|