Skip to content

Provide variables used in feel expressions#74

Open
Buckwich wants to merge 1 commit intomainfrom
5639_variable-input-requirements
Open

Provide variables used in feel expressions#74
Buckwich wants to merge 1 commit intomainfrom
5639_variable-input-requirements

Conversation

@Buckwich
Copy link
Member

@Buckwich Buckwich commented Feb 18, 2026

Related to camunda/camunda-modeler#5639

Proposed Changes

runs feel-analyzer on every input "feel" expression (input mapping starting with = and scripts) and adds them to raw variables without scope

new function getInputRequirementsForElement can be used by consumers to get those variables

variables without scope are filtered out of the normal getVariables

Probably best to try out in task testing demo:

npx @bpmn-io/sr camunda/task-testing#5640_prefill-tasktesting -l bpmn-io/variable-resolver#5639_variable-input-requirements

Checklist

Ensure you provide everything we need to review your contribution:

  • Contribution meets our definition of done
  • Pull request establishes context
    • Link to related issue(s), i.e. Closes {LINK_TO_ISSUE} or Related to {LINK_TO_ISSUE}
    • Brief textual description of the changes
    • Screenshots or short videos showing UI/UX changes
    • Steps to try out, i.e. using the @bpmn-io/sr tool

@bpmn-io-tasks bpmn-io-tasks bot added the in progress Currently worked on label Feb 18, 2026
@Buckwich Buckwich requested a review from Copilot February 18, 2026 23:16
@Buckwich Buckwich changed the base branch from simon-wip to main February 18, 2026 23:16
@Buckwich Buckwich changed the title feat: provide variables used in feel expressions Provide variables used in feel expressions Feb 18, 2026
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This pull request implements functionality to extract and track variables used in FEEL expressions within BPMN process definitions. The feature analyzes input mappings and script task expressions to identify which variables are required as inputs, creating "input requirement" entries that track dependencies between variables.

Changes:

  • Added FEEL expression analysis using @bpmn-io/feel-analyzer to extract input variables from expressions
  • Introduced usedBy property on ProcessVariable objects to track which target variables depend on each input
  • Added getInputRequirementsForElement API method to retrieve input requirements for specific elements

Reviewed changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated no comments.

Show a summary per file
File Description
package.json Added dependencies for @bpmn-io/feel-analyzer and @camunda/feel-builtins to enable FEEL expression analysis
package-lock.json Updated dependency tree with new packages and peer dependency resolutions
lib/zeebe/util/feelUtility.js Core implementation: analyzes expressions with FeelAnalyzer, builds input requirements with deduplication and entry merging, filters scoped variables
lib/zeebe/VariableResolver.js Integrates input requirements into the variable resolution pipeline
lib/base/VariableResolver.js Adds getInputRequirementsForElement method, updates scope filtering to exclude input requirements, fixes async return type documentation
test/spec/zeebe/Mappings.spec.js Comprehensive tests for input requirement extraction covering simple/nested expressions, deduplication, merging, scoping, and script tasks
test/fixtures/zeebe/mappings/input-requirements.bpmn Test fixture with various input mapping scenarios
test/fixtures/zeebe/mappings/script-task-inputs.bpmn Test fixture for script task input extraction
test/fixtures/zeebe/mappings/script-task-with-input-mappings.bpmn Test fixture combining script tasks with input mappings
Comments suppressed due to low confidence (3)

lib/base/VariableResolver.js:320

  • The new public method getInputRequirementsForElement has no test coverage. Consider adding tests to verify that it correctly filters input requirements by element and handles edge cases like elements with no input requirements, multiple input requirements, and both diagram-js elements and moddle elements as parameters.
  async getInputRequirementsForElement(element) {
    const allVariablesByRoot = await this.getVariables()
      .catch(() => {
        return {};
      });

    const allVariables = Object.values(allVariablesByRoot).flat();

    return allVariables.filter(v =>
      v.usedBy && v.usedBy.length > 0
      && v.origin.length === 1 && v.origin[0].id === element.id
    );
  }

