"use strict"; const isFunction = require('min-dash').isFunction, isObject = require('min-dash').isObject, some = require('min-dash').some const WILDCARD = '*' function CamundaModdleExtension(eventBus) { const self = this eventBus.on("moddleCopy.canCopyProperty", function(context) { const property = context.property, parent = context.parent return self.canCopyProperty(property, parent); }); } CamundaModdleExtension.$inject = ["eventBus"]; /** * Check wether to disallow copying property. */ CamundaModdleExtension.prototype.canCopyProperty = function(property, parent) { // (1) check wether property is allowed in parent if (isObject(property) && !isAllowedInParent(property, parent)) { return false; } // (2) check more complex scenarios if (is(property, "camunda:InputOutput") && !this.canHostInputOutput(parent)) { return false; } if (isAny(property, ["camunda:Connector", "camunda:Field"]) && !this.canHostConnector(parent)) { return false; } if (is(property, "camunda:In") && !this.canHostIn(parent)) { return false; } }; CamundaModdleExtension.prototype.canHostInputOutput = function(parent) { // allowed in camunda:Connector const connector = getParent(parent, 'camunda:Connector') if (connector) { return true; } // special rules inside bpmn:FlowNode const flowNode = getParent(parent, 'bpmn:FlowNode') if (!flowNode) { return false; } if (isAny(flowNode, ["bpmn:StartEvent", "bpmn:Gateway", "bpmn:BoundaryEvent"])) { return false; } return !(is(flowNode, "bpmn:SubProcess") && flowNode.get("triggeredByEvent")); }; CamundaModdleExtension.prototype.canHostConnector = function(parent) { const serviceTaskLike = getParent(parent, 'camunda:ServiceTaskLike') if (is(serviceTaskLike, "bpmn:MessageEventDefinition")) { // only allow on throw and end events return getParent(parent, "bpmn:IntermediateThrowEvent") || getParent(parent, "bpmn:EndEvent"); } return true; }; CamundaModdleExtension.prototype.canHostIn = function(parent) { const callActivity = getParent(parent, 'bpmn:CallActivity') if (callActivity) { return true; } const signalEventDefinition = getParent(parent, 'bpmn:SignalEventDefinition') if (signalEventDefinition) { // only allow on throw and end events return getParent(parent, "bpmn:IntermediateThrowEvent") || getParent(parent, "bpmn:EndEvent"); } return true; }; module.exports = CamundaModdleExtension; // helpers ////////// function is(element, type) { return element && isFunction(element.$instanceOf) && element.$instanceOf(type); } function isAny(element, types) { return some(types, function(t) { return is(element, t); }); } function getParent(element, type) { if (!type) { return element.$parent; } if (is(element, type)) { return element; } if (!element.$parent) { return; } return getParent(element.$parent, type); } function isAllowedInParent(property, parent) { // (1) find property descriptor const descriptor = property.$type && property.$model.getTypeDescriptor(property.$type) const allowedIn = descriptor && descriptor.meta && descriptor.meta.allowedIn if (!allowedIn || isWildcard(allowedIn)) { return true; } // (2) check wether property has parent of allowed type return some(allowedIn, function(type) { return getParent(parent, type); }); } function isWildcard(allowedIn) { return allowedIn.indexOf(WILDCARD) !== -1; }