@camunda/linting 0.4.1 → 0.5.0-alpha.2
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 +13 -0
- package/README.md +33 -4
- package/assets/linting.css +33 -0
- package/lib/modeler/Linting.js +105 -0
- package/lib/modeler/LintingAnnotations.js +72 -0
- package/lib/modeler/index.js +11 -0
- package/lib/utils/error-messages.js +7 -0
- package/lib/utils/properties-panel.js +18 -0
- package/modeler.js +1 -0
- package/package.json +25 -9
- package/properties-panel.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,19 @@ All notable changes to [@camunda/linting](https://github.com/camunda/linting) ar
|
|
|
6
6
|
|
|
7
7
|
___Note:__ Yet to be released changes appear here._
|
|
8
8
|
|
|
9
|
+
## 0.5.0-alpha.2
|
|
10
|
+
|
|
11
|
+
* `FIX`: publish assets
|
|
12
|
+
|
|
13
|
+
## 0.5.0-alpha.1
|
|
14
|
+
|
|
15
|
+
* `FIX`: publish modeler.js
|
|
16
|
+
|
|
17
|
+
## 0.5.0-alpha.0
|
|
18
|
+
|
|
19
|
+
* `FEAT`: add bpmn-js plugin for canvas and properties panel errors ([#11](https://github.com/camunda/linting/pull/11))
|
|
20
|
+
* `FEAT`: add no-zeebe-properties rule ([#43](https://github.com/camunda/bpmnlint-plugin-camunda-compat/pull/43))
|
|
21
|
+
|
|
9
22
|
## 0.4.1
|
|
10
23
|
|
|
11
24
|
* `DEPS`: broaden supported versions range of `bpmn-js-properties-panel`
|
package/README.md
CHANGED
|
@@ -8,12 +8,24 @@ The BPMN linter used by the Camunda Desktop and Web Modeler. Batteries included.
|
|
|
8
8
|
* configures linter based on `modeler:executionPlatform` and `modeler:executionPlatformVersion`
|
|
9
9
|
* creates error messages to be shown in desktop and web modeler
|
|
10
10
|
* creates errors to be shown in properties panel
|
|
11
|
+
* creates error overlays to be shown on canvas
|
|
11
12
|
|
|
12
13
|
# Usage
|
|
13
14
|
|
|
14
15
|
```javascript
|
|
16
|
+
import Modeler from 'bpmn-js/lib/Modeler';
|
|
17
|
+
|
|
15
18
|
import { Linter } from '@camunda/linting';
|
|
16
|
-
|
|
19
|
+
|
|
20
|
+
import lintingModule from '@camunda/linting/modeler';
|
|
21
|
+
|
|
22
|
+
import '@camunda/linting/assets/linting.css';
|
|
23
|
+
|
|
24
|
+
const modeler = new Modeler({
|
|
25
|
+
additionalModules: [
|
|
26
|
+
lintingModule
|
|
27
|
+
]
|
|
28
|
+
});
|
|
17
29
|
|
|
18
30
|
// configure to be used with desktop or web modeler
|
|
19
31
|
const linter = new Linter({
|
|
@@ -28,10 +40,27 @@ const reports = await linter.lint(xml);
|
|
|
28
40
|
|
|
29
41
|
...
|
|
30
42
|
|
|
31
|
-
|
|
43
|
+
// update errors on canvas and in properties panel (requires bpmn-js-properties-panel >= 1.3.0)
|
|
44
|
+
modeler.get('linting').setErrors(reports);
|
|
45
|
+
|
|
46
|
+
// show error by selecting element and properties panel entry
|
|
47
|
+
modeler.get('linting').showError(report);
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
# Development
|
|
51
|
+
|
|
52
|
+
```sh
|
|
53
|
+
# install
|
|
54
|
+
npm i
|
|
55
|
+
|
|
56
|
+
# run tests
|
|
57
|
+
npm t
|
|
58
|
+
|
|
59
|
+
# run tests in watch mode
|
|
60
|
+
npm run test:watch
|
|
32
61
|
|
|
33
|
-
|
|
34
|
-
|
|
62
|
+
# run example
|
|
63
|
+
npm start
|
|
35
64
|
```
|
|
36
65
|
|
|
37
66
|
# License
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--color-red-360-100-45: hsl(360, 100%, 45%);
|
|
3
|
+
--color-white: hsl(0, 0%, 100%);
|
|
4
|
+
|
|
5
|
+
--linting-annotation-background-color: var(--color-red-360-100-45);
|
|
6
|
+
--linting-annotation-fill-color: var(--color-white);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.djs-overlays:not(.hover) .bjs-linting-annotation {
|
|
10
|
+
opacity: 0.5;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.djs-overlays.hover .bjs-linting-annotation,
|
|
14
|
+
.djs-overlays .bjs-linting-annotation:hover {
|
|
15
|
+
opacity: 1;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.bjs-linting-annotation {
|
|
19
|
+
display: flex;
|
|
20
|
+
flex-direction: row;
|
|
21
|
+
align-items: center;
|
|
22
|
+
padding: 1px;
|
|
23
|
+
border-radius: 2px;
|
|
24
|
+
background-color: var(--linting-annotation-background-color);
|
|
25
|
+
cursor: default;
|
|
26
|
+
z-index: 100000;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.bjs-linting-annotation > svg {
|
|
30
|
+
fill: var(--linting-annotation-fill-color);
|
|
31
|
+
width: 18px;
|
|
32
|
+
height: 18px;
|
|
33
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { getErrors } from '../utils/properties-panel';
|
|
2
|
+
|
|
3
|
+
export default class Linting {
|
|
4
|
+
constructor(canvas, elementRegistry, eventBus, lintingAnnotations, selection) {
|
|
5
|
+
this._canvas = canvas;
|
|
6
|
+
this._elementRegistry = elementRegistry;
|
|
7
|
+
this._eventBus = eventBus;
|
|
8
|
+
this._lintingAnnotations = lintingAnnotations;
|
|
9
|
+
this._selection = selection;
|
|
10
|
+
|
|
11
|
+
this._reports = [];
|
|
12
|
+
|
|
13
|
+
eventBus.on('selection.changed', () => this._update());
|
|
14
|
+
|
|
15
|
+
eventBus.on('lintingAnnotations.click', ({ report }) => this.showError(report));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
showError(report) {
|
|
19
|
+
const {
|
|
20
|
+
id,
|
|
21
|
+
propertiesPanel = {}
|
|
22
|
+
} = report;
|
|
23
|
+
|
|
24
|
+
const element = this._elementRegistry.get(id);
|
|
25
|
+
|
|
26
|
+
if (element !== this._canvas.getRootElement() && needsScrollToElement(this._canvas, element)) {
|
|
27
|
+
this._canvas.scrollToElement(element);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
this._selection.select(element);
|
|
31
|
+
|
|
32
|
+
const { entryId } = propertiesPanel;
|
|
33
|
+
|
|
34
|
+
this._eventBus.fire('propertiesPanel.showEntry', {
|
|
35
|
+
id: entryId
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
setErrors(reports) {
|
|
40
|
+
this._reports = reports;
|
|
41
|
+
|
|
42
|
+
this._update();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
activate() {
|
|
46
|
+
this._update();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
deactivate() {
|
|
50
|
+
this._update([]);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
_update(reports) {
|
|
54
|
+
if (!reports) {
|
|
55
|
+
reports = this._reports;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// set annotations
|
|
59
|
+
this._lintingAnnotations.setErrors(reports);
|
|
60
|
+
|
|
61
|
+
// set properties panel errors
|
|
62
|
+
const selectedElement = this._getSelectedElement();
|
|
63
|
+
|
|
64
|
+
this._eventBus.fire('propertiesPanel.setErrors', {
|
|
65
|
+
errors: getErrors(this._reports, selectedElement)
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
_getSelectedElement() {
|
|
70
|
+
const selection = this._selection.get();
|
|
71
|
+
|
|
72
|
+
if (!selection || !selection.length) {
|
|
73
|
+
return this._canvas.getRootElement();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const selectedElement = selection[ 0 ];
|
|
77
|
+
|
|
78
|
+
if (isLabel(selectedElement)) {
|
|
79
|
+
return selectedElement.labelTarget;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return selectedElement;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
Linting.$inject = [
|
|
87
|
+
'canvas',
|
|
88
|
+
'elementRegistry',
|
|
89
|
+
'eventBus',
|
|
90
|
+
'lintingAnnotations',
|
|
91
|
+
'selection'
|
|
92
|
+
];
|
|
93
|
+
|
|
94
|
+
function isLabel(element) {
|
|
95
|
+
return !!element.labelTarget;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function needsScrollToElement(canvas, element) {
|
|
99
|
+
const viewbox = canvas.viewbox();
|
|
100
|
+
|
|
101
|
+
return viewbox.x > element.x
|
|
102
|
+
|| viewbox.y > element.y
|
|
103
|
+
|| viewbox.x + viewbox.width < element.x + element.width
|
|
104
|
+
|| viewbox.y + viewbox.height < element.y + element.height;
|
|
105
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { groupBy } from 'min-dash';
|
|
2
|
+
|
|
3
|
+
import { domify } from 'min-dom';
|
|
4
|
+
|
|
5
|
+
const errorSvg = `
|
|
6
|
+
<svg viewBox="2 2 20 20">
|
|
7
|
+
<path d="M12,5 C15.8659932,5 19,8.13400675 19,12 C19,15.8659932 15.8659932,19 12,19 C8.13400675,19 5,15.8659932 5,12 C5,8.13400675 8.13400675,5 12,5 Z M9.33333333,8 L8,9.33333333 L10.667,12 L8,14.6666667 L9.33333333,16 L12,13.333 L14.6666667,16 L16,14.6666667 L13.333,12 L16,9.33333333 L14.6666667,8 L12,10.666 L9.33333333,8 Z"></path>
|
|
8
|
+
</svg>
|
|
9
|
+
`;
|
|
10
|
+
|
|
11
|
+
export default class LintingAnnotations {
|
|
12
|
+
constructor(elementRegistry, eventBus, overlays) {
|
|
13
|
+
this._elementRegistry = elementRegistry;
|
|
14
|
+
this._eventBus = eventBus;
|
|
15
|
+
this._overlays = overlays;
|
|
16
|
+
|
|
17
|
+
this._reportsByElement = {};
|
|
18
|
+
|
|
19
|
+
this._overlayIds = {};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
setErrors(reports) {
|
|
23
|
+
this._reportsByElement = groupBy(reports, 'id');
|
|
24
|
+
|
|
25
|
+
this._update();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
_update(reportsByElement) {
|
|
29
|
+
if (!reportsByElement) {
|
|
30
|
+
reportsByElement = this._reportsByElement;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
this._overlays.remove({ type: 'linting' });
|
|
34
|
+
|
|
35
|
+
Object.entries(reportsByElement).forEach(([ id, reports ]) => {
|
|
36
|
+
const element = this._elementRegistry.get(id);
|
|
37
|
+
|
|
38
|
+
if (!element) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const overlay = domify(`
|
|
43
|
+
<div class="bjs-linting-annotation" title="Click to show">
|
|
44
|
+
${ errorSvg }
|
|
45
|
+
</div>
|
|
46
|
+
`);
|
|
47
|
+
|
|
48
|
+
overlay.addEventListener('click', () => {
|
|
49
|
+
this._eventBus.fire('lintingAnnotations.click', { report: reports[ 0 ] });
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const overlayId = this._overlays.add(element, 'linting', {
|
|
53
|
+
position: {
|
|
54
|
+
bottom: -5,
|
|
55
|
+
left: 0
|
|
56
|
+
},
|
|
57
|
+
html: overlay,
|
|
58
|
+
show: {
|
|
59
|
+
minZoom: 0.5
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
this._overlayIds[ id ] = overlayId;
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
LintingAnnotations.$inject = [
|
|
69
|
+
'elementRegistry',
|
|
70
|
+
'eventBus',
|
|
71
|
+
'overlays'
|
|
72
|
+
];
|
|
@@ -108,13 +108,20 @@ function getExtensionElementNotAllowedErrorMessage(report, executionPlatformLabe
|
|
|
108
108
|
|
|
109
109
|
const {
|
|
110
110
|
node,
|
|
111
|
+
parentNode,
|
|
111
112
|
extensionElement
|
|
112
113
|
} = error;
|
|
113
114
|
|
|
115
|
+
const typeString = getTypeString(parentNode || node);
|
|
116
|
+
|
|
114
117
|
if (is(node, 'bpmn:BusinessRuleTask') && is(extensionElement, 'zeebe:CalledDecision')) {
|
|
115
118
|
return `A <Business Rule Task> with <Implementation: DMN decision> is not supported by ${ executionPlatformLabel }`;
|
|
116
119
|
}
|
|
117
120
|
|
|
121
|
+
if (is(extensionElement, 'zeebe:Properties')) {
|
|
122
|
+
return `${ getIndefiniteArticle(typeString) } <${ typeString }> with <Extension properties> is not supported by ${ executionPlatformLabel }`;
|
|
123
|
+
}
|
|
124
|
+
|
|
118
125
|
return message;
|
|
119
126
|
}
|
|
120
127
|
|
|
@@ -122,6 +122,14 @@ export function getEntryIds(report) {
|
|
|
122
122
|
});
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
+
if (isExtensionElementNotAllowedError(error, 'zeebe:Properties')) {
|
|
126
|
+
const { extensionElement } = error;
|
|
127
|
+
|
|
128
|
+
return extensionElement.get('zeebe:properties').map((zeebeProperty, index) => {
|
|
129
|
+
return `${ id }-extensionProperty-${ index }-name`;
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
125
133
|
return [];
|
|
126
134
|
}
|
|
127
135
|
|
|
@@ -189,6 +197,16 @@ export function getErrorMessage(id) {
|
|
|
189
197
|
if (/^.+-header-[0-9]+-key$/.test(id)) {
|
|
190
198
|
return 'Must be unique.';
|
|
191
199
|
}
|
|
200
|
+
|
|
201
|
+
if (/^.+-extensionProperty-[0-9]+-name$/.test(id)) {
|
|
202
|
+
return 'Not supported.';
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function isExtensionElementNotAllowedError(error, extensionElement, type) {
|
|
207
|
+
return error.type === ERROR_TYPES.EXTENSION_ELEMENT_NOT_ALLOWED
|
|
208
|
+
&& is(error.extensionElement, extensionElement)
|
|
209
|
+
&& (!type || is(error.node, type));
|
|
192
210
|
}
|
|
193
211
|
|
|
194
212
|
function isExtensionElementRequiredError(error, requiredExtensionElement, type) {
|
package/modeler.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './lib/modeler';
|
package/package.json
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camunda/linting",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0-alpha.2",
|
|
4
4
|
"description": "Linting for Camunda Platform",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"all": "npm run lint && npm test",
|
|
8
8
|
"lint": "eslint .",
|
|
9
|
-
"
|
|
10
|
-
"test
|
|
9
|
+
"start": "cross-env SINGLE_START=modeler npm run test:watch",
|
|
10
|
+
"test": "karma start",
|
|
11
|
+
"test:watch": "npm test -- --auto-watch --no-single-run"
|
|
11
12
|
},
|
|
12
13
|
"keywords": [
|
|
13
14
|
"bpmnlint",
|
|
@@ -25,18 +26,32 @@
|
|
|
25
26
|
"dependencies": {
|
|
26
27
|
"bpmn-moddle": "^7.1.2",
|
|
27
28
|
"bpmnlint": "^7.8.0",
|
|
28
|
-
"bpmnlint-plugin-camunda-compat": "^0.
|
|
29
|
+
"bpmnlint-plugin-camunda-compat": "^0.11.0",
|
|
29
30
|
"bpmnlint-utils": "^1.0.2",
|
|
31
|
+
"min-dash": "^3.8.1",
|
|
32
|
+
"min-dom": "^3.2.1",
|
|
30
33
|
"modeler-moddle": "^0.2.0",
|
|
31
|
-
"zeebe-bpmn-moddle": "^0.
|
|
34
|
+
"zeebe-bpmn-moddle": "^0.14.0"
|
|
32
35
|
},
|
|
33
36
|
"devDependencies": {
|
|
37
|
+
"bpmn-js": "^9.4.0",
|
|
34
38
|
"chai": "^4.3.6",
|
|
39
|
+
"cross-env": "^7.0.3",
|
|
35
40
|
"eslint": "^4.11.0",
|
|
36
41
|
"eslint-plugin-bpmn-io": "^0.4.1",
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
42
|
+
"karma": "^6.4.0",
|
|
43
|
+
"karma-chrome-launcher": "^3.1.1",
|
|
44
|
+
"karma-debug-launcher": "0.0.5",
|
|
45
|
+
"karma-env-preprocessor": "^0.1.1",
|
|
46
|
+
"karma-mocha": "^2.0.1",
|
|
47
|
+
"karma-sinon-chai": "^2.0.2",
|
|
48
|
+
"karma-webpack": "^5.0.0",
|
|
49
|
+
"mocha": "^4.0.1",
|
|
50
|
+
"mocha-test-container-support": "^0.2.0",
|
|
51
|
+
"puppeteer": "^16.2.0",
|
|
52
|
+
"sinon": "^14.0.0",
|
|
53
|
+
"sinon-chai": "^3.7.0",
|
|
54
|
+
"webpack": "^5.74.0"
|
|
40
55
|
},
|
|
41
56
|
"peerDependencies": {
|
|
42
57
|
"bpmn-js-properties-panel": "^1.3.0"
|
|
@@ -47,8 +62,9 @@
|
|
|
47
62
|
}
|
|
48
63
|
},
|
|
49
64
|
"files": [
|
|
65
|
+
"assets",
|
|
50
66
|
"lib",
|
|
51
|
-
"
|
|
67
|
+
"modeler.js"
|
|
52
68
|
],
|
|
53
69
|
"publishConfig": {
|
|
54
70
|
"access": "public"
|
package/properties-panel.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './lib/utils/properties-panel';
|