Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 24 additions & 8 deletions lib/base/VariableResolver.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { getBusinessObject, is } from 'bpmn-js/lib/util/ModelUtil';
import CachedValue from './util/CachedValue';
import { getParents, getScope } from './util/scopeUtil';
import { uniqueBy } from 'min-dash';

/**
* @typedef {Object} AdditionalVariable
Expand All @@ -17,6 +16,7 @@ import { uniqueBy } from 'min-dash';
* @typedef {AdditionalVariable} ProcessVariable
* @property {Array<ModdleElement>} origin
* @property {ModdleElement} scope
* @property {Array<Object>} provider
*/

/**
Expand Down Expand Up @@ -49,7 +49,7 @@ export class BaseVariableResolver {
}

/**
* To be implemented by super class. This should be an instance of `getProcessVariables` from `@bpmn-io/extract-process-variables`,
* To be implemented by a subclass. This should be an instance of `getProcessVariables` from `@bpmn-io/extract-process-variables`,
* either C7 or C8.
*
* @returns {Promise<Array<ProcessVariable>>}
Expand Down Expand Up @@ -258,24 +258,40 @@ export class BaseVariableResolver {
const root = getRootElement(bo);
const allVariables = await this.getProcessVariables(root);

// keep only unique variables based on name property
const uniqueVariables = uniqueBy('name', allVariables.reverse());

// (1) get variables for given scope
var scopeVariables = uniqueVariables.filter(function(variable) {
var scopeVariables = allVariables.filter(function(variable) {
return variable.scope.id === bo.id;
});

// (2) get variables for parent scopes
var parents = getParents(bo);

var parentsScopeVariables = uniqueVariables.filter(function(variable) {
var parentsScopeVariables = allVariables.filter(function(variable) {
return parents.find(function(parent) {
return parent.id === variable.scope.id;
});
});

return [ ...scopeVariables, ...parentsScopeVariables ];
const reversedVariables = [ ...scopeVariables, ...parentsScopeVariables ].reverse();

const seenNames = new Set();

return reversedVariables.filter(variable => {

// if external variable, keep
if (variable.provider.find(extractor => extractor !== this._baseExtractor)) {
return true;
}

// if not external, keep only the first occurrence of each name
if (!seenNames.has(variable.name)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Powered by Flip + 🤖 ❤️

seenNames.add(variable.name);

return true;
}

return false;
});
}
}

Expand Down
34 changes: 23 additions & 11 deletions test/fixtures/zeebe/simple.bpmn
Original file line number Diff line number Diff line change
@@ -1,37 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_0uo7yqr" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.5.1" modeler:executionPlatform="Camunda Cloud" modeler:executionPlatformVersion="8.1.0">
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_0uo7yqr" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.37.0" modeler:executionPlatform="Camunda Cloud" modeler:executionPlatformVersion="8.1.0">
<bpmn:process id="Process_1" isExecutable="true">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_16gvdav</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_16gvdav" sourceRef="StartEvent_1" targetRef="ServiceTask_1" />
<bpmn:endEvent id="Event_0ld1d1y">
<bpmn:incoming>Flow_0elge1o</bpmn:incoming>
<bpmn:incoming>Flow_00zecls</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_0elge1o" sourceRef="ServiceTask_1" targetRef="Event_0ld1d1y" />
<bpmn:sequenceFlow id="Flow_00zecls" sourceRef="ServiceTask_2" targetRef="Event_0ld1d1y" />
<bpmn:sequenceFlow id="Flow_0elge1o" sourceRef="ServiceTask_1" targetRef="ServiceTask_2" />
<bpmn:sequenceFlow id="Flow_16gvdav" sourceRef="StartEvent_1" targetRef="ServiceTask_1" />
<bpmn:serviceTask id="ServiceTask_1">
<bpmn:incoming>Flow_16gvdav</bpmn:incoming>
<bpmn:outgoing>Flow_0elge1o</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:serviceTask id="ServiceTask_2">
<bpmn:incoming>Flow_0elge1o</bpmn:incoming>
<bpmn:outgoing>Flow_00zecls</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_16gvdav</bpmn:outgoing>
</bpmn:startEvent>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0ld1d1y_di" bpmnElement="Event_0ld1d1y">
<dc:Bounds x="432" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_10piuzo_di" bpmnElement="ServiceTask_1">
<dc:Bounds x="270" y="77" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0ld1d1y_di" bpmnElement="Event_0ld1d1y">
<dc:Bounds x="582" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0otfqm7_di" bpmnElement="ServiceTask_2">
<dc:Bounds x="420" y="77" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_16gvdav_di" bpmnElement="Flow_16gvdav">
<di:waypoint x="215" y="117" />
<di:waypoint x="270" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0elge1o_di" bpmnElement="Flow_0elge1o">
<di:waypoint x="370" y="117" />
<di:waypoint x="432" y="117" />
<di:waypoint x="420" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_00zecls_di" bpmnElement="Flow_00zecls">
<di:waypoint x="520" y="117" />
<di:waypoint x="582" y="117" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
Expand Down
41 changes: 39 additions & 2 deletions test/spec/zeebe/ZeebeVariableResolver.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ describe('ZeebeVariableResolver', function() {
);


it('should merge variables of same scope', inject(async function(variableResolver, elementRegistry) {
it('should merge variables of same scope and same name', inject(async function(variableResolver, elementRegistry) {

// given
const root = elementRegistry.get('Process_1');
Expand All @@ -385,7 +385,44 @@ describe('ZeebeVariableResolver', function() {
const variables = await variableResolver.getVariablesForElement(root);

// then
expect(variables).to.variableEqual([ { name: 'foo', type: 'String', scope: 'Process_1', origin: [ 'ServiceTask_1', 'Process_1' ] } ]);
expect(variables).to.variableEqual([
{ name: 'foo', type: 'String', scope: 'Process_1', origin: [ 'ServiceTask_1', 'Process_1' ] }
]);
}));


it('should not merge variables of different scopes and same name', inject(async function(variableResolver, elementRegistry) {

// given
const serviceTask1 = elementRegistry.get('ServiceTask_1'),
serviceTask2 = elementRegistry.get('ServiceTask_2');

createProvider({
variables: [ { name: 'foo', type: 'String', scope: serviceTask1 } ],
variableResolver,
origin: 'ServiceTask_1'
});
createProvider({
variables: [ { name: 'foo', type: 'String', scope: serviceTask2 } ],
variableResolver,
origin: 'ServiceTask_2'
});

// when
let variables = await variableResolver.getVariablesForElement(serviceTask1);

// then
expect(variables).to.variableEqual([
{ name: 'foo', type: 'String', scope: 'ServiceTask_1', origin: [ 'ServiceTask_1' ] },
]);

// when
variables = await variableResolver.getVariablesForElement(serviceTask2);

// then
expect(variables).to.variableEqual([
{ name: 'foo', type: 'String', scope: 'ServiceTask_2', origin: [ 'ServiceTask_2' ] },
]);
}));


Expand Down