Skip to content

Commit

Permalink
feat: support execution listeners
Browse files Browse the repository at this point in the history
Related to camunda/camunda-modeler#3951

feat: add `no-duplicate-execution-listeners` rule

feat: add `no-execution-listeners` rule

feat: add `execution-listener` rule
  • Loading branch information
barmac committed Jul 29, 2024
1 parent c7b65fc commit 3841463
Show file tree
Hide file tree
Showing 10 changed files with 699 additions and 11 deletions.
11 changes: 9 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const camundaCloud10Rules = withConfig({
'loop-characteristics': 'error',
'message-reference': 'error',
'no-candidate-users': 'error',
'no-execution-listeners': 'error',
'no-expression': 'error',
'no-loop': 'error',
'no-multiple-none-start-events': 'error',
Expand Down Expand Up @@ -75,8 +76,11 @@ const camundaCloud85Rules = withConfig({
'wait-for-completion': 'error'
}, { version: '8.5' });

const camundaCloud86Rules = withConfig(
omit(camundaCloud85Rules, 'inclusive-gateway'), { version: '8.6' });
const camundaCloud86Rules = withConfig({
...omit(camundaCloud85Rules, [ 'inclusive-gateway', 'no-execution-listeners' ]),
'duplicate-execution-listeners': 'error',
'execution-listener': 'error'
}, { version: '8.6' });

const camundaPlatform719Rules = withConfig({
'history-time-to-live': 'info'
Expand Down Expand Up @@ -105,12 +109,14 @@ const rules = {
'called-element': './rules/camunda-cloud/called-element',
'collapsed-subprocess': './rules/camunda-cloud/collapsed-subprocess',
'connector-properties': './rules/camunda-cloud/connector-properties',
'duplicate-execution-listeners': './rules/camunda-cloud/duplicate-execution-listeners',
'duplicate-task-headers': './rules/camunda-cloud/duplicate-task-headers',
'error-reference': './rules/camunda-cloud/error-reference',
'escalation-boundary-event-attached-to-ref': './rules/camunda-cloud/escalation-boundary-event-attached-to-ref',
'escalation-reference': './rules/camunda-cloud/escalation-reference',
'event-based-gateway-target': './rules/camunda-cloud/event-based-gateway-target',
'executable-process': './rules/camunda-cloud/executable-process',
'execution-listener': './rules/camunda-cloud/execution-listener',
'feel': './rules/camunda-cloud/feel',
'history-time-to-live': './rules/camunda-platform/history-time-to-live',
'implementation': './rules/camunda-cloud/implementation',
Expand All @@ -119,6 +125,7 @@ const rules = {
'loop-characteristics': './rules/camunda-cloud/loop-characteristics',
'message-reference': './rules/camunda-cloud/message-reference',
'no-candidate-users': './rules/camunda-cloud/no-candidate-users',
'no-execution-listeners': './rules/camunda-cloud/no-execution-listeners',
'no-expression': './rules/camunda-cloud/no-expression',
'no-loop': './rules/camunda-cloud/no-loop',
'no-multiple-none-start-events': './rules/camunda-cloud/no-multiple-none-start-events',
Expand Down
17 changes: 9 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"modeler-moddle": "^0.2.0",
"sinon": "^17.0.1",
"sinon-chai": "^3.7.0",
"zeebe-bpmn-moddle": "^1.1.0"
"zeebe-bpmn-moddle": "^1.4.0"
},
"dependencies": {
"@bpmn-io/feel-lint": "^1.2.0",
Expand Down
81 changes: 81 additions & 0 deletions rules/camunda-cloud/duplicate-execution-listeners.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
const {
ERROR_TYPES,
findExtensionElement
} = require('../utils/element');

const { reportErrors } = require('../utils/reporter');

const { skipInNonExecutableProcess } = require('../utils/rule');

module.exports = skipInNonExecutableProcess(function() {
function check(node, reporter) {
const executionListeners = findExtensionElement(node, 'zeebe:ExecutionListeners');

if (!executionListeners) {
return;
}

const errors = hasDuplicatedExecutionListeners(executionListeners, node);

if (errors && errors.length) {
reportErrors(node, reporter, errors);
}
}

return {
check
};
});

// helpers //////////
function hasDuplicatedExecutionListeners(executionListeners, parentNode = null) {
const listeners = executionListeners.get('listeners');

// (1) find duplicates
const duplicates = [];
const events = new Map();
for (const listener of listeners) {
const eventName = listener.get('eventType'),
type = listener.get('type');

if (!events.has(eventName)) {
events.set(eventName, new Set([ type ]));
continue;
}

const types = events.get(eventName);
if (types.has(type)) {
duplicates.push(listener);
} else {
types.add(type);
}
}

// (2) report error for each duplicate
if (duplicates.length) {
return duplicates.map(duplicate => {
const eventName = duplicate.get('eventType'),
type = duplicate.get('type');

// (3) find properties with duplicate
const duplicateProperties = listeners.filter(listener => listener.get('eventType') === eventName && listener.get('type') === type);

// (4) report error
return {
message: `Duplicate execution listener with event type <${eventName}> and job type <${type}>`,
path: null,
data: {
type: ERROR_TYPES.PROPERTY_VALUE_DUPLICATED,
node: executionListeners,
parentNode: parentNode === executionListeners ? null : parentNode,
duplicatedProperty: 'type',
duplicatedPropertyValue: type,
properties: duplicateProperties,
propertiesName: 'listeners'
}
};
});
}

return [];
}
37 changes: 37 additions & 0 deletions rules/camunda-cloud/execution-listener.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
const {
findExtensionElement,
hasProperties
} = require('../utils/element');

const { reportErrors } = require('../utils/reporter');

const { skipInNonExecutableProcess } = require('../utils/rule');


module.exports = skipInNonExecutableProcess(function() {
function check(node, reporter) {

console.log(node);

const executionListeners = findExtensionElement(node, 'zeebe:ExecutionListeners');

if (!executionListeners) {
return;
}

const listeners = executionListeners.get('listeners');
const errors = listeners.flatMap(listener => hasProperties(listener, {
type: {
required: true
}
}, node));

if (errors.length) {
reportErrors(node, reporter, errors);
}
}

return {
check
};
});
21 changes: 21 additions & 0 deletions rules/camunda-cloud/no-execution-listeners.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const { reportErrors } = require('../utils/reporter');

const { skipInNonExecutableProcess } = require('../utils/rule');

const { hasNoExtensionElement } = require('../utils/element');

const ALLOWED_VERSION = '8.6';

module.exports = skipInNonExecutableProcess(function() {
function check(node, reporter) {
const errors = hasNoExtensionElement(node, 'zeebe:ExecutionListeners', node, ALLOWED_VERSION);

if (errors && errors.length) {
reportErrors(node, reporter, errors);
}
}

return {
check
};
});
Loading

0 comments on commit 3841463

Please sign in to comment.