lib/base/VariableResolver.js:305

  • The parameter type annotation for element should be {ModdleElement} to be consistent with other methods in this class like getProcessVariables and getVariablesForElement which use the same parameter type.
   * @param {Object} element

lib/base/VariableResolver.js:318

  • The method compares v.origin[0].id with element.id directly, but the method might be called with a diagram-js element (which has a .businessObject property) or a moddle element directly. Consider using getBusinessObject(element) like getVariablesForElement does on line 256 to handle both cases correctly.
      && v.origin.length === 1 && v.origin[0].id === element.id

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@Buckwich Buckwich marked this pull request as ready for review February 19, 2026 10:33
@bpmn-io-tasks bpmn-io-tasks bot added needs review Review pending and removed in progress Currently worked on labels Feb 19, 2026
@Buckwich Buckwich requested review from a team, barmac and jarekdanielak and removed request for a team February 19, 2026 10:33
@barmac
Copy link
Member

barmac commented Feb 19, 2026

One problem which I noticed is that we don't take into account the order in which inputs are defined. This is already a problem with existing variable resolver as we suggest the local variables even before they are declared. You can consider this to be an edge case, but it may be confusing for the users (potential follow-up).

On the example, abc is not defined when input1 is evaluated, so the script result is null in the consequence:

image

In this PR, this manifests by not prefiling abc:

image

@Buckwich
Copy link
Member Author

@barmac I've adjusted the behavior to follow the input mapping chain

@barmac
Copy link
Member

barmac commented Feb 20, 2026

@barmac I've adjusted the behavior to follow the input mapping chain

Hmm it looks that we still remove the variable which is required for the execution:

Screen.Recording.2026-02-20.at.14.07.03.mov

@Buckwich
Copy link
Member Author

Sorry I didn't update the task testing PR yet. you need to test with (updated description)

npx @bpmn-io/sr camunda/task-testing#5640_prefill-tasktesting -l bpmn-io/variable-resolver#5639_variable-input-requirements
Screen.Recording.2026-02-20.at.14.20.03.mov

@barmac
Copy link
Member

barmac commented Feb 20, 2026

Do we want to handle script and business rule tasks correctly in this PR? Asking because there are many places where a variable can be used, and not necessarily defined.

image image

@barmac
Copy link
Member

barmac commented Feb 20, 2026

Variables ordering in script:

  1. inputs from the top to the bottom
  2. script FEEL expression

So the script can use the inputs contrary to what the screenshot indicates.

@Buckwich
Copy link
Member Author

ATM it only looks at io mappings and script expressions. I can either just include all feel expressions (in the sense of any value starting with =, might be to broad) or I need to come up with a list of potential feel expressions

@barmac
Copy link
Member

barmac commented Feb 20, 2026

Gotcha. In that case, I think it's fine to move the complete support to a separate issue, but let's either fix or remove the script part.

@barmac
Copy link
Member

barmac commented Feb 20, 2026

We don't want to check all of the values starting with =, cf. camunda/bpmnlint-plugin-camunda-compat#53

@Buckwich Buckwich force-pushed the 5639_variable-input-requirements branch from ccce04e to 3120e8a Compare February 23, 2026 14:06
Copy link
Member

@nikku nikku left a comment

Choose a reason for hiding this comment

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

Let's discuss the things mentioned:

  • Performance - are we now "fast enough" with all built-ins used?
  • Parsing - we parse the AST twice (this library, and feel-analyzer) - does it matter, if so, how?
  • inputRequrements, is that the name we want to use?
  • output mappings may establish dependencies

