import { isFunction, isObject } from '../../../../../../../../../packages/utils/src'; const WILDCARD = '*'; function CamundaModdleExtension(eventBus) { // eslint-disable-next-line unicorn/no-this-assignment, @typescript-eslint/no-this-alias const self = this; eventBus.on('moddleCopy.canCopyProperty', (context) => { const parent = context.parent; const property = context.property; 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; export default CamundaModdleExtension; // helpers ////////// function is(element, type) { return ( element && isFunction(element.$instanceOf) && element.$instanceOf(type) ); } function isAny(element, types) { return types.some((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 allowedIn.some((type) => { return getParent(parent, type); }); } function isWildcard(allowedIn) { return allowedIn.includes(WILDCARD); }