@@ -24,13 +24,14 @@ import { getParents } from './util/elementsUtil';
2424 * Base Class that handles additional variable extractors, variable parsing and caching.
2525 */
2626export class BaseVariableResolver {
27+
2728 constructor ( eventBus , bpmnjs ) {
2829 this . providers = [ ] ;
2930 this . _eventBus = eventBus ;
3031 this . _bpmnjs = bpmnjs ;
3132
3233 this . rawVariables = new CachedValue ( this . _generateRawVariables . bind ( this ) ) ;
33- this . parsedVariables = new CachedValue ( async ( ) => {
34+ this . _allParsedVariables = new CachedValue ( async ( ) => {
3435
3536 const rawVariables = await this . getRawVariables ( ) ;
3637 const context = { variables : rawVariables } ;
@@ -39,6 +40,17 @@ export class BaseVariableResolver {
3940
4041 return context . variables ;
4142 } ) ;
43+ this . parsedVariables = new CachedValue ( async ( ) => {
44+ const allParsed = await this . _allParsedVariables . get ( ) ;
45+
46+ // Filter out variables with no scope (e.g. consumed variable markers)
47+ const filtered = { } ;
48+ for ( const key in allParsed ) {
49+ filtered [ key ] = allParsed [ key ] . filter ( v => v . scope ) ;
50+ }
51+
52+ return filtered ;
53+ } ) ;
4254
4355 eventBus . on ( [ 'commandStack.changed' , 'diagram.clear' , 'import.done' , 'variables.changed' ] , ( ) => {
4456 this . invalidateCache ( ) ;
@@ -100,6 +112,7 @@ export class BaseVariableResolver {
100112 */
101113 invalidateCache ( ) {
102114 this . rawVariables . invalidate ( ) ;
115+ this . _allParsedVariables . invalidate ( ) ;
103116 this . parsedVariables . invalidate ( ) ;
104117 }
105118
@@ -159,12 +172,26 @@ export class BaseVariableResolver {
159172 variables . forEach ( variable => {
160173 const existingVariable = mergedVariables . find ( v =>
161174 v . name === variable . name && v . scope === variable . scope
175+ && ( v . scope || ! v . usedBy ) && ( variable . scope || ! variable . usedBy )
162176 ) ;
163177
164178 if ( existingVariable ) {
165179 merge ( 'origin' , existingVariable , variable ) ;
166180 merge ( 'provider' , existingVariable , variable ) ;
167181 mergeEntries ( existingVariable , variable ) ;
182+
183+ // Preserve usedBy from either side during merge
184+ if ( variable . usedBy ) {
185+ if ( ! existingVariable . usedBy ) {
186+ existingVariable . usedBy = [ ...variable . usedBy ] ;
187+ } else {
188+ variable . usedBy . forEach ( target => {
189+ if ( ! existingVariable . usedBy . includes ( target ) ) {
190+ existingVariable . usedBy . push ( target ) ;
191+ }
192+ } ) ;
193+ }
194+ }
168195 } else {
169196 mergedVariables . push ( variable ) ;
170197 }
@@ -251,7 +278,7 @@ export class BaseVariableResolver {
251278 *
252279 * @async
253280 * @param {ModdleElement } element
254- * @returns {Array<ProcessVariable> } variables
281+ * @returns {Promise< Array<ProcessVariable> > } variables
255282 */
256283 async getVariablesForElement ( element ) {
257284 const bo = getBusinessObject ( element ) ;
@@ -261,14 +288,14 @@ export class BaseVariableResolver {
261288
262289 // (1) get variables for given scope
263290 var scopeVariables = allVariables . filter ( function ( variable ) {
264- return variable . scope . id === bo . id ;
291+ return variable . scope && variable . scope . id === bo . id ;
265292 } ) ;
266293
267294 // (2) get variables for parent scopes
268295 var parents = getParents ( bo ) ;
269296
270297 var parentsScopeVariables = allVariables . filter ( function ( variable ) {
271- return parents . find ( function ( parent ) {
298+ return variable . scope && parents . find ( function ( parent ) {
272299 return parent . id === variable . scope . id ;
273300 } ) ;
274301 } ) ;
@@ -299,6 +326,31 @@ export class BaseVariableResolver {
299326 throw new Error ( 'not implemented VariableResolver#_getScope' ) ;
300327 }
301328
329+ /**
330+ * Returns consumed variables for an element — variables
331+ * the element needs as input for its expressions and mappings.
332+ *
333+ * Uses `getVariables()` instead of `getVariablesForElement()` to
334+ * bypass the name-based deduplication that would drop requirement
335+ * entries for variables that also exist in ancestor scopes.
336+ *
337+ * @param {Object } element
338+ * @returns {Promise<Array<AvailableVariable>> }
339+ */
340+ async getConsumedVariablesForElement ( element ) {
341+ const allVariablesByRoot = await this . _allParsedVariables . get ( )
342+ . catch ( ( ) => {
343+ return { } ;
344+ } ) ;
345+
346+ const allVariables = Object . values ( allVariablesByRoot ) . flat ( ) ;
347+
348+ return allVariables . filter ( v =>
349+ v . usedBy && v . usedBy . length > 0
350+ && ! v . scope
351+ && v . origin . length === 1 && v . origin [ 0 ] . id === element . id
352+ ) ;
353+ }
302354}
303355
304356BaseVariableResolver . $inject = [ 'eventBus' , 'bpmnjs' ] ;
0 commit comments