@0dep/bpmn-extensions 0.0.3 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @0dep/bpmn-extensions
2
2
 
3
- [![Built latest](https://github.com/zerodep/bpmn-extensions/actions/workflows/build-latest.yaml/badge.svg)](https://github.com/zerodep/bpmn-extensions/actions/workflows/build-latest.yaml)[![Coverage Status](https://coveralls.io/repos/github/zerodep/bpmn-extensions/badge.svg?branch=main)](https://coveralls.io/github/zerodep/bpmn-extensions?branch=main)[![npm version](https://img.shields.io/npm/v/@0dep/bpmn-extensions)](https://www.npmjs.com/package/@0dep/bpmn-extensions)
3
+ [![Built latest](https://github.com/zerodep/bpmn-extensions/actions/workflows/build-latest.yaml/badge.svg)](https://github.com/zerodep/bpmn-extensions/actions/workflows/build-latest.yaml)[![Coverage Status](https://coveralls.io/repos/github/zerodep/bpmn-extensions/badge.svg?branch=main)](https://coveralls.io/github/zerodep/bpmn-extensions?branch=main)
4
4
 
5
5
  Flow extensions for [bpmn-elements](https://github.com/paed01/bpmn-elements) with
6
6
  [FEEL](https://www.omg.org/dmn/) expression support.
@@ -21,6 +21,12 @@ npm install @0dep/bpmn-extensions bpmn-elements
21
21
 
22
22
  - **FEEL expressions** — a `FeelExpressions()` adapter resolves FEEL (`= order.total > 100`)
23
23
  everywhere bpmn-elements resolves an expression, including sequence flow conditions.
24
+ - **Environment services in FEEL scope** — every FEEL expression can call the environment services
25
+ as functions, namespaced under `services` (e.g. a condition `= services.isEligible(order)`).
26
+ This strays from strict Camunda 8 conformance on purpose: unlike functions smuggled through
27
+ variables, services survive `getState()`/`recover()` — state is JSON-serialized (functions are
28
+ dropped), while services are re-supplied by the host at recover time — so service-backed
29
+ conditions are resume-safe. A variable named `services` shadows the overlay.
24
30
  - **`zeebe:script`** — a `FeelScripts()` adapter runs a script task's FEEL `expression` and assigns
25
31
  the result to its `resultVariable`.
26
32
  - **`zeebe:taskDefinition`** — maps a service task's job `type` to an environment service (job worker).
@@ -32,6 +38,9 @@ npm install @0dep/bpmn-extensions bpmn-elements
32
38
  process's input becomes variables local to its children.
33
39
  - **`zeebe:taskHeaders`** / **`zeebe:properties`** — exposed on the element content.
34
40
  - **`zeebe:assignmentDefinition`** — assignee / candidate users / groups for user tasks.
41
+ - **`zeebe:priorityDefinition`** / **`zeebe:taskSchedule`** — a user task's `priority` and
42
+ `dueDate` / `followUpDate` resolved onto the element content for a task list to order and
43
+ remind by; FEEL date results are exposed as ISO 8601 strings.
35
44
  - **`zeebe:formDefinition`** — resolves a user task's form (`formId` / `formKey` / `externalReference`,
36
45
  `bindingType`) onto the element content for a task list to render.
37
46
  - **`zeebe:executionListeners`** — blocking start/end job workers around an element, called as
@@ -48,11 +57,15 @@ npm install @0dep/bpmn-extensions bpmn-elements
48
57
  ## API
49
58
 
50
59
  - `extensions(element, context)` — the flow extensions factory; pass it as an environment extension.
60
+ Elements that carry no zeebe extension data (and nothing else to format) get no extension attached
61
+ at all and run untouched; call activities and processes are always attached, since they propagate
62
+ io across process boundaries.
51
63
  - `extendFn(behaviour)` — moddle-context-serializer behaviour extender (lifts the extension data
52
64
  bpmn-elements expects on the behaviour: call activity process id and multi-instance collection).
53
65
  - `FeelExpressions()` — a bpmn-elements `IExpressions` implementation backed by FEEL.
54
66
  - `FeelScripts()` — a bpmn-elements `scripts` implementation that runs `zeebe:script` FEEL expressions.
55
- - FEEL helpers: `isFeelExpression`, `stripFeel`, `evaluateFeel`, `evaluateFeelUnaryTest`, `resolveValue`.
67
+ - FEEL helpers: `isFeelExpression`, `stripFeel`, `evaluateFeel`, `evaluateFeelUnaryTest`, `resolveValue`,
68
+ `getFeelScope` (the scope every expression is evaluated in: `services` + environment variables + local overlay).
56
69
  - `JobService`, `ServiceError`, `FormatError`.
57
70
 
58
71
  ## Usage
@@ -62,7 +75,7 @@ Wire it into a bpmn-elements definition (see `test/helpers/testHelpers.js` for t
62
75
  ```javascript
63
76
  import { createRequire } from 'node:module';
64
77
  import { strict as assert } from 'node:assert';
65
- import BpmnModdle from 'bpmn-moddle';
78
+ import { BpmnModdle } from 'bpmn-moddle';
66
79
  import * as elements from 'bpmn-elements';
67
80
  import { Serializer, TypeResolver } from 'moddle-context-serializer';
68
81
  import { extensions, extendFn, FeelExpressions, FeelScripts } from '@0dep/bpmn-extensions';
package/dist/index.js CHANGED
@@ -11609,9 +11609,9 @@ function getSpecializer(spec) {
11609
11609
  *
11610
11610
  * @return {T[]}
11611
11611
  */
11612
- const nativeHasOwnProperty$1 = Object.prototype.hasOwnProperty;
11612
+ const nativeHasOwnProperty = Object.prototype.hasOwnProperty;
11613
11613
 
11614
- function isNil$2(obj) {
11614
+ function isNil$1(obj) {
11615
11615
  return obj == null;
11616
11616
  }
11617
11617
 
@@ -11623,8 +11623,8 @@ function isNil$2(obj) {
11623
11623
  *
11624
11624
  * @return {Boolean}
11625
11625
  */
11626
- function has$1(target, key) {
11627
- return !isNil$2(target) && nativeHasOwnProperty$1.call(target, key);
11626
+ function has(target, key) {
11627
+ return !isNil$1(target) && nativeHasOwnProperty.call(target, key);
11628
11628
  }
11629
11629
 
11630
11630
  let nextTagID = 0;
@@ -13107,7 +13107,7 @@ class VariableContext {
13107
13107
  continue;
13108
13108
  }
13109
13109
 
13110
- if (has$1(merged, key)) {
13110
+ if (has(merged, key)) {
13111
13111
 
13112
13112
  // deep merge nested contexts
13113
13113
  merged[key] = this.__merge(merged[key], value);
@@ -13241,7 +13241,7 @@ class Variables {
13241
13241
  return null;
13242
13242
  }
13243
13243
 
13244
- if (!isNil$2(scope.value)) {
13244
+ if (!isNil$1(scope.value)) {
13245
13245
  return scope.value;
13246
13246
  }
13247
13247
  }
@@ -13871,33 +13871,6 @@ const parser = LRParser.deserialize({
13871
13871
  tokenPrec: 2660
13872
13872
  });
13873
13873
 
13874
- /**
13875
- * Flatten array, one level deep.
13876
- *
13877
- * @template T
13878
- *
13879
- * @param {T[][] | T[] | null} [arr]
13880
- *
13881
- * @return {T[]}
13882
- */
13883
- const nativeHasOwnProperty = Object.prototype.hasOwnProperty;
13884
-
13885
- function isNil$1(obj) {
13886
- return obj == null;
13887
- }
13888
-
13889
- /**
13890
- * Return true, if target owns a property with the given key.
13891
- *
13892
- * @param {Object} target
13893
- * @param {String} key
13894
- *
13895
- * @return {Boolean}
13896
- */
13897
- function has(target, key) {
13898
- return !isNil$1(target) && nativeHasOwnProperty.call(target, key);
13899
- }
13900
-
13901
13874
  function isNil(e) {
13902
13875
  return e === null || e === undefined;
13903
13876
  }
@@ -16222,30 +16195,50 @@ function resolveValue(value, context) {
16222
16195
  return value;
16223
16196
  }
16224
16197
 
16198
+ /**
16199
+ * Build the FEEL evaluation scope for an environment. The environment services are exposed
16200
+ * under `services`, callable as FEEL functions (e.g. `services.isEligible(order)`) — resume-safe,
16201
+ * since the host re-supplies services at recover time, unlike functions smuggled through
16202
+ * variables, which JSON state serialization drops. The environment variables form the base
16203
+ * scope, overlaid with any local variables (a job result, element-local variables such as a
16204
+ * multi-instance item); a variable named `services` shadows the overlay.
16205
+ * @param {import('bpmn-elements').Environment} [environment]
16206
+ * @param {Record<string, any>} [localVariables] scope-local overlay
16207
+ * @returns {Record<string, any>}
16208
+ */
16209
+ function getFeelScope(environment, localVariables) {
16210
+ return { services: environment?.services, ...environment?.variables, ...localVariables };
16211
+ }
16212
+
16225
16213
  /**
16226
16214
  * Format an activity on enter from its behaviour and extensions: documentation and,
16227
- * for user tasks, the `zeebe:assignmentDefinition` (assignee, candidate users/groups).
16215
+ * for user tasks, the `zeebe:assignmentDefinition` (assignee, candidate users/groups),
16216
+ * `zeebe:priorityDefinition` (priority), and `zeebe:taskSchedule` (due/follow-up date).
16228
16217
  */
16229
16218
  class FormatActivity {
16230
16219
  /**
16231
16220
  * @param {import('bpmn-elements').Activity} activity
16232
16221
  * @param {any} assignmentDefinition
16222
+ * @param {any} [priorityDefinition]
16223
+ * @param {any} [taskSchedule]
16233
16224
  */
16234
- constructor(activity, assignmentDefinition) {
16225
+ constructor(activity, assignmentDefinition, priorityDefinition, taskSchedule) {
16235
16226
  this.activity = activity;
16236
16227
  this.assignmentDefinition = assignmentDefinition;
16228
+ this.priorityDefinition = priorityDefinition;
16229
+ this.taskSchedule = taskSchedule;
16237
16230
  }
16238
16231
  /**
16239
16232
  * @param {import('bpmn-elements').IApi<import('bpmn-elements').Activity>} elementApi
16240
16233
  */
16241
16234
  resolve(elementApi) {
16242
- const scope = elementApi.environment.variables;
16235
+ const scope = getFeelScope(elementApi.environment);
16243
16236
  const result = {};
16244
16237
 
16245
16238
  const documentation = this.activity.behaviour.documentation;
16246
16239
  if (documentation && !elementApi.content.description) {
16247
16240
  const text = documentation[0]?.text;
16248
- if (text) result.description = resolveValue(text, scope);
16241
+ if (text) result.description = /** @type {string} */ (resolveValue(text, scope));
16249
16242
  }
16250
16243
 
16251
16244
  const assignment = this.assignmentDefinition;
@@ -16258,6 +16251,22 @@ class FormatActivity {
16258
16251
  if (groups) result.candidateGroups = groups;
16259
16252
  }
16260
16253
 
16254
+ const priority = this.priorityDefinition?.priority;
16255
+ if (priority !== undefined) {
16256
+ const resolved = resolveValue(priority, scope);
16257
+ // A static attribute value is a string — expose a numeric one as a number (like retries).
16258
+ const num = Number(resolved);
16259
+ /** @type {Number | string | undefined} */
16260
+ result.priority = typeof resolved === 'string' && resolved.trim() !== '' && Number.isFinite(num) ? num : resolved;
16261
+ }
16262
+
16263
+ const schedule = this.taskSchedule;
16264
+ if (schedule) {
16265
+ const { dueDate, followUpDate } = schedule;
16266
+ if (dueDate !== undefined) result.dueDate = resolveDate(dueDate, scope);
16267
+ if (followUpDate !== undefined) result.followUpDate = resolveDate(followUpDate, scope);
16268
+ }
16269
+
16261
16270
  return result;
16262
16271
  }
16263
16272
  }
@@ -16280,15 +16289,33 @@ class FormatProcess {
16280
16289
  const documentation = this.process.behaviour.documentation;
16281
16290
  if (documentation && !elementApi.content.description) {
16282
16291
  const text = documentation[0]?.text;
16283
- if (text) result.description = resolveValue(text, elementApi.environment.variables);
16292
+ if (text) result.description = /** @type {string} */ (resolveValue(text, getFeelScope(elementApi.environment)));
16284
16293
  }
16285
16294
  return result;
16286
16295
  }
16287
16296
  }
16288
16297
 
16298
+ /**
16299
+ * Resolve a due/follow-up date to an ISO 8601 string. A FEEL temporal result (a luxon
16300
+ * DateTime) or a Date is ISO-stringified — content is JSON-serialized on `getState()`, so a
16301
+ * string is the shape that survives a recover round trip. Anything else passes through as-is.
16302
+ * @param {any} value
16303
+ * @param {any} scope
16304
+ * @returns {string | undefined} Date as iso string
16305
+ */
16306
+ function resolveDate(value, scope) {
16307
+ const resolved = resolveValue(value, scope);
16308
+ if (typeof resolved?.toISO === 'function') return resolved.toISO();
16309
+ if (resolved instanceof Date) return resolved.toISOString();
16310
+ return resolved;
16311
+ }
16312
+
16289
16313
  /**
16290
16314
  * Resolve a candidate users/groups value to a string array. A FEEL expression may yield an
16291
16315
  * array directly, otherwise a comma-separated string is split.
16316
+ * @param {any} value
16317
+ * @param {any} scope
16318
+ * @returns {string[] | undefined}
16292
16319
  */
16293
16320
  function resolveList(value, scope) {
16294
16321
  if (!value) return undefined;
@@ -16329,7 +16356,7 @@ class IoMapping {
16329
16356
  * @param {import('bpmn-elements').IApi<any>} elementApi
16330
16357
  */
16331
16358
  getInput(elementApi) {
16332
- const scope = elementApi.environment.variables;
16359
+ const scope = getFeelScope(elementApi.environment);
16333
16360
  const result = {};
16334
16361
  for (const { source, target } of this.inputParameters) {
16335
16362
  if (!target) continue;
@@ -16343,7 +16370,7 @@ class IoMapping {
16343
16370
  * @param {Record<string, any>} [jobResult] Variables produced by the job
16344
16371
  */
16345
16372
  getOutput(elementApi, jobResult) {
16346
- const scope = { ...elementApi.environment.variables, ...jobResult };
16373
+ const scope = getFeelScope(elementApi.environment, jobResult);
16347
16374
  const result = {};
16348
16375
  for (const { source, target } of this.outputParameters) {
16349
16376
  if (!target) continue;
@@ -16399,7 +16426,7 @@ class Properties {
16399
16426
  this.properties = properties.properties || [];
16400
16427
  }
16401
16428
  resolve(elementApi) {
16402
- const scope = elementApi.environment.variables;
16429
+ const scope = getFeelScope(elementApi.environment);
16403
16430
  const result = {};
16404
16431
  for (const { name, value } of this.properties) {
16405
16432
  if (name === undefined) continue;
@@ -16495,7 +16522,7 @@ class Form {
16495
16522
  this.formDefinition = formDefinition;
16496
16523
  }
16497
16524
  resolve(elementApi) {
16498
- const scope = elementApi.environment.variables;
16525
+ const scope = getFeelScope(elementApi.environment);
16499
16526
  const { formId, formKey, externalReference, bindingType, versionTag } = this.formDefinition;
16500
16527
  return {
16501
16528
  ...(formId !== undefined && { formId: resolveValue(formId, scope) }),
@@ -16528,7 +16555,7 @@ class LoopCharacteristics {
16528
16555
  }
16529
16556
  /**
16530
16557
  * @param {Record<string, any>|undefined} indexedOutput bpmn-elements index-keyed instance outputs
16531
- * @param {Record<string, any>} baseScope process variables in scope for `outputElement`
16558
+ * @param {Record<string, any>} baseScope base scope for `outputElement` (services + process variables)
16532
16559
  * @returns {any[]}
16533
16560
  */
16534
16561
  aggregate(indexedOutput, baseScope) {
@@ -16583,7 +16610,7 @@ JobService.prototype.execute = function execute(executionMessage, callback) {
16583
16610
 
16584
16611
  let jobType;
16585
16612
  try {
16586
- jobType = resolveValue(this.taskType, environment.variables);
16613
+ jobType = resolveValue(this.taskType, getFeelScope(environment));
16587
16614
  } catch (err) {
16588
16615
  return callback(err);
16589
16616
  }
@@ -16618,7 +16645,7 @@ class Subscription {
16618
16645
  resolve(elementApi) {
16619
16646
  return {
16620
16647
  message: this.message,
16621
- correlationKey: resolveValue(this.correlationKey, elementApi.environment.variables),
16648
+ correlationKey: resolveValue(this.correlationKey, getFeelScope(elementApi.environment)),
16622
16649
  };
16623
16650
  }
16624
16651
  }
@@ -16637,6 +16664,7 @@ class Subscription {
16637
16664
  * @property {any} [calledDecision]
16638
16665
  * @property {Function} [Service]
16639
16666
  * @property {Subscription} [subscription]
16667
+ * @property {boolean} [isEmpty] no zeebe extension data found and nothing to format — the element needs no extension
16640
16668
  */
16641
16669
 
16642
16670
  /**
@@ -16649,10 +16677,15 @@ function getExtensions(element, context) {
16649
16677
  const result = {};
16650
16678
  const isProcess = element.type === 'bpmn:Process';
16651
16679
 
16652
- let assignmentDefinition;
16680
+ let assignmentDefinition, priorityDefinition, taskSchedule;
16681
+ let foundZeebe = false;
16653
16682
  const values = element.behaviour.extensionElements?.values;
16654
16683
  if (values) {
16655
16684
  for (const ext of values) {
16685
+ // Any zeebe-namespaced extension element counts as found — including ones with no
16686
+ // handler (e.g. the bare `zeebe:userTask` marker), which keep the element extension
16687
+ // loaded so e.g. a native user task's completion payload is merged.
16688
+ if (ext.$type.startsWith('zeebe:')) foundZeebe = true;
16656
16689
  switch (ext.$type) {
16657
16690
  case 'zeebe:IoMapping':
16658
16691
  result.io = new IoMapping(element, ext);
@@ -16666,6 +16699,12 @@ function getExtensions(element, context) {
16666
16699
  case 'zeebe:AssignmentDefinition':
16667
16700
  assignmentDefinition = ext;
16668
16701
  break;
16702
+ case 'zeebe:PriorityDefinition':
16703
+ priorityDefinition = ext;
16704
+ break;
16705
+ case 'zeebe:TaskSchedule':
16706
+ taskSchedule = ext;
16707
+ break;
16669
16708
  case 'zeebe:ExecutionListeners':
16670
16709
  if (ext.listeners?.length) result.listeners = new ExecutionListeners(element, ext);
16671
16710
  break;
@@ -16707,7 +16746,16 @@ function getExtensions(element, context) {
16707
16746
  );
16708
16747
  if (loopExtension?.outputCollection) result.loop = new LoopCharacteristics(loopExtension);
16709
16748
 
16710
- result.format = isProcess ? new FormatProcess(element) : new FormatActivity(element, assignmentDefinition);
16749
+ // Nothing zeebe-flavoured and nothing to format — the element needs no extension. A call
16750
+ // activity is never inert: its output unwrap/merge is type-driven (the standard BPMN
16751
+ // `calledElement` attribute needs no zeebe elements). Ignored for processes — a called
16752
+ // process always needs its inbound input promoted, whatever it carries itself.
16753
+ result.isEmpty =
16754
+ !foundZeebe && !result.subscription && !loopExtension && !element.behaviour.documentation && element.type !== 'bpmn:CallActivity';
16755
+
16756
+ result.format = isProcess
16757
+ ? new FormatProcess(element)
16758
+ : new FormatActivity(element, assignmentDefinition, priorityDefinition, taskSchedule);
16711
16759
 
16712
16760
  return result;
16713
16761
  }
@@ -16846,7 +16894,7 @@ class ElementExtensions {
16846
16894
 
16847
16895
  // Multi-instance: aggregate the per-instance outputs into the `outputCollection` array.
16848
16896
  if (loop?.hasOutputCollection) {
16849
- const output = { [loop.outputCollection]: loop.aggregate(jobResult, elementApi.environment.variables) };
16897
+ const output = { [loop.outputCollection]: loop.aggregate(jobResult, getFeelScope(elementApi.environment)) };
16850
16898
  this.#assignOutput(elementApi, output);
16851
16899
  return { output };
16852
16900
  }
@@ -17009,22 +17057,14 @@ function hasExpression(text) {
17009
17057
 
17010
17058
  /**
17011
17059
  * Resolve a templated string. Static literals are returned as-is; FEEL expressions are
17012
- * evaluated against the environment variables (overlaid with any element-local variables).
17060
+ * evaluated in the environment scope (see `getFeelScope`), overlaid with any element-local
17061
+ * variables carried on the message content (e.g. a multi-instance item).
17013
17062
  * @param {string} templatedString
17014
17063
  * @param {{ environment?: import('bpmn-elements').Environment, content?: any }} [context]
17015
17064
  */
17016
17065
  function resolveExpression(templatedString, context) {
17017
17066
  if (!isFeelExpression(templatedString)) return templatedString;
17018
- return evaluateFeel(templatedString, getScope(context));
17019
- }
17020
-
17021
- /**
17022
- * Build the FEEL variable scope from a resolution context. Process/definition variables form
17023
- * the base scope, overlaid with any local variables carried on the element message content
17024
- * (e.g. a multi-instance item).
17025
- */
17026
- function getScope(context) {
17027
- return { ...context?.environment?.variables, ...context?.content?.variables };
17067
+ return evaluateFeel(templatedString, getFeelScope(context?.environment, context?.content?.variables));
17028
17068
  }
17029
17069
 
17030
17070
  /**
@@ -17049,12 +17089,12 @@ class FeelScriptRegistry {
17049
17089
  /**
17050
17090
  * @param {string} _scriptFormat
17051
17091
  * @param {{ id: string, [x: string]: any }} activity
17052
- * @returns {import('bpmn-elements').Script} the FEEL script, or undefined when the activity
17053
- * has no `zeebe:script` — bpmn-elements handles that, but `IScripts` declares a bare `Script`
17092
+ * @returns {import('bpmn-elements').Script | undefined} the FEEL script, or undefined when
17093
+ * the activity has no `zeebe:script`
17054
17094
  */
17055
17095
  getScript(_scriptFormat, activity) {
17056
17096
  const expression = getScriptExpression(activity);
17057
- if (expression === undefined) return /** @type {any} */ (undefined);
17097
+ if (expression === undefined) return undefined;
17058
17098
  return new FeelScript(expression);
17059
17099
  }
17060
17100
  }
@@ -17065,7 +17105,7 @@ class FeelScript {
17065
17105
  }
17066
17106
  execute(scope, callback) {
17067
17107
  try {
17068
- const value = isFeelExpression(this.expression) ? evaluateFeel(this.expression, { ...scope.environment.variables }) : this.expression;
17108
+ const value = isFeelExpression(this.expression) ? evaluateFeel(this.expression, getFeelScope(scope.environment)) : this.expression;
17069
17109
  callback(null, value);
17070
17110
  } catch (err) {
17071
17111
  callback(err);
@@ -17092,20 +17132,32 @@ function getScriptExpression(activity) {
17092
17132
 
17093
17133
  /**
17094
17134
  * Flow extensions factory. Pass it to the engine via the environment `extensions` option.
17135
+ *
17136
+ * Returns undefined for an element that carries no zeebe extension data and nothing else to
17137
+ * format (no documentation, not a call activity) — bpmn-elements skips falsy extensions, so
17138
+ * plain elements run untouched, with no broker subscriptions or format-queue traffic.
17095
17139
  * @param {import('bpmn-elements').Activity | import('bpmn-elements').Process} element
17096
17140
  * @param {import('bpmn-elements').ContextInstance} context
17097
- * @returns {FlowExtension}
17141
+ * @returns {FlowExtension | undefined}
17098
17142
  */
17099
17143
  function extensions(element, context) {
17100
17144
  switch (element.type) {
17101
17145
  case 'bpmn:Process':
17146
+ // A process is always attached: a called process needs its inbound input promoted
17147
+ // even when it carries no zeebe extension data of its own.
17102
17148
  return new ProcessExtensions(element, context);
17103
17149
  case 'bpmn:SubProcess':
17104
17150
  case 'bpmn:AdHocSubProcess':
17105
- case 'bpmn:Transaction':
17106
- return new SubProcessExtensions(element, context);
17107
- default:
17108
- return new ElementExtensions(element, context);
17151
+ case 'bpmn:Transaction': {
17152
+ const subProcessExtensions = new SubProcessExtensions(element, context);
17153
+ if (subProcessExtensions.extensions.isEmpty) return undefined;
17154
+ return subProcessExtensions;
17155
+ }
17156
+ default: {
17157
+ const elementExtensions = new ElementExtensions(element, context);
17158
+ if (elementExtensions.extensions.isEmpty) return undefined;
17159
+ return elementExtensions;
17160
+ }
17109
17161
  }
17110
17162
  }
17111
17163
 
@@ -17149,6 +17201,7 @@ exports.evaluateFeel = evaluateFeel;
17149
17201
  exports.evaluateFeelUnaryTest = evaluateFeelUnaryTest;
17150
17202
  exports.extendFn = extendFn;
17151
17203
  exports.extensions = extensions;
17204
+ exports.getFeelScope = getFeelScope;
17152
17205
  exports.isFeelExpression = isFeelExpression;
17153
17206
  exports.resolveValue = resolveValue;
17154
17207
  exports.stripFeel = stripFeel;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@0dep/bpmn-extensions",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "description": "Flow extensions for bpmn-elements: FEEL expressions and the zeebe-namespace BPMN extension elements",
5
5
  "type": "module",
6
6
  "module": "src/index.js",
@@ -69,7 +69,7 @@
69
69
  "@types/mocha": "^10.0.10",
70
70
  "@types/node": "^26.1.1",
71
71
  "bpmn-elements": "^18.0.12",
72
- "bpmn-moddle": "^9.0.1",
72
+ "bpmn-moddle": "^10.1.0",
73
73
  "c8": "^12.0.0",
74
74
  "chai": "^6.2.2",
75
75
  "debug": "^4.4.3",
@@ -1,4 +1,5 @@
1
1
  import { getExtensions } from './getExtensions.js';
2
+ import { getFeelScope } from './feel.js';
2
3
 
3
4
  const SUBPROCESS_TYPES = new Set(['bpmn:SubProcess', 'bpmn:AdHocSubProcess', 'bpmn:Transaction']);
4
5
 
@@ -134,7 +135,7 @@ export class ElementExtensions {
134
135
 
135
136
  // Multi-instance: aggregate the per-instance outputs into the `outputCollection` array.
136
137
  if (loop?.hasOutputCollection) {
137
- const output = { [loop.outputCollection]: loop.aggregate(jobResult, elementApi.environment.variables) };
138
+ const output = { [loop.outputCollection]: loop.aggregate(jobResult, getFeelScope(elementApi.environment)) };
138
139
  this.#assignOutput(elementApi, output);
139
140
  return { output };
140
141
  }
@@ -1,4 +1,4 @@
1
- import { isFeelExpression, evaluateFeel } from './feel.js';
1
+ import { isFeelExpression, evaluateFeel, getFeelScope } from './feel.js';
2
2
 
3
3
  /**
4
4
  * FEEL-aware expressions implementation for bpmn-elements.
@@ -27,20 +27,12 @@ function hasExpression(text) {
27
27
 
28
28
  /**
29
29
  * Resolve a templated string. Static literals are returned as-is; FEEL expressions are
30
- * evaluated against the environment variables (overlaid with any element-local variables).
30
+ * evaluated in the environment scope (see `getFeelScope`), overlaid with any element-local
31
+ * variables carried on the message content (e.g. a multi-instance item).
31
32
  * @param {string} templatedString
32
33
  * @param {{ environment?: import('bpmn-elements').Environment, content?: any }} [context]
33
34
  */
34
35
  function resolveExpression(templatedString, context) {
35
36
  if (!isFeelExpression(templatedString)) return templatedString;
36
- return evaluateFeel(templatedString, getScope(context));
37
- }
38
-
39
- /**
40
- * Build the FEEL variable scope from a resolution context. Process/definition variables form
41
- * the base scope, overlaid with any local variables carried on the element message content
42
- * (e.g. a multi-instance item).
43
- */
44
- function getScope(context) {
45
- return { ...context?.environment?.variables, ...context?.content?.variables };
37
+ return evaluateFeel(templatedString, getFeelScope(context?.environment, context?.content?.variables));
46
38
  }
@@ -1,4 +1,4 @@
1
- import { isFeelExpression, evaluateFeel } from '../feel.js';
1
+ import { isFeelExpression, evaluateFeel, getFeelScope } from '../feel.js';
2
2
 
3
3
  /**
4
4
  * A bpmn-elements `scripts` implementation for script tasks.
@@ -22,12 +22,12 @@ class FeelScriptRegistry {
22
22
  /**
23
23
  * @param {string} _scriptFormat
24
24
  * @param {{ id: string, [x: string]: any }} activity
25
- * @returns {import('bpmn-elements').Script} the FEEL script, or undefined when the activity
26
- * has no `zeebe:script` — bpmn-elements handles that, but `IScripts` declares a bare `Script`
25
+ * @returns {import('bpmn-elements').Script | undefined} the FEEL script, or undefined when
26
+ * the activity has no `zeebe:script`
27
27
  */
28
28
  getScript(_scriptFormat, activity) {
29
29
  const expression = getScriptExpression(activity);
30
- if (expression === undefined) return /** @type {any} */ (undefined);
30
+ if (expression === undefined) return undefined;
31
31
  return new FeelScript(expression);
32
32
  }
33
33
  }
@@ -38,7 +38,7 @@ class FeelScript {
38
38
  }
39
39
  execute(scope, callback) {
40
40
  try {
41
- const value = isFeelExpression(this.expression) ? evaluateFeel(this.expression, { ...scope.environment.variables }) : this.expression;
41
+ const value = isFeelExpression(this.expression) ? evaluateFeel(this.expression, getFeelScope(scope.environment)) : this.expression;
42
42
  callback(null, value);
43
43
  } catch (err) {
44
44
  callback(err);
@@ -1,4 +1,4 @@
1
- import { resolveValue } from '../feel.js';
1
+ import { resolveValue, getFeelScope } from '../feel.js';
2
2
 
3
3
  /**
4
4
  * `zeebe:formDefinition`.
@@ -13,7 +13,7 @@ export class Form {
13
13
  this.formDefinition = formDefinition;
14
14
  }
15
15
  resolve(elementApi) {
16
- const scope = elementApi.environment.variables;
16
+ const scope = getFeelScope(elementApi.environment);
17
17
  const { formId, formKey, externalReference, bindingType, versionTag } = this.formDefinition;
18
18
  return {
19
19
  ...(formId !== undefined && { formId: resolveValue(formId, scope) }),
@@ -1,4 +1,4 @@
1
- import { resolveValue } from '../feel.js';
1
+ import { resolveValue, getFeelScope } from '../feel.js';
2
2
 
3
3
  /**
4
4
  * `zeebe:ioMapping`.
@@ -28,7 +28,7 @@ export class IoMapping {
28
28
  * @param {import('bpmn-elements').IApi<any>} elementApi
29
29
  */
30
30
  getInput(elementApi) {
31
- const scope = elementApi.environment.variables;
31
+ const scope = getFeelScope(elementApi.environment);
32
32
  const result = {};
33
33
  for (const { source, target } of this.inputParameters) {
34
34
  if (!target) continue;
@@ -42,7 +42,7 @@ export class IoMapping {
42
42
  * @param {Record<string, any>} [jobResult] Variables produced by the job
43
43
  */
44
44
  getOutput(elementApi, jobResult) {
45
- const scope = { ...elementApi.environment.variables, ...jobResult };
45
+ const scope = getFeelScope(elementApi.environment, jobResult);
46
46
  const result = {};
47
47
  for (const { source, target } of this.outputParameters) {
48
48
  if (!target) continue;
@@ -21,7 +21,7 @@ export class LoopCharacteristics {
21
21
  }
22
22
  /**
23
23
  * @param {Record<string, any>|undefined} indexedOutput bpmn-elements index-keyed instance outputs
24
- * @param {Record<string, any>} baseScope process variables in scope for `outputElement`
24
+ * @param {Record<string, any>} baseScope base scope for `outputElement` (services + process variables)
25
25
  * @returns {any[]}
26
26
  */
27
27
  aggregate(indexedOutput, baseScope) {
@@ -1,4 +1,4 @@
1
- import { resolveValue } from '../feel.js';
1
+ import { resolveValue, getFeelScope } from '../feel.js';
2
2
 
3
3
  /**
4
4
  * `zeebe:properties`.
@@ -11,7 +11,7 @@ export class Properties {
11
11
  this.properties = properties.properties || [];
12
12
  }
13
13
  resolve(elementApi) {
14
- const scope = elementApi.environment.variables;
14
+ const scope = getFeelScope(elementApi.environment);
15
15
  const result = {};
16
16
  for (const { name, value } of this.properties) {
17
17
  if (name === undefined) continue;
@@ -1,4 +1,4 @@
1
- import { resolveValue } from '../feel.js';
1
+ import { resolveValue, getFeelScope } from '../feel.js';
2
2
 
3
3
  /**
4
4
  * `zeebe:subscription` — rides on the referenced `bpmn:Message`, not on the catching element.
@@ -24,7 +24,7 @@ export class Subscription {
24
24
  resolve(elementApi) {
25
25
  return {
26
26
  message: this.message,
27
- correlationKey: resolveValue(this.correlationKey, elementApi.environment.variables),
27
+ correlationKey: resolveValue(this.correlationKey, getFeelScope(elementApi.environment)),
28
28
  };
29
29
  }
30
30
  }
@@ -1,5 +1,5 @@
1
1
  import { ServiceError } from '../Errors.js';
2
- import { resolveValue } from '../feel.js';
2
+ import { resolveValue, getFeelScope } from '../feel.js';
3
3
 
4
4
  /**
5
5
  * `zeebe:taskDefinition`.
@@ -34,7 +34,7 @@ JobService.prototype.execute = function execute(executionMessage, callback) {
34
34
 
35
35
  let jobType;
36
36
  try {
37
- jobType = resolveValue(this.taskType, environment.variables);
37
+ jobType = resolveValue(this.taskType, getFeelScope(environment));
38
38
  } catch (err) {
39
39
  return callback(err);
40
40
  }
@@ -1,29 +1,34 @@
1
- import { resolveValue } from '../feel.js';
1
+ import { resolveValue, getFeelScope } from '../feel.js';
2
2
 
3
3
  /**
4
4
  * Format an activity on enter from its behaviour and extensions: documentation and,
5
- * for user tasks, the `zeebe:assignmentDefinition` (assignee, candidate users/groups).
5
+ * for user tasks, the `zeebe:assignmentDefinition` (assignee, candidate users/groups),
6
+ * `zeebe:priorityDefinition` (priority), and `zeebe:taskSchedule` (due/follow-up date).
6
7
  */
7
8
  export class FormatActivity {
8
9
  /**
9
10
  * @param {import('bpmn-elements').Activity} activity
10
11
  * @param {any} assignmentDefinition
12
+ * @param {any} [priorityDefinition]
13
+ * @param {any} [taskSchedule]
11
14
  */
12
- constructor(activity, assignmentDefinition) {
15
+ constructor(activity, assignmentDefinition, priorityDefinition, taskSchedule) {
13
16
  this.activity = activity;
14
17
  this.assignmentDefinition = assignmentDefinition;
18
+ this.priorityDefinition = priorityDefinition;
19
+ this.taskSchedule = taskSchedule;
15
20
  }
16
21
  /**
17
22
  * @param {import('bpmn-elements').IApi<import('bpmn-elements').Activity>} elementApi
18
23
  */
19
24
  resolve(elementApi) {
20
- const scope = elementApi.environment.variables;
25
+ const scope = getFeelScope(elementApi.environment);
21
26
  const result = {};
22
27
 
23
28
  const documentation = this.activity.behaviour.documentation;
24
29
  if (documentation && !elementApi.content.description) {
25
30
  const text = documentation[0]?.text;
26
- if (text) result.description = resolveValue(text, scope);
31
+ if (text) result.description = /** @type {string} */ (resolveValue(text, scope));
27
32
  }
28
33
 
29
34
  const assignment = this.assignmentDefinition;
@@ -36,6 +41,22 @@ export class FormatActivity {
36
41
  if (groups) result.candidateGroups = groups;
37
42
  }
38
43
 
44
+ const priority = this.priorityDefinition?.priority;
45
+ if (priority !== undefined) {
46
+ const resolved = resolveValue(priority, scope);
47
+ // A static attribute value is a string — expose a numeric one as a number (like retries).
48
+ const num = Number(resolved);
49
+ /** @type {Number | string | undefined} */
50
+ result.priority = typeof resolved === 'string' && resolved.trim() !== '' && Number.isFinite(num) ? num : resolved;
51
+ }
52
+
53
+ const schedule = this.taskSchedule;
54
+ if (schedule) {
55
+ const { dueDate, followUpDate } = schedule;
56
+ if (dueDate !== undefined) result.dueDate = resolveDate(dueDate, scope);
57
+ if (followUpDate !== undefined) result.followUpDate = resolveDate(followUpDate, scope);
58
+ }
59
+
39
60
  return result;
40
61
  }
41
62
  }
@@ -58,15 +79,33 @@ export class FormatProcess {
58
79
  const documentation = this.process.behaviour.documentation;
59
80
  if (documentation && !elementApi.content.description) {
60
81
  const text = documentation[0]?.text;
61
- if (text) result.description = resolveValue(text, elementApi.environment.variables);
82
+ if (text) result.description = /** @type {string} */ (resolveValue(text, getFeelScope(elementApi.environment)));
62
83
  }
63
84
  return result;
64
85
  }
65
86
  }
66
87
 
88
+ /**
89
+ * Resolve a due/follow-up date to an ISO 8601 string. A FEEL temporal result (a luxon
90
+ * DateTime) or a Date is ISO-stringified — content is JSON-serialized on `getState()`, so a
91
+ * string is the shape that survives a recover round trip. Anything else passes through as-is.
92
+ * @param {any} value
93
+ * @param {any} scope
94
+ * @returns {string | undefined} Date as iso string
95
+ */
96
+ function resolveDate(value, scope) {
97
+ const resolved = resolveValue(value, scope);
98
+ if (typeof resolved?.toISO === 'function') return resolved.toISO();
99
+ if (resolved instanceof Date) return resolved.toISOString();
100
+ return resolved;
101
+ }
102
+
67
103
  /**
68
104
  * Resolve a candidate users/groups value to a string array. A FEEL expression may yield an
69
105
  * array directly, otherwise a comma-separated string is split.
106
+ * @param {any} value
107
+ * @param {any} scope
108
+ * @returns {string[] | undefined}
70
109
  */
71
110
  function resolveList(value, scope) {
72
111
  if (!value) return undefined;
package/src/feel.js CHANGED
@@ -58,3 +58,18 @@ export function resolveValue(value, context) {
58
58
  if (isFeelExpression(value)) return evaluateFeel(value, context);
59
59
  return value;
60
60
  }
61
+
62
+ /**
63
+ * Build the FEEL evaluation scope for an environment. The environment services are exposed
64
+ * under `services`, callable as FEEL functions (e.g. `services.isEligible(order)`) — resume-safe,
65
+ * since the host re-supplies services at recover time, unlike functions smuggled through
66
+ * variables, which JSON state serialization drops. The environment variables form the base
67
+ * scope, overlaid with any local variables (a job result, element-local variables such as a
68
+ * multi-instance item); a variable named `services` shadows the overlay.
69
+ * @param {import('bpmn-elements').Environment} [environment]
70
+ * @param {Record<string, any>} [localVariables] scope-local overlay
71
+ * @returns {Record<string, any>}
72
+ */
73
+ export function getFeelScope(environment, localVariables) {
74
+ return { services: environment?.services, ...environment?.variables, ...localVariables };
75
+ }
@@ -22,6 +22,7 @@ import { Subscription } from './extensions/Subscription.js';
22
22
  * @property {any} [calledDecision]
23
23
  * @property {Function} [Service]
24
24
  * @property {Subscription} [subscription]
25
+ * @property {boolean} [isEmpty] no zeebe extension data found and nothing to format — the element needs no extension
25
26
  */
26
27
 
27
28
  /**
@@ -34,10 +35,15 @@ export function getExtensions(element, context) {
34
35
  const result = {};
35
36
  const isProcess = element.type === 'bpmn:Process';
36
37
 
37
- let assignmentDefinition;
38
+ let assignmentDefinition, priorityDefinition, taskSchedule;
39
+ let foundZeebe = false;
38
40
  const values = element.behaviour.extensionElements?.values;
39
41
  if (values) {
40
42
  for (const ext of values) {
43
+ // Any zeebe-namespaced extension element counts as found — including ones with no
44
+ // handler (e.g. the bare `zeebe:userTask` marker), which keep the element extension
45
+ // loaded so e.g. a native user task's completion payload is merged.
46
+ if (ext.$type.startsWith('zeebe:')) foundZeebe = true;
41
47
  switch (ext.$type) {
42
48
  case 'zeebe:IoMapping':
43
49
  result.io = new IoMapping(element, ext);
@@ -51,6 +57,12 @@ export function getExtensions(element, context) {
51
57
  case 'zeebe:AssignmentDefinition':
52
58
  assignmentDefinition = ext;
53
59
  break;
60
+ case 'zeebe:PriorityDefinition':
61
+ priorityDefinition = ext;
62
+ break;
63
+ case 'zeebe:TaskSchedule':
64
+ taskSchedule = ext;
65
+ break;
54
66
  case 'zeebe:ExecutionListeners':
55
67
  if (ext.listeners?.length) result.listeners = new ExecutionListeners(element, ext);
56
68
  break;
@@ -92,7 +104,16 @@ export function getExtensions(element, context) {
92
104
  );
93
105
  if (loopExtension?.outputCollection) result.loop = new LoopCharacteristics(loopExtension);
94
106
 
95
- result.format = isProcess ? new FormatProcess(element) : new FormatActivity(element, assignmentDefinition);
107
+ // Nothing zeebe-flavoured and nothing to format — the element needs no extension. A call
108
+ // activity is never inert: its output unwrap/merge is type-driven (the standard BPMN
109
+ // `calledElement` attribute needs no zeebe elements). Ignored for processes — a called
110
+ // process always needs its inbound input promoted, whatever it carries itself.
111
+ result.isEmpty =
112
+ !foundZeebe && !result.subscription && !loopExtension && !element.behaviour.documentation && element.type !== 'bpmn:CallActivity';
113
+
114
+ result.format = isProcess
115
+ ? new FormatProcess(element)
116
+ : new FormatActivity(element, assignmentDefinition, priorityDefinition, taskSchedule);
96
117
 
97
118
  return result;
98
119
  }
package/src/index.js CHANGED
@@ -5,7 +5,7 @@ import { SubProcessExtensions } from './SubProcessExtensions.js';
5
5
  export { ElementExtensions, ProcessExtensions, SubProcessExtensions };
6
6
  export { FeelExpressions } from './Expressions.js';
7
7
  export { FeelScripts } from './extensions/FeelScripts.js';
8
- export { isFeelExpression, stripFeel, evaluateFeel, evaluateFeelUnaryTest, resolveValue } from './feel.js';
8
+ export { isFeelExpression, stripFeel, evaluateFeel, evaluateFeelUnaryTest, resolveValue, getFeelScope } from './feel.js';
9
9
  export { JobService } from './extensions/TaskDefinition.js';
10
10
  export { ServiceError, FormatError } from './Errors.js';
11
11
 
@@ -18,20 +18,32 @@ export { ServiceError, FormatError } from './Errors.js';
18
18
 
19
19
  /**
20
20
  * Flow extensions factory. Pass it to the engine via the environment `extensions` option.
21
+ *
22
+ * Returns undefined for an element that carries no zeebe extension data and nothing else to
23
+ * format (no documentation, not a call activity) — bpmn-elements skips falsy extensions, so
24
+ * plain elements run untouched, with no broker subscriptions or format-queue traffic.
21
25
  * @param {import('bpmn-elements').Activity | import('bpmn-elements').Process} element
22
26
  * @param {import('bpmn-elements').ContextInstance} context
23
- * @returns {FlowExtension}
27
+ * @returns {FlowExtension | undefined}
24
28
  */
25
29
  export function extensions(element, context) {
26
30
  switch (element.type) {
27
31
  case 'bpmn:Process':
32
+ // A process is always attached: a called process needs its inbound input promoted
33
+ // even when it carries no zeebe extension data of its own.
28
34
  return new ProcessExtensions(element, context);
29
35
  case 'bpmn:SubProcess':
30
36
  case 'bpmn:AdHocSubProcess':
31
- case 'bpmn:Transaction':
32
- return new SubProcessExtensions(element, context);
33
- default:
34
- return new ElementExtensions(element, context);
37
+ case 'bpmn:Transaction': {
38
+ const subProcessExtensions = new SubProcessExtensions(element, context);
39
+ if (subProcessExtensions.extensions.isEmpty) return undefined;
40
+ return subProcessExtensions;
41
+ }
42
+ default: {
43
+ const elementExtensions = new ElementExtensions(element, context);
44
+ if (elementExtensions.extensions.isEmpty) return undefined;
45
+ return elementExtensions;
46
+ }
35
47
  }
36
48
  }
37
49
 
package/types/index.d.ts CHANGED
@@ -4,8 +4,12 @@ declare module '@0dep/bpmn-extensions' {
4
4
  * */
5
5
  /**
6
6
  * Flow extensions factory. Pass it to the engine via the environment `extensions` option.
7
+ *
8
+ * Returns undefined for an element that carries no zeebe extension data and nothing else to
9
+ * format (no documentation, not a call activity) — bpmn-elements skips falsy extensions, so
10
+ * plain elements run untouched, with no broker subscriptions or format-queue traffic.
7
11
  * */
8
- export function extensions(element: import("bpmn-elements").Activity | import("bpmn-elements").Process, context: import("bpmn-elements").ContextInstance): FlowExtension;
12
+ export function extensions(element: import("bpmn-elements").Activity | import("bpmn-elements").Process, context: import("bpmn-elements").ContextInstance): FlowExtension | undefined;
9
13
  /**
10
14
  * Behaviour extend function for moddle-context-serializer.
11
15
  *
@@ -171,6 +175,16 @@ declare module '@0dep/bpmn-extensions' {
171
175
  * @param context Variables in scope for FEEL evaluation
172
176
  * */
173
177
  export function resolveValue(value: any, context?: Record<string, any>): any;
178
+ /**
179
+ * Build the FEEL evaluation scope for an environment. The environment services are exposed
180
+ * under `services`, callable as FEEL functions (e.g. `services.isEligible(order)`) — resume-safe,
181
+ * since the host re-supplies services at recover time, unlike functions smuggled through
182
+ * variables, which JSON state serialization drops. The environment variables form the base
183
+ * scope, overlaid with any local variables (a job result, element-local variables such as a
184
+ * multi-instance item); a variable named `services` shadows the overlay.
185
+ * @param localVariables scope-local overlay
186
+ * */
187
+ export function getFeelScope(environment?: import("bpmn-elements").Environment, localVariables?: Record<string, any>): Record<string, any>;
174
188
  export class ServiceError extends Error {
175
189
  constructor(jobType: any);
176
190
  code: string;
@@ -200,22 +214,33 @@ declare module '@0dep/bpmn-extensions' {
200
214
  calledDecision?: any;
201
215
  Service?: Function | undefined;
202
216
  subscription?: Subscription | undefined;
217
+ /**
218
+ * no zeebe extension data found and nothing to format — the element needs no extension
219
+ */
220
+ isEmpty?: boolean | undefined;
203
221
  };
204
222
  /**
205
223
  * Format an activity on enter from its behaviour and extensions: documentation and,
206
- * for user tasks, the `zeebe:assignmentDefinition` (assignee, candidate users/groups).
224
+ * for user tasks, the `zeebe:assignmentDefinition` (assignee, candidate users/groups),
225
+ * `zeebe:priorityDefinition` (priority), and `zeebe:taskSchedule` (due/follow-up date).
207
226
  */
208
227
  class FormatActivity {
209
228
 
210
- constructor(activity: import("bpmn-elements").Activity, assignmentDefinition: any);
229
+ constructor(activity: import("bpmn-elements").Activity, assignmentDefinition: any, priorityDefinition?: any, taskSchedule?: any);
211
230
  activity: import("bpmn-elements").Activity;
212
231
  assignmentDefinition: any;
232
+ priorityDefinition: any;
233
+ taskSchedule: any;
213
234
 
214
235
  resolve(elementApi: import("bpmn-elements").IApi<import("bpmn-elements").Activity>): {
215
- description: any;
236
+ description: string;
216
237
  assignee: any;
217
- candidateUsers: any[];
218
- candidateGroups: any[];
238
+ candidateUsers: string[];
239
+ candidateGroups: string[];
240
+
241
+ priority: number | string | undefined;
242
+ dueDate: string | undefined;
243
+ followUpDate: string | undefined;
219
244
  };
220
245
  }
221
246
  /**
@@ -227,7 +252,7 @@ declare module '@0dep/bpmn-extensions' {
227
252
  process: import("bpmn-elements").Process;
228
253
 
229
254
  resolve(elementApi: import("bpmn-elements").IApi<import("bpmn-elements").Process>): {
230
- description: any;
255
+ description: string;
231
256
  };
232
257
  }
233
258
  /**
@@ -338,7 +363,7 @@ declare module '@0dep/bpmn-extensions' {
338
363
  get hasOutputCollection(): boolean;
339
364
  /**
340
365
  * @param indexedOutput bpmn-elements index-keyed instance outputs
341
- * @param baseScope process variables in scope for `outputElement`
366
+ * @param baseScope base scope for `outputElement` (services + process variables)
342
367
  * */
343
368
  aggregate(indexedOutput: Record<string, any> | undefined, baseScope: Record<string, any>): any[];
344
369
  }
@@ -15,6 +15,7 @@
15
15
  "evaluateFeel",
16
16
  "evaluateFeelUnaryTest",
17
17
  "resolveValue",
18
+ "getFeelScope",
18
19
  "ServiceError",
19
20
  "FormatError",
20
21
  "FormatActivity",
@@ -65,6 +66,6 @@
65
66
  null,
66
67
  null
67
68
  ],
68
- "mappings": ";;;;;;;iBAwBgBA,UAAUA;;;;;;;;iBAqBVC,QAAQA;;;;;;;;;;;;;;;;iBClCRC,eAAeA;;;;;;;;;;;;;;iBCEfC,WAAWA;;;;;;;;;;;;;;;iBCIXC,UAAUA;cAAVA,UAAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cCCbC,iBAAiBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cCXjBC,iBAAiBA;;;;;;;;;;;;;;;;;;;cCIjBC,oBAAoBA;;;;;;;iBCEjBC,gBAAgBA;;;;iBAShBC,SAASA;;;;;;iBAUTC,YAAYA;;;;;;;;iBAYZC,qBAAqBA;;;;;;iBAYrBC,YAAYA;cCxDfC,YAAYA;;;;;;;cAQZC,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;OCFXC,cAAcA;;;;;;;;;;;;;;;;OAuCdC,aAAaA;;;;;;;;;;;;;;;;;;;;OChCbC,SAASA;;;;;;;;;;;;;;;;;;;;;;;OCPTC,WAAWA;;;;;;;;;;;OCEXC,UAAUA;;;;;;;;;;;;;;;OCIVC,kBAAkBA;;;;;;;;;;;;;;;;;;;OCFlBC,IAAIA;;;;;;;;;;;;;;;;;;;;;;OCGJC,mBAAmBA;;;;;;;;;;;;;;;;;;;OCHnBC,YAAYA",
69
+ "mappings": ";;;;;;;;;;;iBA4BgBA,UAAUA;;;;;;;;iBA6BVC,QAAQA;;;;;;;;;;;;;;;;iBC9CRC,eAAeA;;;;;;;;;;;;;;iBCEfC,WAAWA;;;;;;;;;;;;;;;iBCIXC,UAAUA;cAAVA,UAAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cCEbC,iBAAiBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cCZjBC,iBAAiBA;;;;;;;;;;;;;;;;;;;cCIjBC,oBAAoBA;;;;;;;iBCEjBC,gBAAgBA;;;;iBAShBC,SAASA;;;;;;iBAUTC,YAAYA;;;;;;;;iBAYZC,qBAAqBA;;;;;;iBAYrBC,YAAYA;;;;;;;;;;iBAgBZC,YAAYA;cCxEfC,YAAYA;;;;;;;cAQZC,WAAWA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OCDXC,cAAcA;;;;;;;;;;;;;;;;;;;;;;OA2DdC,aAAaA;;;;;;;;;;;;;;;;;;;;OCrDbC,SAASA;;;;;;;;;;;;;;;;;;;;;;;OCPTC,WAAWA;;;;;;;;;;;OCEXC,UAAUA;;;;;;;;;;;;;;;OCIVC,kBAAkBA;;;;;;;;;;;;;;;;;;;OCFlBC,IAAIA;;;;;;;;;;;;;;;;;;;;;;OCGJC,mBAAmBA;;;;;;;;;;;;;;;;;;;OCHnBC,YAAYA",
69
70
  "ignoreList": []
70
71
  }