diff --git a/index.js b/index.js
index 6cf6ff9..2002a4f 100644
--- a/index.js
+++ b/index.js
@@ -7,6 +7,7 @@ module.exports = {
'processmaker/call-activity-child-process': 'error',
'processmaker/call-activity-sequence-flow': 'error',
'processmaker/id-required': 'error',
+ 'processmaker/signal-ref-required': 'error',
},
},
},
diff --git a/rules/id-required.js b/rules/id-required.js
index 3c6ddfd..576e992 100644
--- a/rules/id-required.js
+++ b/rules/id-required.js
@@ -1,4 +1,4 @@
-const { is } = require('bpmnlint-utils');
+const { is, isAny } = require('bpmnlint-utils');
/**
* A rule that checks the presence of a node ID.
@@ -8,8 +8,26 @@ module.exports = function() {
return node.$type.startsWith('bpmndi') || node.$type.startsWith('dc');
}
+ function isEventDefinition(node) {
+ return isAny(node, [
+ 'bpmn:CancelEventDefinition',
+ 'bpmn:CompensateDefinition',
+ 'bpmn:ErrorEventDefinition',
+ 'bpmn:EscalationEventDefinition',
+ 'bpmn:Expression',
+ 'bpmn:LinkEventDefinition',
+ 'bpmn:MessageEventDefinition',
+ 'bpmn:SignalEventDefinition',
+ 'bpmn:TerminateEventDefinition',
+ 'bpmn:TimeCycle',
+ 'bpmn:TimeDate',
+ 'bpmn:TimeDuration',
+ 'bpmn:TimerEventDefinition',
+ ]);
+ }
+
function check(node, reporter) {
- if (is(node, 'bpmn:Definitions') || isNonBpmnType(node)) {
+ if (is(node, 'bpmn:Definitions') || isNonBpmnType(node) || isEventDefinition(node)) {
return;
}
diff --git a/rules/signal-ref-required.js b/rules/signal-ref-required.js
new file mode 100644
index 0000000..74b8e26
--- /dev/null
+++ b/rules/signal-ref-required.js
@@ -0,0 +1,43 @@
+const { is, isAny } = require('bpmnlint-utils');
+
+/**
+ * A rule that checks that signal events have a signal ref
+ */
+module.exports = function() {
+
+ function hasEventDefinitions(node) {
+ return Array.isArray(node.eventDefinitions)
+ && node.eventDefinitions.length > 0;
+ }
+
+ function filterEventDefinitionsWithoutSignalRef(node) {
+ return node.eventDefinitions.filter(
+ eventDefinition => is(eventDefinition, 'bpmn:SignalEventDefinition')
+ && !eventDefinition.signalRef
+ );
+ }
+
+ function check(node, reporter) {
+ if (!isAny(node, [
+ 'bpmn:StartEvent',
+ 'bpmn:EndEvent',
+ 'bpmn:IntermediateCatchEvent',
+ 'bpmn:IntermediateThrowEvent',
+ 'bpmn:BoundaryEvent',
+ ])) {
+ return;
+ }
+
+ if (!hasEventDefinitions(node)) {
+ return;
+ }
+
+ const missing = filterEventDefinitionsWithoutSignalRef(node);
+
+ if (missing.length > 0) {
+ reporter.report(node.id, 'Missing signal reference');
+ }
+ }
+
+ return { check };
+};
diff --git a/test-diagrams/boundary-event-signal-ref.invalid.bpmn b/test-diagrams/boundary-event-signal-ref.invalid.bpmn
new file mode 100644
index 0000000..9ad7df9
--- /dev/null
+++ b/test-diagrams/boundary-event-signal-ref.invalid.bpmn
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test-diagrams/boundary-event-signal-ref.valid.bpmn b/test-diagrams/boundary-event-signal-ref.valid.bpmn
new file mode 100644
index 0000000..d59aadc
--- /dev/null
+++ b/test-diagrams/boundary-event-signal-ref.valid.bpmn
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test-diagrams/end-event-signal-ref.invalid.bpmn b/test-diagrams/end-event-signal-ref.invalid.bpmn
new file mode 100644
index 0000000..08a31a4
--- /dev/null
+++ b/test-diagrams/end-event-signal-ref.invalid.bpmn
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test-diagrams/end-event-signal-ref.valid.bpmn b/test-diagrams/end-event-signal-ref.valid.bpmn
new file mode 100644
index 0000000..8e74ed0
--- /dev/null
+++ b/test-diagrams/end-event-signal-ref.valid.bpmn
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test-diagrams/event-definitions.valid.bpmn b/test-diagrams/event-definitions.valid.bpmn
new file mode 100644
index 0000000..31888ed
--- /dev/null
+++ b/test-diagrams/event-definitions.valid.bpmn
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+ 2020-04-17T20:19:00.000Z|R/2020-04-17T20:19:00.000Z/P1W
+
+
+
+
+
+
+
+ 2020-04-17T20:34:00.000Z
+
+
+
+
+
+
+
+
+
+
+ PT1H
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test-diagrams/intermediate-catch-event-signal-ref.invalid.bpmn b/test-diagrams/intermediate-catch-event-signal-ref.invalid.bpmn
new file mode 100644
index 0000000..7f3042f
--- /dev/null
+++ b/test-diagrams/intermediate-catch-event-signal-ref.invalid.bpmn
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test-diagrams/intermediate-catch-event-signal-ref.valid.bpmn b/test-diagrams/intermediate-catch-event-signal-ref.valid.bpmn
new file mode 100644
index 0000000..c3b8e94
--- /dev/null
+++ b/test-diagrams/intermediate-catch-event-signal-ref.valid.bpmn
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test-diagrams/intermediate-throw-event-signal-ref.invalid.bpmn b/test-diagrams/intermediate-throw-event-signal-ref.invalid.bpmn
new file mode 100644
index 0000000..72c96f6
--- /dev/null
+++ b/test-diagrams/intermediate-throw-event-signal-ref.invalid.bpmn
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test-diagrams/intermediate-throw-event-signal-ref.valid.bpmn b/test-diagrams/intermediate-throw-event-signal-ref.valid.bpmn
new file mode 100644
index 0000000..efe0753
--- /dev/null
+++ b/test-diagrams/intermediate-throw-event-signal-ref.valid.bpmn
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test-diagrams/start-event-signal-ref.invalid.bpmn b/test-diagrams/start-event-signal-ref.invalid.bpmn
new file mode 100644
index 0000000..2c767ed
--- /dev/null
+++ b/test-diagrams/start-event-signal-ref.invalid.bpmn
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test-diagrams/start-event-signal-ref.valid.bpmn b/test-diagrams/start-event-signal-ref.valid.bpmn
new file mode 100644
index 0000000..d00c270
--- /dev/null
+++ b/test-diagrams/start-event-signal-ref.valid.bpmn
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test.js b/test.js
index 98f04b2..932e796 100644
--- a/test.js
+++ b/test.js
@@ -5,6 +5,7 @@ const gatewayDirectionRule = require('./rules/gateway-direction');
const callActivityChildProcessRule = require('./rules/call-activity-child-process');
const callActivitySequenceFlowRule = require('./rules/call-activity-sequence-flow');
const idRequiredRule = require('./rules/id-required');
+const signalRefRequiredRule = require('./rules/signal-ref-required');
RuleTester.verify('gateway-direction', gatewayDirectionRule, {
valid: [
@@ -85,6 +86,9 @@ RuleTester.verify('id-required', idRequiredRule, {
valid: [
{
moddleElement: readModdle('./test-diagrams/id-required.valid.bpmn')
+ },
+ {
+ moddleElement: readModdle('./test-diagrams/event-definitions.valid.bpmn')
}
],
invalid: [
@@ -104,3 +108,60 @@ RuleTester.verify('id-required', idRequiredRule, {
}
]
});
+
+RuleTester.verify('signal-ref-required', signalRefRequiredRule, {
+ valid: [
+ {
+ moddleElement: readModdle('./test-diagrams/start-event-signal-ref.valid.bpmn')
+ },
+ {
+ moddleElement: readModdle('./test-diagrams/intermediate-catch-event-signal-ref.valid.bpmn')
+ },
+ {
+ moddleElement: readModdle('./test-diagrams/intermediate-throw-event-signal-ref.valid.bpmn')
+ },
+ {
+ moddleElement: readModdle('./test-diagrams/boundary-event-signal-ref.valid.bpmn')
+ },
+ {
+ moddleElement: readModdle('./test-diagrams/end-event-signal-ref.valid.bpmn')
+ }
+ ],
+ invalid: [
+ {
+ moddleElement: readModdle('./test-diagrams/start-event-signal-ref.invalid.bpmn'),
+ report: {
+ id: 'node_2',
+ message: 'Missing signal reference'
+ }
+ },
+ {
+ moddleElement: readModdle('./test-diagrams/intermediate-catch-event-signal-ref.invalid.bpmn'),
+ report: {
+ id: 'node_2',
+ message: 'Missing signal reference'
+ }
+ },
+ {
+ moddleElement: readModdle('./test-diagrams/intermediate-throw-event-signal-ref.invalid.bpmn'),
+ report: {
+ id: 'node_2',
+ message: 'Missing signal reference'
+ }
+ },
+ {
+ moddleElement: readModdle('./test-diagrams/boundary-event-signal-ref.invalid.bpmn'),
+ report: {
+ id: 'node_2',
+ message: 'Missing signal reference'
+ }
+ },
+ {
+ moddleElement: readModdle('./test-diagrams/end-event-signal-ref.invalid.bpmn'),
+ report: {
+ id: 'node_2',
+ message: 'Missing signal reference'
+ }
+ },
+ ]
+});