@Buckwich Buckwich force-pushed the 5639_variable-input-requirements branch from f4de807 to 7ff271b Compare March 3, 2026 09:16
@Buckwich Buckwich marked this pull request as ready for review March 3, 2026 09:21
@bpmn-io-tasks bpmn-io-tasks bot added needs review Review pending and removed in progress Currently worked on labels Mar 3, 2026
@Buckwich Buckwich requested review from Copilot and nikku and removed request for Copilot March 3, 2026 10:01
const variables = await variableResolver.getConsumedVariablesForElement(task);

// then
const a = variables.find(v => v.name === 'a');
Copy link
Member

Choose a reason for hiding this comment

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

We should use our existing helpers here:

expect(variables).to.variableInclude({
  name: 'a',
  usedBy: [ 'sum' ]
});

Copy link
Member

@nikku nikku left a comment

Choose a reason for hiding this comment

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

@Buckwich Could you update the PR description - to be clear on how the introduction of used variables as proposed changes the API surface?

  • We have an existing API - will that contain used variables, or not?
  • Especially as we have variable-outline in place, if that would want to show the variables for an element that are "used" - how would it do that, today?

➡️ Let's ensure both PR description and README updates clearly reflect the change in scope of this library - instead of "just looking at written variables" the library now gives you comprehensive intelligence on both written and consumed variables.

@nikku
Copy link
Member

nikku commented Mar 5, 2026

@Buckwich Can we have an environment (i.e. variable-int-up) to validate the changes E2E? I'd love to measure the end-user effect on typical diagrams.

@nikku
Copy link
Member

nikku commented Mar 5, 2026

@barinali I'd like to summon you into the discussion - we will have usedBy intelligence with this PR merged - should we integrate that into variable-outline? And what would you need for a proper integration? We discussed previously that the Written by... (variable outline) is not a good filter - we probably want to focus on "variables related to this element" in the future.

@Buckwich
Copy link
Member Author

Buckwich commented Mar 5, 2026

Can we have an environment (i.e. variable-int-up) to validate the changes E2E? I'd love to measure the end-user effect on typical diagrams.

Integration in desktop modeler: prefill-integration

npx @bpmn-io/sr camunda/camunda-modeler#prefill-integration

@barinali
Copy link
Contributor

barinali commented Mar 5, 2026

@barinali I'd like to summon you into the discussion - we will have usedBy intelligence with this PR merged

Thanks!

Eventually, yes. The question right now would be about how we want to proceed. variable-outline has work to do still, mostly for hardening I'd say, mainly consisting of remarks we have had in the pull requests.

And what would you need for a proper integration?

Variables exposed via VariableResolver#getVariables should suffice along with their usedBy elements. I reckon that we want to possibly introduce another "Used by N elements" section along with showing the respective elements and possibly another (👁️) icon tag to indicate this variable is used by the current selection in the overview.

We discussed previously that the Written by... (variable outline) is not a good filter - we probably want to focus on "variables related to this element" in the future.

Agreed, but I'm unsure if we just want "variables related to this element" filter straight like that. I was thinking around the idea of giving the flexibility of individually filtering for;

  1. variables the current selection writes to
  2. variables the current selection uses
  3. variables the current selection both writes to and uses ("variables related to this element" as you mention)

I understand all three cases produce different narrowed down list of variables (compared to accessible variables) and provides different set of value. I think in case of debugging/inspection, all three filter modes may be valuable.

@Buckwich
Copy link
Member Author

Buckwich commented Mar 5, 2026

should we integrate that into variable-outline?

I already did some experiments for that, but yeah currently waiting for the main changes in variables outline to be completed to avoid merge conflicts and we need to decide what to show. cf

@nikku
Copy link
Member

nikku commented Mar 5, 2026

variables the current selection both writes to and uses ("variables related to this element" as you mention)

I'd start with the combined view, because less is more and await user feedback if they need more.

@nikku
Copy link
Member

nikku commented Mar 5, 2026

Variables exposed via VariableResolver.getVariables() should suffice along with their usedBy elements.

So @barinali we should expose all variables via VariableProvider#getVariables(...). It will be a major release, as we now expose also variables without a scope, that are just usedBy. You have to filter client-side.

