@0dep/bpmn-extensions 0.0.3 → 0.0.4
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 +8 -1
- package/dist/index.js +33 -25
- package/package.json +1 -1
- package/src/ElementExtensions.js +2 -1
- package/src/Expressions.js +4 -12
- package/src/extensions/FeelScripts.js +5 -5
- package/src/extensions/Form.js +2 -2
- package/src/extensions/IoMapping.js +3 -3
- package/src/extensions/LoopCharacteristics.js +1 -1
- package/src/extensions/Properties.js +2 -2
- package/src/extensions/Subscription.js +2 -2
- package/src/extensions/TaskDefinition.js +2 -2
- package/src/extensions/formatters.js +3 -3
- package/src/feel.js +15 -0
- package/src/index.js +1 -1
- package/types/index.d.ts +11 -1
- package/types/index.d.ts.map +2 -1
package/README.md
CHANGED
|
@@ -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).
|
|
@@ -52,7 +58,8 @@ npm install @0dep/bpmn-extensions bpmn-elements
|
|
|
52
58
|
bpmn-elements expects on the behaviour: call activity process id and multi-instance collection).
|
|
53
59
|
- `FeelExpressions()` — a bpmn-elements `IExpressions` implementation backed by FEEL.
|
|
54
60
|
- `FeelScripts()` — a bpmn-elements `scripts` implementation that runs `zeebe:script` FEEL expressions.
|
|
55
|
-
- FEEL helpers: `isFeelExpression`, `stripFeel`, `evaluateFeel`, `evaluateFeelUnaryTest`, `resolveValue
|
|
61
|
+
- FEEL helpers: `isFeelExpression`, `stripFeel`, `evaluateFeel`, `evaluateFeelUnaryTest`, `resolveValue`,
|
|
62
|
+
`getFeelScope` (the scope every expression is evaluated in: `services` + environment variables + local overlay).
|
|
56
63
|
- `JobService`, `ServiceError`, `FormatError`.
|
|
57
64
|
|
|
58
65
|
## Usage
|
package/dist/index.js
CHANGED
|
@@ -16222,6 +16222,21 @@ function resolveValue(value, context) {
|
|
|
16222
16222
|
return value;
|
|
16223
16223
|
}
|
|
16224
16224
|
|
|
16225
|
+
/**
|
|
16226
|
+
* Build the FEEL evaluation scope for an environment. The environment services are exposed
|
|
16227
|
+
* under `services`, callable as FEEL functions (e.g. `services.isEligible(order)`) — resume-safe,
|
|
16228
|
+
* since the host re-supplies services at recover time, unlike functions smuggled through
|
|
16229
|
+
* variables, which JSON state serialization drops. The environment variables form the base
|
|
16230
|
+
* scope, overlaid with any local variables (a job result, element-local variables such as a
|
|
16231
|
+
* multi-instance item); a variable named `services` shadows the overlay.
|
|
16232
|
+
* @param {import('bpmn-elements').Environment} [environment]
|
|
16233
|
+
* @param {Record<string, any>} [localVariables] scope-local overlay
|
|
16234
|
+
* @returns {Record<string, any>}
|
|
16235
|
+
*/
|
|
16236
|
+
function getFeelScope(environment, localVariables) {
|
|
16237
|
+
return { services: environment?.services, ...environment?.variables, ...localVariables };
|
|
16238
|
+
}
|
|
16239
|
+
|
|
16225
16240
|
/**
|
|
16226
16241
|
* Format an activity on enter from its behaviour and extensions: documentation and,
|
|
16227
16242
|
* for user tasks, the `zeebe:assignmentDefinition` (assignee, candidate users/groups).
|
|
@@ -16239,7 +16254,7 @@ class FormatActivity {
|
|
|
16239
16254
|
* @param {import('bpmn-elements').IApi<import('bpmn-elements').Activity>} elementApi
|
|
16240
16255
|
*/
|
|
16241
16256
|
resolve(elementApi) {
|
|
16242
|
-
const scope = elementApi.environment
|
|
16257
|
+
const scope = getFeelScope(elementApi.environment);
|
|
16243
16258
|
const result = {};
|
|
16244
16259
|
|
|
16245
16260
|
const documentation = this.activity.behaviour.documentation;
|
|
@@ -16280,7 +16295,7 @@ class FormatProcess {
|
|
|
16280
16295
|
const documentation = this.process.behaviour.documentation;
|
|
16281
16296
|
if (documentation && !elementApi.content.description) {
|
|
16282
16297
|
const text = documentation[0]?.text;
|
|
16283
|
-
if (text) result.description = resolveValue(text, elementApi.environment
|
|
16298
|
+
if (text) result.description = resolveValue(text, getFeelScope(elementApi.environment));
|
|
16284
16299
|
}
|
|
16285
16300
|
return result;
|
|
16286
16301
|
}
|
|
@@ -16329,7 +16344,7 @@ class IoMapping {
|
|
|
16329
16344
|
* @param {import('bpmn-elements').IApi<any>} elementApi
|
|
16330
16345
|
*/
|
|
16331
16346
|
getInput(elementApi) {
|
|
16332
|
-
const scope = elementApi.environment
|
|
16347
|
+
const scope = getFeelScope(elementApi.environment);
|
|
16333
16348
|
const result = {};
|
|
16334
16349
|
for (const { source, target } of this.inputParameters) {
|
|
16335
16350
|
if (!target) continue;
|
|
@@ -16343,7 +16358,7 @@ class IoMapping {
|
|
|
16343
16358
|
* @param {Record<string, any>} [jobResult] Variables produced by the job
|
|
16344
16359
|
*/
|
|
16345
16360
|
getOutput(elementApi, jobResult) {
|
|
16346
|
-
const scope =
|
|
16361
|
+
const scope = getFeelScope(elementApi.environment, jobResult);
|
|
16347
16362
|
const result = {};
|
|
16348
16363
|
for (const { source, target } of this.outputParameters) {
|
|
16349
16364
|
if (!target) continue;
|
|
@@ -16399,7 +16414,7 @@ class Properties {
|
|
|
16399
16414
|
this.properties = properties.properties || [];
|
|
16400
16415
|
}
|
|
16401
16416
|
resolve(elementApi) {
|
|
16402
|
-
const scope = elementApi.environment
|
|
16417
|
+
const scope = getFeelScope(elementApi.environment);
|
|
16403
16418
|
const result = {};
|
|
16404
16419
|
for (const { name, value } of this.properties) {
|
|
16405
16420
|
if (name === undefined) continue;
|
|
@@ -16495,7 +16510,7 @@ class Form {
|
|
|
16495
16510
|
this.formDefinition = formDefinition;
|
|
16496
16511
|
}
|
|
16497
16512
|
resolve(elementApi) {
|
|
16498
|
-
const scope = elementApi.environment
|
|
16513
|
+
const scope = getFeelScope(elementApi.environment);
|
|
16499
16514
|
const { formId, formKey, externalReference, bindingType, versionTag } = this.formDefinition;
|
|
16500
16515
|
return {
|
|
16501
16516
|
...(formId !== undefined && { formId: resolveValue(formId, scope) }),
|
|
@@ -16528,7 +16543,7 @@ class LoopCharacteristics {
|
|
|
16528
16543
|
}
|
|
16529
16544
|
/**
|
|
16530
16545
|
* @param {Record<string, any>|undefined} indexedOutput bpmn-elements index-keyed instance outputs
|
|
16531
|
-
* @param {Record<string, any>} baseScope
|
|
16546
|
+
* @param {Record<string, any>} baseScope base scope for `outputElement` (services + process variables)
|
|
16532
16547
|
* @returns {any[]}
|
|
16533
16548
|
*/
|
|
16534
16549
|
aggregate(indexedOutput, baseScope) {
|
|
@@ -16583,7 +16598,7 @@ JobService.prototype.execute = function execute(executionMessage, callback) {
|
|
|
16583
16598
|
|
|
16584
16599
|
let jobType;
|
|
16585
16600
|
try {
|
|
16586
|
-
jobType = resolveValue(this.taskType, environment
|
|
16601
|
+
jobType = resolveValue(this.taskType, getFeelScope(environment));
|
|
16587
16602
|
} catch (err) {
|
|
16588
16603
|
return callback(err);
|
|
16589
16604
|
}
|
|
@@ -16618,7 +16633,7 @@ class Subscription {
|
|
|
16618
16633
|
resolve(elementApi) {
|
|
16619
16634
|
return {
|
|
16620
16635
|
message: this.message,
|
|
16621
|
-
correlationKey: resolveValue(this.correlationKey, elementApi.environment
|
|
16636
|
+
correlationKey: resolveValue(this.correlationKey, getFeelScope(elementApi.environment)),
|
|
16622
16637
|
};
|
|
16623
16638
|
}
|
|
16624
16639
|
}
|
|
@@ -16846,7 +16861,7 @@ class ElementExtensions {
|
|
|
16846
16861
|
|
|
16847
16862
|
// Multi-instance: aggregate the per-instance outputs into the `outputCollection` array.
|
|
16848
16863
|
if (loop?.hasOutputCollection) {
|
|
16849
|
-
const output = { [loop.outputCollection]: loop.aggregate(jobResult, elementApi.environment
|
|
16864
|
+
const output = { [loop.outputCollection]: loop.aggregate(jobResult, getFeelScope(elementApi.environment)) };
|
|
16850
16865
|
this.#assignOutput(elementApi, output);
|
|
16851
16866
|
return { output };
|
|
16852
16867
|
}
|
|
@@ -17009,22 +17024,14 @@ function hasExpression(text) {
|
|
|
17009
17024
|
|
|
17010
17025
|
/**
|
|
17011
17026
|
* Resolve a templated string. Static literals are returned as-is; FEEL expressions are
|
|
17012
|
-
* evaluated
|
|
17027
|
+
* evaluated in the environment scope (see `getFeelScope`), overlaid with any element-local
|
|
17028
|
+
* variables carried on the message content (e.g. a multi-instance item).
|
|
17013
17029
|
* @param {string} templatedString
|
|
17014
17030
|
* @param {{ environment?: import('bpmn-elements').Environment, content?: any }} [context]
|
|
17015
17031
|
*/
|
|
17016
17032
|
function resolveExpression(templatedString, context) {
|
|
17017
17033
|
if (!isFeelExpression(templatedString)) return templatedString;
|
|
17018
|
-
return evaluateFeel(templatedString,
|
|
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 };
|
|
17034
|
+
return evaluateFeel(templatedString, getFeelScope(context?.environment, context?.content?.variables));
|
|
17028
17035
|
}
|
|
17029
17036
|
|
|
17030
17037
|
/**
|
|
@@ -17049,12 +17056,12 @@ class FeelScriptRegistry {
|
|
|
17049
17056
|
/**
|
|
17050
17057
|
* @param {string} _scriptFormat
|
|
17051
17058
|
* @param {{ id: string, [x: string]: any }} activity
|
|
17052
|
-
* @returns {import('bpmn-elements').Script} the FEEL script, or undefined when
|
|
17053
|
-
* has no `zeebe:script`
|
|
17059
|
+
* @returns {import('bpmn-elements').Script | undefined} the FEEL script, or undefined when
|
|
17060
|
+
* the activity has no `zeebe:script`
|
|
17054
17061
|
*/
|
|
17055
17062
|
getScript(_scriptFormat, activity) {
|
|
17056
17063
|
const expression = getScriptExpression(activity);
|
|
17057
|
-
if (expression === undefined) return
|
|
17064
|
+
if (expression === undefined) return undefined;
|
|
17058
17065
|
return new FeelScript(expression);
|
|
17059
17066
|
}
|
|
17060
17067
|
}
|
|
@@ -17065,7 +17072,7 @@ class FeelScript {
|
|
|
17065
17072
|
}
|
|
17066
17073
|
execute(scope, callback) {
|
|
17067
17074
|
try {
|
|
17068
|
-
const value = isFeelExpression(this.expression) ? evaluateFeel(this.expression,
|
|
17075
|
+
const value = isFeelExpression(this.expression) ? evaluateFeel(this.expression, getFeelScope(scope.environment)) : this.expression;
|
|
17069
17076
|
callback(null, value);
|
|
17070
17077
|
} catch (err) {
|
|
17071
17078
|
callback(err);
|
|
@@ -17149,6 +17156,7 @@ exports.evaluateFeel = evaluateFeel;
|
|
|
17149
17156
|
exports.evaluateFeelUnaryTest = evaluateFeelUnaryTest;
|
|
17150
17157
|
exports.extendFn = extendFn;
|
|
17151
17158
|
exports.extensions = extensions;
|
|
17159
|
+
exports.getFeelScope = getFeelScope;
|
|
17152
17160
|
exports.isFeelExpression = isFeelExpression;
|
|
17153
17161
|
exports.resolveValue = resolveValue;
|
|
17154
17162
|
exports.stripFeel = stripFeel;
|
package/package.json
CHANGED
package/src/ElementExtensions.js
CHANGED
|
@@ -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
|
|
138
|
+
const output = { [loop.outputCollection]: loop.aggregate(jobResult, getFeelScope(elementApi.environment)) };
|
|
138
139
|
this.#assignOutput(elementApi, output);
|
|
139
140
|
return { output };
|
|
140
141
|
}
|
package/src/Expressions.js
CHANGED
|
@@ -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
|
|
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,
|
|
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
|
|
26
|
-
* has no `zeebe: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
|
|
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,
|
|
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);
|
package/src/extensions/Form.js
CHANGED
|
@@ -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
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
37
|
+
jobType = resolveValue(this.taskType, getFeelScope(environment));
|
|
38
38
|
} catch (err) {
|
|
39
39
|
return callback(err);
|
|
40
40
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
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,
|
|
@@ -17,7 +17,7 @@ export class FormatActivity {
|
|
|
17
17
|
* @param {import('bpmn-elements').IApi<import('bpmn-elements').Activity>} elementApi
|
|
18
18
|
*/
|
|
19
19
|
resolve(elementApi) {
|
|
20
|
-
const scope = elementApi.environment
|
|
20
|
+
const scope = getFeelScope(elementApi.environment);
|
|
21
21
|
const result = {};
|
|
22
22
|
|
|
23
23
|
const documentation = this.activity.behaviour.documentation;
|
|
@@ -58,7 +58,7 @@ export class FormatProcess {
|
|
|
58
58
|
const documentation = this.process.behaviour.documentation;
|
|
59
59
|
if (documentation && !elementApi.content.description) {
|
|
60
60
|
const text = documentation[0]?.text;
|
|
61
|
-
if (text) result.description = resolveValue(text, elementApi.environment
|
|
61
|
+
if (text) result.description = resolveValue(text, getFeelScope(elementApi.environment));
|
|
62
62
|
}
|
|
63
63
|
return result;
|
|
64
64
|
}
|
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
|
+
}
|
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
|
|
package/types/index.d.ts
CHANGED
|
@@ -171,6 +171,16 @@ declare module '@0dep/bpmn-extensions' {
|
|
|
171
171
|
* @param context Variables in scope for FEEL evaluation
|
|
172
172
|
* */
|
|
173
173
|
export function resolveValue(value: any, context?: Record<string, any>): any;
|
|
174
|
+
/**
|
|
175
|
+
* Build the FEEL evaluation scope for an environment. The environment services are exposed
|
|
176
|
+
* under `services`, callable as FEEL functions (e.g. `services.isEligible(order)`) — resume-safe,
|
|
177
|
+
* since the host re-supplies services at recover time, unlike functions smuggled through
|
|
178
|
+
* variables, which JSON state serialization drops. The environment variables form the base
|
|
179
|
+
* scope, overlaid with any local variables (a job result, element-local variables such as a
|
|
180
|
+
* multi-instance item); a variable named `services` shadows the overlay.
|
|
181
|
+
* @param localVariables scope-local overlay
|
|
182
|
+
* */
|
|
183
|
+
export function getFeelScope(environment?: import("bpmn-elements").Environment, localVariables?: Record<string, any>): Record<string, any>;
|
|
174
184
|
export class ServiceError extends Error {
|
|
175
185
|
constructor(jobType: any);
|
|
176
186
|
code: string;
|
|
@@ -338,7 +348,7 @@ declare module '@0dep/bpmn-extensions' {
|
|
|
338
348
|
get hasOutputCollection(): boolean;
|
|
339
349
|
/**
|
|
340
350
|
* @param indexedOutput bpmn-elements index-keyed instance outputs
|
|
341
|
-
* @param baseScope
|
|
351
|
+
* @param baseScope base scope for `outputElement` (services + process variables)
|
|
342
352
|
* */
|
|
343
353
|
aggregate(indexedOutput: Record<string, any> | undefined, baseScope: Record<string, any>): any[];
|
|
344
354
|
}
|
package/types/index.d.ts.map
CHANGED
|
@@ -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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
69
|
+
"mappings": ";;;;;;;iBAwBgBA,UAAUA;;;;;;;;iBAqBVC,QAAQA;;;;;;;;;;;;;;;;iBClCRC,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;;;;;;;;;;;;;;;;;;;;;;;;;;;OCFXC,cAAcA;;;;;;;;;;;;;;;;OAuCdC,aAAaA;;;;;;;;;;;;;;;;;;;;OChCbC,SAASA;;;;;;;;;;;;;;;;;;;;;;;OCPTC,WAAWA;;;;;;;;;;;OCEXC,UAAUA;;;;;;;;;;;;;;;OCIVC,kBAAkBA;;;;;;;;;;;;;;;;;;;OCFlBC,IAAIA;;;;;;;;;;;;;;;;;;;;;;OCGJC,mBAAmBA;;;;;;;;;;;;;;;;;;;OCHnBC,YAAYA",
|
|
69
70
|
"ignoreList": []
|
|
70
71
|
}
|