diff --git a/lib/base/VariableResolver.js b/lib/base/VariableResolver.js index 53611bc..a5e0523 100644 --- a/lib/base/VariableResolver.js +++ b/lib/base/VariableResolver.js @@ -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 @@ -17,6 +16,7 @@ import { uniqueBy } from 'min-dash'; * @typedef {AdditionalVariable} ProcessVariable * @property {Array} origin * @property {ModdleElement} scope + * @property {Array} provider */ /** @@ -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>} @@ -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)) { + seenNames.add(variable.name); + + return true; + } + + return false; + }); } } diff --git a/test/fixtures/zeebe/simple.bpmn b/test/fixtures/zeebe/simple.bpmn index e77e398..af26a56 100644 --- a/test/fixtures/zeebe/simple.bpmn +++ b/test/fixtures/zeebe/simple.bpmn @@ -1,37 +1,49 @@ - + - - Flow_16gvdav - - - Flow_0elge1o + Flow_00zecls - + + + Flow_16gvdav Flow_0elge1o + + Flow_0elge1o + Flow_00zecls + + + Flow_16gvdav + - - - + + + + + + - + + + + + diff --git a/test/spec/zeebe/ZeebeVariableResolver.spec.js b/test/spec/zeebe/ZeebeVariableResolver.spec.js index 2890534..b797f0d 100644 --- a/test/spec/zeebe/ZeebeVariableResolver.spec.js +++ b/test/spec/zeebe/ZeebeVariableResolver.spec.js @@ -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'); @@ -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' ] }, + ]); }));