Perfect, this is what I needed.

@Buckwich
Copy link
Member Author

Buckwich commented Mar 5, 2026

So @barinali we should expose all variables via VariableProvider#getVariables(...). It will be a major release, as we now expose also variables without a scope, that are just usedBy. You have to filter client-side.

No, currently the main interface stays the same. but of course can be adjusted, but after the discussion in https://camunda.slack.com/archives/GP70M0J6M/p1772456953844339 I thought we agreed on this one

Note:

  • variables without scope are filtered out of the normal getVariables
  • new function getInputRequirementsForElement can be used by consumers to get those variables

@barinali
Copy link
Contributor

barinali commented Mar 5, 2026

@nikku

I and @Buckwich have had a huddle about this. We both are on the same page about introducing usedBy variables after I am through with the remarks in variable-outline.

The topic about changing the VariablesProvider#getVariables interface heavily depends on what and how we want to incorporate these "new" variables in the variables panel. While it's easier to incorporate usedBy variables with scopes, I got some questions about visualizing scope-less variables like;

  1. Is it another set of scope variables (for the scope of "noscope") where we show usedBy variables that have no scope?
  2. What happens when we have multi-selection in the canvas and need to show many noscope variables?
    2.1. Do we still show a single noscope variables group?
    2.2. Do we show many noscope variables groups as many as selected elements?
    2.2. Do we incorporate them in the scopes where they're used? This might cause more harm than benefits unless they're made obvious that their origin is unknown, but they're used.

@Buckwich
Copy link
Member Author

Buckwich commented Mar 5, 2026

Update from discussion:

  • we will release this as a breaking change/major
  • getVariables will return all variables, even without scope -> interface change scope becomes optional and consumers need to handle/filter that
  • for the initial release we won't necessarily show consumed variables yet in the outline panel
  • will iterate further for UI after initial data is available
  • getConsumedVariablesForElement can be used as a nice helper

@Buckwich Buckwich marked this pull request as draft March 6, 2026 14:23
@bpmn-io-tasks bpmn-io-tasks bot added in progress Currently worked on and removed needs review Review pending labels Mar 6, 2026
@nikku
Copy link
Member

nikku commented Mar 6, 2026

Via #74 (review) I wanted us to show the E2E scope of this change - ensuring we add "used variables" in an integrated way. I went ahead and sketched how that integration could look like in this document.

Summary

To summarize the main takeaways:

  • scope and origin become optional - there can be variables that don't have an origin, that don’t have a scope. usedBy tracks diagram elements that use a particular variable
  • usedBy is a ModdleElement[] - if an element with id=Task_1 is in the usedBy list of variable[name=foo], then it means Task_1 uses foo
  • We need to merge / attache usedBy to the correct scopes (test: verify usedBy attaches to correct scope #92)
  • We have to handle dual use (read and write) scenarios (test: validate dual use of read and written variable #91)
  • We have to be able to handle scenarios where no variables are written (from the model) (test: verify used variables in different scenarios #90)
  • We release the change as major - variables may now be unscoped, and key APIs return read and written variables
  • We don't need to introduce a new API - but can add basic filters to the existing API

Proposed addition to existing API

// return only read variables, excluding local ones
const consumedVariables = variableResolver.getVariablesForElement(element, { read: true, local: false });

// return all written variables
const allWrittenVariables = variableResolver.getVariablesForElement(element, { written: true });

// return all variables (default)
const allVariables = variableResolver.getVariablesForElement(element);

@Buckwich Buckwich force-pushed the 5639_variable-input-requirements branch from d873ddf to dd46c34 Compare March 6, 2026 16:57
@Buckwich Buckwich marked this pull request as ready for review March 6, 2026 16:59
@bpmn-io-tasks bpmn-io-tasks bot added needs review Review pending and removed in progress Currently worked on labels Mar 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs review Review pending

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants