@0dep/bpmn-extensions 0.0.1 → 0.0.3
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 +12 -2
- package/dist/index.js +171 -47
- package/package.json +12 -4
- package/src/ElementExtensions.js +56 -19
- package/src/Expressions.js +2 -5
- package/src/ProcessExtensions.js +7 -0
- package/src/SubProcessExtensions.js +5 -5
- package/src/extensions/FeelScripts.js +10 -2
- package/src/extensions/Subscription.js +30 -0
- package/src/extensions/TaskDefinition.js +6 -0
- package/src/extensions/formatters.js +14 -1
- package/src/feel.js +3 -3
- package/src/getExtensions.js +39 -11
- package/src/index.js +2 -2
- package/types/index.d.ts +99 -43
- package/types/index.d.ts.map +6 -3
package/README.md
CHANGED
|
@@ -24,6 +24,8 @@ npm install @0dep/bpmn-extensions bpmn-elements
|
|
|
24
24
|
- **`zeebe:script`** — a `FeelScripts()` adapter runs a script task's FEEL `expression` and assigns
|
|
25
25
|
the result to its `resultVariable`.
|
|
26
26
|
- **`zeebe:taskDefinition`** — maps a service task's job `type` to an environment service (job worker).
|
|
27
|
+
- **`zeebe:calledDecision`** — a business rule task resolves its `decisionId` via an environment
|
|
28
|
+
service (you bring the decision; we don't evaluate DMN) and assigns the result to `resultVariable`.
|
|
27
29
|
- **`zeebe:ioMapping`** — input mapping on entry (parent scope) and output mapping on completion
|
|
28
30
|
(job-result scope), with dotted `target` paths. Propagates across boundaries: a call activity's
|
|
29
31
|
input reaches the called process and its output maps the called process result back; a sub
|
|
@@ -38,6 +40,10 @@ npm install @0dep/bpmn-extensions bpmn-elements
|
|
|
38
40
|
- **`zeebe:calledElement`** — call activity target process id.
|
|
39
41
|
- **`zeebe:loopCharacteristics`** — collection-based multi-instance (`inputCollection` / `inputElement`),
|
|
40
42
|
sequential or parallel, with `outputElement` aggregated into the `outputCollection` array in input order.
|
|
43
|
+
- **`zeebe:subscription`** — the referenced message's `correlationKey` is resolved when the catching
|
|
44
|
+
element (receive task, message event) starts waiting, and exposed on its content as
|
|
45
|
+
`subscription: { message, correlationKey }` — route an incoming message by matching it against the
|
|
46
|
+
waiting elements (`getPostponed()`) and signalling the right one.
|
|
41
47
|
|
|
42
48
|
## API
|
|
43
49
|
|
|
@@ -126,8 +132,12 @@ in `test/helpers/factory.js`, then run on a real bpmn-elements `Definition`. The
|
|
|
126
132
|
the engine's `Logger` to the [`debug`](https://www.npmjs.com/package/debug) package, so
|
|
127
133
|
`DEBUG=bpmn-extensions:* npm test` traces the engine and extensions (`:error:*` for errors only).
|
|
128
134
|
|
|
129
|
-
|
|
130
|
-
|
|
135
|
+
# Ecosystem
|
|
136
|
+
|
|
137
|
+
- [bpmn-engine](https://github.com/paed01/bpmn-engine) — BPMN 2.0 execution engine wrapping `bpmn-elements`; the batteries-included way to run, stop, resume, and recover flows.
|
|
138
|
+
- [bpmn-middleware](https://github.com/zerodep/bpmn-middleware) — Express middleware exposing the engine over HTTP, with pluggable state storage.
|
|
139
|
+
- [@onify/flow-extensions](https://github.com/onify/flow-extensions) — Onify Flow extensions for `bpmn-elements`.
|
|
140
|
+
- [dmn-elements](https://github.com/zerodep/dmn-elements) — Executable DMN 1.3 decision elements; back a Business Rule Task with it (see [Conformance](/docs/Conformance.md#business-rule-task-and-dmn)).
|
|
131
141
|
|
|
132
142
|
## License
|
|
133
143
|
|
package/dist/index.js
CHANGED
|
@@ -16203,11 +16203,11 @@ function evaluateFeel(expression, context) {
|
|
|
16203
16203
|
* @param {string} expression FEEL unary test
|
|
16204
16204
|
* @param {any} input The value being tested, available as `?` in the test
|
|
16205
16205
|
* @param {Record<string, any>} [context] Additional variables in scope
|
|
16206
|
-
* @returns {boolean}
|
|
16206
|
+
* @returns {boolean} true only when the test is satisfied — an undecidable (null) test is false
|
|
16207
16207
|
*/
|
|
16208
16208
|
function evaluateFeelUnaryTest(expression, input, context) {
|
|
16209
|
-
const { value } = unaryTest(stripFeel(expression), { ...
|
|
16210
|
-
return value;
|
|
16209
|
+
const { value } = unaryTest(stripFeel(expression), { ...context, '?': input });
|
|
16210
|
+
return value === true;
|
|
16211
16211
|
}
|
|
16212
16212
|
|
|
16213
16213
|
/**
|
|
@@ -16227,10 +16227,17 @@ function resolveValue(value, context) {
|
|
|
16227
16227
|
* for user tasks, the `zeebe:assignmentDefinition` (assignee, candidate users/groups).
|
|
16228
16228
|
*/
|
|
16229
16229
|
class FormatActivity {
|
|
16230
|
+
/**
|
|
16231
|
+
* @param {import('bpmn-elements').Activity} activity
|
|
16232
|
+
* @param {any} assignmentDefinition
|
|
16233
|
+
*/
|
|
16230
16234
|
constructor(activity, assignmentDefinition) {
|
|
16231
16235
|
this.activity = activity;
|
|
16232
16236
|
this.assignmentDefinition = assignmentDefinition;
|
|
16233
16237
|
}
|
|
16238
|
+
/**
|
|
16239
|
+
* @param {import('bpmn-elements').IApi<import('bpmn-elements').Activity>} elementApi
|
|
16240
|
+
*/
|
|
16234
16241
|
resolve(elementApi) {
|
|
16235
16242
|
const scope = elementApi.environment.variables;
|
|
16236
16243
|
const result = {};
|
|
@@ -16259,9 +16266,15 @@ class FormatActivity {
|
|
|
16259
16266
|
* Format a process on enter: documentation.
|
|
16260
16267
|
*/
|
|
16261
16268
|
class FormatProcess {
|
|
16269
|
+
/**
|
|
16270
|
+
* @param {import('bpmn-elements').Process} bp
|
|
16271
|
+
*/
|
|
16262
16272
|
constructor(bp) {
|
|
16263
16273
|
this.process = bp;
|
|
16264
16274
|
}
|
|
16275
|
+
/**
|
|
16276
|
+
* @param {import('bpmn-elements').IApi<import('bpmn-elements').Process>} elementApi
|
|
16277
|
+
*/
|
|
16265
16278
|
resolve(elementApi) {
|
|
16266
16279
|
const result = {};
|
|
16267
16280
|
const documentation = this.process.behaviour.documentation;
|
|
@@ -16280,7 +16293,7 @@ class FormatProcess {
|
|
|
16280
16293
|
function resolveList(value, scope) {
|
|
16281
16294
|
if (!value) return undefined;
|
|
16282
16295
|
const resolved = resolveValue(value, scope);
|
|
16283
|
-
if (Array.isArray(resolved)) return resolved.filter(
|
|
16296
|
+
if (Array.isArray(resolved)) return resolved.filter(Boolean);
|
|
16284
16297
|
if (typeof resolved !== 'string') return undefined;
|
|
16285
16298
|
return resolved
|
|
16286
16299
|
.split(',')
|
|
@@ -16558,6 +16571,12 @@ function JobService(taskType, activity) {
|
|
|
16558
16571
|
this.activity = activity;
|
|
16559
16572
|
}
|
|
16560
16573
|
|
|
16574
|
+
/**
|
|
16575
|
+
* Execute
|
|
16576
|
+
* @param {import('bpmn-elements').ElementBrokerMessage} executionMessage
|
|
16577
|
+
* @param {CallableFunction} callback
|
|
16578
|
+
* @returns {any}
|
|
16579
|
+
*/
|
|
16561
16580
|
JobService.prototype.execute = function execute(executionMessage, callback) {
|
|
16562
16581
|
const activity = this.activity;
|
|
16563
16582
|
const environment = activity.environment;
|
|
@@ -16575,21 +16594,58 @@ JobService.prototype.execute = function execute(executionMessage, callback) {
|
|
|
16575
16594
|
return serviceFn.call(activity, executionMessage, (err, result) => callback(err, result));
|
|
16576
16595
|
};
|
|
16577
16596
|
|
|
16597
|
+
/**
|
|
16598
|
+
* `zeebe:subscription` — rides on the referenced `bpmn:Message`, not on the catching element.
|
|
16599
|
+
*
|
|
16600
|
+
* Resolves the correlation key in the activity's variable scope on enter and exposes it on the
|
|
16601
|
+
* element content as `subscription`. Correlation itself is the embedding application's job:
|
|
16602
|
+
* read the resolved key off the waiting activity (`getPostponed()` → `content.subscription`)
|
|
16603
|
+
* and signal the matching one (`api.signal(...)`).
|
|
16604
|
+
*/
|
|
16605
|
+
class Subscription {
|
|
16606
|
+
/**
|
|
16607
|
+
* @param {{ id: string, name?: string }} messageRef The serialized message reference
|
|
16608
|
+
* @param {{ correlationKey: string }} subscription The `zeebe:Subscription` behaviour
|
|
16609
|
+
*/
|
|
16610
|
+
constructor(messageRef, subscription) {
|
|
16611
|
+
this.message = { id: messageRef.id, name: messageRef.name };
|
|
16612
|
+
this.correlationKey = subscription.correlationKey;
|
|
16613
|
+
}
|
|
16614
|
+
/**
|
|
16615
|
+
* @param {import('bpmn-elements').IApi<any>} elementApi
|
|
16616
|
+
* @returns {{ message: { id: string, name?: string }, correlationKey: any }}
|
|
16617
|
+
*/
|
|
16618
|
+
resolve(elementApi) {
|
|
16619
|
+
return {
|
|
16620
|
+
message: this.message,
|
|
16621
|
+
correlationKey: resolveValue(this.correlationKey, elementApi.environment.variables),
|
|
16622
|
+
};
|
|
16623
|
+
}
|
|
16624
|
+
}
|
|
16625
|
+
|
|
16626
|
+
/**
|
|
16627
|
+
* The extension handlers assembled for one element.
|
|
16628
|
+
* @typedef {object} ExtensionHandlers
|
|
16629
|
+
* @property {FormatActivity | FormatProcess} format
|
|
16630
|
+
* @property {IoMapping} [io]
|
|
16631
|
+
* @property {TaskHeaders} [headers]
|
|
16632
|
+
* @property {Properties} [properties]
|
|
16633
|
+
* @property {ExecutionListeners} [listeners]
|
|
16634
|
+
* @property {Form} [form]
|
|
16635
|
+
* @property {LoopCharacteristics} [loop]
|
|
16636
|
+
* @property {any} [script]
|
|
16637
|
+
* @property {any} [calledDecision]
|
|
16638
|
+
* @property {Function} [Service]
|
|
16639
|
+
* @property {Subscription} [subscription]
|
|
16640
|
+
*/
|
|
16641
|
+
|
|
16578
16642
|
/**
|
|
16579
16643
|
* Inspect an element's extension elements and assemble the extension handlers it needs.
|
|
16580
16644
|
* @param {import('bpmn-elements').Activity | import('bpmn-elements').Process} element
|
|
16581
|
-
* @
|
|
16582
|
-
*
|
|
16583
|
-
* io?: IoMapping,
|
|
16584
|
-
* headers?: TaskHeaders,
|
|
16585
|
-
* properties?: Properties,
|
|
16586
|
-
* listeners?: ExecutionListeners,
|
|
16587
|
-
* form?: Form,
|
|
16588
|
-
* loop?: LoopCharacteristics,
|
|
16589
|
-
* Service?: Function,
|
|
16590
|
-
* }}
|
|
16645
|
+
* @param {import('bpmn-elements').ContextInstance} [context]
|
|
16646
|
+
* @returns {ExtensionHandlers}
|
|
16591
16647
|
*/
|
|
16592
|
-
function getExtensions(element) {
|
|
16648
|
+
function getExtensions(element, context) {
|
|
16593
16649
|
const result = {};
|
|
16594
16650
|
const isProcess = element.type === 'bpmn:Process';
|
|
16595
16651
|
|
|
@@ -16619,6 +16675,13 @@ function getExtensions(element) {
|
|
|
16619
16675
|
case 'zeebe:Script':
|
|
16620
16676
|
result.script = ext;
|
|
16621
16677
|
break;
|
|
16678
|
+
case 'zeebe:CalledDecision':
|
|
16679
|
+
// A business rule task runs as a service task (bpmn-elements maps it to ServiceTask). The
|
|
16680
|
+
// decision is resolved by an environment service named by the decision id; its result is
|
|
16681
|
+
// named by `resultVariable`.
|
|
16682
|
+
result.calledDecision = ext;
|
|
16683
|
+
result.Service = JobService.bind(JobService, ext.decisionId);
|
|
16684
|
+
break;
|
|
16622
16685
|
case 'zeebe:FormDefinition':
|
|
16623
16686
|
result.form = new Form(ext);
|
|
16624
16687
|
break;
|
|
@@ -16626,6 +16689,18 @@ function getExtensions(element) {
|
|
|
16626
16689
|
}
|
|
16627
16690
|
}
|
|
16628
16691
|
|
|
16692
|
+
// A message catch (receive task / message event) may reference a bpmn:Message carrying a
|
|
16693
|
+
// zeebe:subscription with the correlation key. The subscription lives on the message element,
|
|
16694
|
+
// which the instantiated bpmn-elements Message strips — read it off the serialized context.
|
|
16695
|
+
const messageRef =
|
|
16696
|
+
element.behaviour.messageRef ?? element.behaviour.eventDefinitions?.find((ed) => ed.behaviour?.messageRef)?.behaviour.messageRef;
|
|
16697
|
+
if (messageRef?.id && context) {
|
|
16698
|
+
const subscription = context.definitionContext
|
|
16699
|
+
.getActivityById(messageRef.id)
|
|
16700
|
+
?.behaviour.extensionElements?.values?.find((v) => v.$type === 'zeebe:Subscription');
|
|
16701
|
+
if (subscription?.correlationKey) result.subscription = new Subscription(messageRef, subscription);
|
|
16702
|
+
}
|
|
16703
|
+
|
|
16629
16704
|
// Output side of a multi-instance `zeebe:loopCharacteristics` (the input side is lifted by extendFn).
|
|
16630
16705
|
const loopExtension = element.behaviour.loopCharacteristics?.behaviour?.extensionElements?.values?.find(
|
|
16631
16706
|
(v) => v.$type === 'zeebe:LoopCharacteristics'
|
|
@@ -16639,6 +16714,13 @@ function getExtensions(element) {
|
|
|
16639
16714
|
|
|
16640
16715
|
const SUBPROCESS_TYPES = new Set(['bpmn:SubProcess', 'bpmn:AdHocSubProcess', 'bpmn:Transaction']);
|
|
16641
16716
|
|
|
16717
|
+
// Consumer tags shared between activate (here and in the SubProcessExtensions override) and
|
|
16718
|
+
// deactivate — deactivate cancels by tag, so both must subscribe with these exact tags.
|
|
16719
|
+
const ON_ENTER_TAG = '0dep-bpmn-extensions:on-enter';
|
|
16720
|
+
const ON_EXECUTED_TAG = '0dep-bpmn-extensions:on-executed';
|
|
16721
|
+
const ON_START_TAG = '0dep-bpmn-extensions:on-start';
|
|
16722
|
+
const ON_END_TAG = '0dep-bpmn-extensions:on-end';
|
|
16723
|
+
|
|
16642
16724
|
/**
|
|
16643
16725
|
* Activity-level extensions.
|
|
16644
16726
|
*
|
|
@@ -16647,43 +16729,55 @@ const SUBPROCESS_TYPES = new Set(['bpmn:SubProcess', 'bpmn:AdHocSubProcess', 'bp
|
|
|
16647
16729
|
* proceeding — the same mechanism bpmn-elements uses for extension formatting.
|
|
16648
16730
|
*/
|
|
16649
16731
|
class ElementExtensions {
|
|
16650
|
-
|
|
16732
|
+
/**
|
|
16733
|
+
* @param {import('bpmn-elements').Activity} activity
|
|
16734
|
+
* @param {import('bpmn-elements').ContextInstance} context
|
|
16735
|
+
*/
|
|
16736
|
+
constructor(activity, context) {
|
|
16651
16737
|
this.activity = activity;
|
|
16652
16738
|
this.formatQ = activity.broker.getQueue('format-run-q');
|
|
16653
16739
|
|
|
16654
|
-
|
|
16740
|
+
/** @type {import('./getExtensions.js').ExtensionHandlers} */
|
|
16741
|
+
this.extensions = getExtensions(activity, context);
|
|
16655
16742
|
const Service = this.extensions.Service;
|
|
16656
16743
|
if (Service) activity.behaviour.Service = Service;
|
|
16657
16744
|
}
|
|
16745
|
+
/**
|
|
16746
|
+
* Activate extensions
|
|
16747
|
+
* @param {import('bpmn-elements').ElementBrokerMessage} message
|
|
16748
|
+
*/
|
|
16658
16749
|
activate(message) {
|
|
16659
16750
|
const activity = this.activity;
|
|
16660
16751
|
const listeners = this.extensions.listeners;
|
|
16661
16752
|
|
|
16662
16753
|
if (message.fields.redelivered && message.fields.routingKey === 'run.start') {
|
|
16663
|
-
activity.on('start', (api) => this._onEnter(api), { consumerTag:
|
|
16754
|
+
activity.on('start', (api) => this._onEnter(api), { consumerTag: ON_ENTER_TAG });
|
|
16664
16755
|
} else {
|
|
16665
|
-
activity.on('enter', (api) => this._onEnter(api), { consumerTag:
|
|
16756
|
+
activity.on('enter', (api) => this._onEnter(api), { consumerTag: ON_ENTER_TAG });
|
|
16666
16757
|
}
|
|
16667
16758
|
|
|
16668
16759
|
activity.on('activity.execution.completed', (api) => this._onExecuted(api), {
|
|
16669
|
-
consumerTag:
|
|
16760
|
+
consumerTag: ON_EXECUTED_TAG,
|
|
16670
16761
|
});
|
|
16671
16762
|
|
|
16672
16763
|
if (listeners?.onStart) {
|
|
16673
|
-
activity.on('start', (api) => this._onListener('start', api), { consumerTag:
|
|
16764
|
+
activity.on('start', (api) => this._onListener('start', api), { consumerTag: ON_START_TAG });
|
|
16674
16765
|
}
|
|
16675
16766
|
if (listeners?.onEnd) {
|
|
16676
|
-
activity.on('end', (api) => this._onListener('end', api), { consumerTag:
|
|
16767
|
+
activity.on('end', (api) => this._onListener('end', api), { consumerTag: ON_END_TAG });
|
|
16677
16768
|
}
|
|
16678
16769
|
}
|
|
16679
16770
|
deactivate() {
|
|
16680
16771
|
const broker = this.activity.broker;
|
|
16681
|
-
broker.cancel(
|
|
16682
|
-
broker.cancel(
|
|
16683
|
-
broker.cancel(
|
|
16684
|
-
broker.cancel(
|
|
16772
|
+
broker.cancel(ON_ENTER_TAG);
|
|
16773
|
+
broker.cancel(ON_EXECUTED_TAG);
|
|
16774
|
+
broker.cancel(ON_START_TAG);
|
|
16775
|
+
broker.cancel(ON_END_TAG);
|
|
16685
16776
|
}
|
|
16686
|
-
/**
|
|
16777
|
+
/**
|
|
16778
|
+
* @internal Shared with SubProcessExtensions.
|
|
16779
|
+
* @param {import('bpmn-elements').IApi<import('bpmn-elements').Activity>} elementApi
|
|
16780
|
+
*/
|
|
16687
16781
|
async _onEnter(elementApi) {
|
|
16688
16782
|
this.formatQ.queueMessage({ routingKey: 'run.enter.format' }, { endRoutingKey: 'run.enter.complete' }, { persistent: false });
|
|
16689
16783
|
try {
|
|
@@ -16693,7 +16787,10 @@ class ElementExtensions {
|
|
|
16693
16787
|
elementApi.broker.publish('format', 'run.enter.error', { error: err }, { persistent: false });
|
|
16694
16788
|
}
|
|
16695
16789
|
}
|
|
16696
|
-
/**
|
|
16790
|
+
/**
|
|
16791
|
+
* @internal Shared with SubProcessExtensions.
|
|
16792
|
+
* @param {import('bpmn-elements').IApi<import('bpmn-elements').Activity>} elementApi
|
|
16793
|
+
*/
|
|
16697
16794
|
async _onExecuted(elementApi) {
|
|
16698
16795
|
this.formatQ.queueMessage({ routingKey: 'run.end.format' }, { endRoutingKey: 'run.end.complete' }, { persistent: false });
|
|
16699
16796
|
try {
|
|
@@ -16703,7 +16800,10 @@ class ElementExtensions {
|
|
|
16703
16800
|
elementApi.broker.publish('format', 'run.end.error', { error: err }, { persistent: false });
|
|
16704
16801
|
}
|
|
16705
16802
|
}
|
|
16706
|
-
/**
|
|
16803
|
+
/**
|
|
16804
|
+
* @internal Shared with SubProcessExtensions.
|
|
16805
|
+
* @param {import('bpmn-elements').IApi<import('bpmn-elements').Activity>} elementApi
|
|
16806
|
+
*/
|
|
16707
16807
|
async _onListener(eventType, elementApi) {
|
|
16708
16808
|
const routingKey = `run.listener.${eventType}`;
|
|
16709
16809
|
this.formatQ.queueMessage({ routingKey }, { endRoutingKey: `${routingKey}.complete` }, { persistent: false });
|
|
@@ -16715,13 +16815,17 @@ class ElementExtensions {
|
|
|
16715
16815
|
elementApi.broker.publish('format', `${routingKey}.error`, { error: err }, { persistent: false });
|
|
16716
16816
|
}
|
|
16717
16817
|
}
|
|
16818
|
+
/**
|
|
16819
|
+
* @param {import('bpmn-elements').IApi<import('bpmn-elements').Activity>} elementApi
|
|
16820
|
+
*/
|
|
16718
16821
|
#formatOnEnter(elementApi) {
|
|
16719
|
-
const { format, io, headers, properties, form } = this.extensions;
|
|
16822
|
+
const { format, io, headers, properties, form, subscription } = this.extensions;
|
|
16720
16823
|
const result = { ...format.resolve(elementApi) };
|
|
16721
16824
|
|
|
16722
16825
|
if (headers) result.headers = headers.resolve();
|
|
16723
16826
|
if (properties) result.properties = properties.resolve(elementApi);
|
|
16724
16827
|
if (form) result.form = form.resolve(elementApi);
|
|
16828
|
+
if (subscription) result.subscription = subscription.resolve(elementApi);
|
|
16725
16829
|
if (io?.hasInput) {
|
|
16726
16830
|
result.input = io.getInput(elementApi);
|
|
16727
16831
|
// A (sub) process input mapping creates local variables visible to its children; a job
|
|
@@ -16733,8 +16837,11 @@ class ElementExtensions {
|
|
|
16733
16837
|
Object.assign(elementApi.content, result);
|
|
16734
16838
|
return result;
|
|
16735
16839
|
}
|
|
16840
|
+
/**
|
|
16841
|
+
* @param {import('bpmn-elements').IApi<import('bpmn-elements').Activity>} elementApi
|
|
16842
|
+
*/
|
|
16736
16843
|
#formatOnExecuted(elementApi) {
|
|
16737
|
-
const { io, script, loop } = this.extensions;
|
|
16844
|
+
const { io, script, calledDecision, loop } = this.extensions;
|
|
16738
16845
|
let jobResult = elementApi.content.output;
|
|
16739
16846
|
|
|
16740
16847
|
// Multi-instance: aggregate the per-instance outputs into the `outputCollection` array.
|
|
@@ -16750,9 +16857,10 @@ class ElementExtensions {
|
|
|
16750
16857
|
jobResult = jobResult.output;
|
|
16751
16858
|
}
|
|
16752
16859
|
|
|
16753
|
-
// A script task
|
|
16754
|
-
// an object of variables.
|
|
16755
|
-
const
|
|
16860
|
+
// A script task (`zeebe:script`) or business rule task (`zeebe:calledDecision`) names its single
|
|
16861
|
+
// result with `resultVariable`. A plain job's result is already an object of variables.
|
|
16862
|
+
const named = script || calledDecision;
|
|
16863
|
+
const resultObject = named ? (named.resultVariable ? { [named.resultVariable]: jobResult } : undefined) : jobResult;
|
|
16756
16864
|
|
|
16757
16865
|
let output;
|
|
16758
16866
|
if (io?.hasOutput) {
|
|
@@ -16768,6 +16876,10 @@ class ElementExtensions {
|
|
|
16768
16876
|
}
|
|
16769
16877
|
return {};
|
|
16770
16878
|
}
|
|
16879
|
+
/**
|
|
16880
|
+
* @param {import('bpmn-elements').IApi<import('bpmn-elements').Activity>} elementApi
|
|
16881
|
+
* @param {any} output
|
|
16882
|
+
*/
|
|
16771
16883
|
#assignOutput(elementApi, output) {
|
|
16772
16884
|
const environment = this.activity.environment;
|
|
16773
16885
|
// Visible to downstream FEEL within the process, and surfaced as process output
|
|
@@ -16783,8 +16895,12 @@ class ElementExtensions {
|
|
|
16783
16895
|
* the result to the process variables.
|
|
16784
16896
|
*/
|
|
16785
16897
|
class ProcessExtensions {
|
|
16898
|
+
/**
|
|
16899
|
+
* @param {import('bpmn-elements').Process} bp
|
|
16900
|
+
*/
|
|
16786
16901
|
constructor(bp) {
|
|
16787
16902
|
this.process = bp;
|
|
16903
|
+
/** @type {import('./getExtensions.js').ExtensionHandlers} */
|
|
16788
16904
|
this.extensions = getExtensions(bp);
|
|
16789
16905
|
}
|
|
16790
16906
|
activate() {
|
|
@@ -16798,6 +16914,9 @@ class ProcessExtensions {
|
|
|
16798
16914
|
deactivate() {
|
|
16799
16915
|
this.process.broker.cancel('0dep-bpmn-extensions:on-enter');
|
|
16800
16916
|
}
|
|
16917
|
+
/**
|
|
16918
|
+
* @param {import('bpmn-elements').IApi<import('bpmn-elements').Process>} elementApi
|
|
16919
|
+
*/
|
|
16801
16920
|
#onEnter(elementApi) {
|
|
16802
16921
|
try {
|
|
16803
16922
|
// bpmn-elements (>=18.0.4) forwards a call activity's formatted input — its io mapping plus,
|
|
@@ -16839,14 +16958,14 @@ class SubProcessExtensions extends ElementExtensions {
|
|
|
16839
16958
|
const listeners = this.extensions.listeners;
|
|
16840
16959
|
const enterKey = message.fields.redelivered && message.fields.routingKey === 'run.start' ? 'activity.start' : 'activity.enter';
|
|
16841
16960
|
|
|
16842
|
-
this.#subscribe(enterKey, (api) => this._onEnter(api),
|
|
16843
|
-
this.#subscribe('activity.execution.completed', (api) => this._onExecuted(api),
|
|
16961
|
+
this.#subscribe(enterKey, (api) => this._onEnter(api), ON_ENTER_TAG);
|
|
16962
|
+
this.#subscribe('activity.execution.completed', (api) => this._onExecuted(api), ON_EXECUTED_TAG);
|
|
16844
16963
|
|
|
16845
16964
|
if (listeners?.onStart) {
|
|
16846
|
-
this.#subscribe('activity.start', (api) => this._onListener('start', api),
|
|
16965
|
+
this.#subscribe('activity.start', (api) => this._onListener('start', api), ON_START_TAG);
|
|
16847
16966
|
}
|
|
16848
16967
|
if (listeners?.onEnd) {
|
|
16849
|
-
this.#subscribe('activity.end', (api) => this._onListener('end', api),
|
|
16968
|
+
this.#subscribe('activity.end', (api) => this._onListener('end', api), ON_END_TAG);
|
|
16850
16969
|
}
|
|
16851
16970
|
}
|
|
16852
16971
|
#subscribe(routingKey, callback, consumerTag) {
|
|
@@ -16870,7 +16989,7 @@ class SubProcessExtensions extends ElementExtensions {
|
|
|
16870
16989
|
* definition resolves FEEL expressions (`= ...`) instead of the default
|
|
16871
16990
|
* `${...}` template expressions.
|
|
16872
16991
|
*
|
|
16873
|
-
* @returns {import('bpmn-elements').IExpressions}
|
|
16992
|
+
* @returns {import('bpmn-elements').IExpressions & {isExpression: (text:string) => boolean, hasExpression: (text:string) => boolean}}
|
|
16874
16993
|
*/
|
|
16875
16994
|
function FeelExpressions() {
|
|
16876
16995
|
return {
|
|
@@ -16905,10 +17024,7 @@ function resolveExpression(templatedString, context) {
|
|
|
16905
17024
|
* (e.g. a multi-instance item).
|
|
16906
17025
|
*/
|
|
16907
17026
|
function getScope(context) {
|
|
16908
|
-
|
|
16909
|
-
const variables = environment ? environment.variables : {};
|
|
16910
|
-
const local = context && context.content && context.content.variables;
|
|
16911
|
-
return { ...variables, ...local };
|
|
17027
|
+
return { ...context?.environment?.variables, ...context?.content?.variables };
|
|
16912
17028
|
}
|
|
16913
17029
|
|
|
16914
17030
|
/**
|
|
@@ -16927,10 +17043,18 @@ function FeelScripts() {
|
|
|
16927
17043
|
}
|
|
16928
17044
|
|
|
16929
17045
|
class FeelScriptRegistry {
|
|
16930
|
-
register() {
|
|
17046
|
+
register() {
|
|
17047
|
+
return undefined;
|
|
17048
|
+
}
|
|
17049
|
+
/**
|
|
17050
|
+
* @param {string} _scriptFormat
|
|
17051
|
+
* @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`
|
|
17054
|
+
*/
|
|
16931
17055
|
getScript(_scriptFormat, activity) {
|
|
16932
17056
|
const expression = getScriptExpression(activity);
|
|
16933
|
-
if (expression === undefined) return undefined;
|
|
17057
|
+
if (expression === undefined) return /** @type {any} */ (undefined);
|
|
16934
17058
|
return new FeelScript(expression);
|
|
16935
17059
|
}
|
|
16936
17060
|
}
|
|
@@ -16962,8 +17086,8 @@ function getScriptExpression(activity) {
|
|
|
16962
17086
|
/**
|
|
16963
17087
|
* A flow extension activated by bpmn-elements around an element's run.
|
|
16964
17088
|
* @typedef {object} FlowExtension
|
|
16965
|
-
* @property {(message:
|
|
16966
|
-
* @property {(message?:
|
|
17089
|
+
* @property {(message: import('bpmn-elements').ElementBrokerMessage) => void} activate
|
|
17090
|
+
* @property {(message?: import('bpmn-elements').ElementBrokerMessage) => void} deactivate
|
|
16967
17091
|
*/
|
|
16968
17092
|
|
|
16969
17093
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@0dep/bpmn-extensions",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
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",
|
|
@@ -51,18 +51,26 @@
|
|
|
51
51
|
"access": "public"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
|
-
"bpmn-elements": ">=18.0.
|
|
54
|
+
"bpmn-elements": ">=18.0.12"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
57
|
"feelin": "^7.0.1"
|
|
58
58
|
},
|
|
59
|
+
"overrides": {
|
|
60
|
+
"mocha": {
|
|
61
|
+
"yargs": "^18.1.0"
|
|
62
|
+
}
|
|
63
|
+
},
|
|
59
64
|
"devDependencies": {
|
|
60
65
|
"@eslint/js": "^10.0.1",
|
|
61
66
|
"@rollup/plugin-commonjs": "^29.0.3",
|
|
62
67
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
63
|
-
"
|
|
68
|
+
"@types/chai": "^5.2.3",
|
|
69
|
+
"@types/mocha": "^10.0.10",
|
|
70
|
+
"@types/node": "^26.1.1",
|
|
71
|
+
"bpmn-elements": "^18.0.12",
|
|
64
72
|
"bpmn-moddle": "^9.0.1",
|
|
65
|
-
"c8": "^
|
|
73
|
+
"c8": "^12.0.0",
|
|
66
74
|
"chai": "^6.2.2",
|
|
67
75
|
"debug": "^4.4.3",
|
|
68
76
|
"dts-buddy": "^0.8.2",
|
package/src/ElementExtensions.js
CHANGED
|
@@ -2,6 +2,13 @@ import { getExtensions } from './getExtensions.js';
|
|
|
2
2
|
|
|
3
3
|
const SUBPROCESS_TYPES = new Set(['bpmn:SubProcess', 'bpmn:AdHocSubProcess', 'bpmn:Transaction']);
|
|
4
4
|
|
|
5
|
+
// Consumer tags shared between activate (here and in the SubProcessExtensions override) and
|
|
6
|
+
// deactivate — deactivate cancels by tag, so both must subscribe with these exact tags.
|
|
7
|
+
export const ON_ENTER_TAG = '0dep-bpmn-extensions:on-enter';
|
|
8
|
+
export const ON_EXECUTED_TAG = '0dep-bpmn-extensions:on-executed';
|
|
9
|
+
export const ON_START_TAG = '0dep-bpmn-extensions:on-start';
|
|
10
|
+
export const ON_END_TAG = '0dep-bpmn-extensions:on-end';
|
|
11
|
+
|
|
5
12
|
/**
|
|
6
13
|
* Activity-level extensions.
|
|
7
14
|
*
|
|
@@ -10,43 +17,55 @@ const SUBPROCESS_TYPES = new Set(['bpmn:SubProcess', 'bpmn:AdHocSubProcess', 'bp
|
|
|
10
17
|
* proceeding — the same mechanism bpmn-elements uses for extension formatting.
|
|
11
18
|
*/
|
|
12
19
|
export class ElementExtensions {
|
|
13
|
-
|
|
20
|
+
/**
|
|
21
|
+
* @param {import('bpmn-elements').Activity} activity
|
|
22
|
+
* @param {import('bpmn-elements').ContextInstance} context
|
|
23
|
+
*/
|
|
24
|
+
constructor(activity, context) {
|
|
14
25
|
this.activity = activity;
|
|
15
26
|
this.formatQ = activity.broker.getQueue('format-run-q');
|
|
16
27
|
|
|
17
|
-
|
|
28
|
+
/** @type {import('./getExtensions.js').ExtensionHandlers} */
|
|
29
|
+
this.extensions = getExtensions(activity, context);
|
|
18
30
|
const Service = this.extensions.Service;
|
|
19
31
|
if (Service) activity.behaviour.Service = Service;
|
|
20
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Activate extensions
|
|
35
|
+
* @param {import('bpmn-elements').ElementBrokerMessage} message
|
|
36
|
+
*/
|
|
21
37
|
activate(message) {
|
|
22
38
|
const activity = this.activity;
|
|
23
39
|
const listeners = this.extensions.listeners;
|
|
24
40
|
|
|
25
41
|
if (message.fields.redelivered && message.fields.routingKey === 'run.start') {
|
|
26
|
-
activity.on('start', (api) => this._onEnter(api), { consumerTag:
|
|
42
|
+
activity.on('start', (api) => this._onEnter(api), { consumerTag: ON_ENTER_TAG });
|
|
27
43
|
} else {
|
|
28
|
-
activity.on('enter', (api) => this._onEnter(api), { consumerTag:
|
|
44
|
+
activity.on('enter', (api) => this._onEnter(api), { consumerTag: ON_ENTER_TAG });
|
|
29
45
|
}
|
|
30
46
|
|
|
31
47
|
activity.on('activity.execution.completed', (api) => this._onExecuted(api), {
|
|
32
|
-
consumerTag:
|
|
48
|
+
consumerTag: ON_EXECUTED_TAG,
|
|
33
49
|
});
|
|
34
50
|
|
|
35
51
|
if (listeners?.onStart) {
|
|
36
|
-
activity.on('start', (api) => this._onListener('start', api), { consumerTag:
|
|
52
|
+
activity.on('start', (api) => this._onListener('start', api), { consumerTag: ON_START_TAG });
|
|
37
53
|
}
|
|
38
54
|
if (listeners?.onEnd) {
|
|
39
|
-
activity.on('end', (api) => this._onListener('end', api), { consumerTag:
|
|
55
|
+
activity.on('end', (api) => this._onListener('end', api), { consumerTag: ON_END_TAG });
|
|
40
56
|
}
|
|
41
57
|
}
|
|
42
58
|
deactivate() {
|
|
43
59
|
const broker = this.activity.broker;
|
|
44
|
-
broker.cancel(
|
|
45
|
-
broker.cancel(
|
|
46
|
-
broker.cancel(
|
|
47
|
-
broker.cancel(
|
|
60
|
+
broker.cancel(ON_ENTER_TAG);
|
|
61
|
+
broker.cancel(ON_EXECUTED_TAG);
|
|
62
|
+
broker.cancel(ON_START_TAG);
|
|
63
|
+
broker.cancel(ON_END_TAG);
|
|
48
64
|
}
|
|
49
|
-
/**
|
|
65
|
+
/**
|
|
66
|
+
* @internal Shared with SubProcessExtensions.
|
|
67
|
+
* @param {import('bpmn-elements').IApi<import('bpmn-elements').Activity>} elementApi
|
|
68
|
+
*/
|
|
50
69
|
async _onEnter(elementApi) {
|
|
51
70
|
this.formatQ.queueMessage({ routingKey: 'run.enter.format' }, { endRoutingKey: 'run.enter.complete' }, { persistent: false });
|
|
52
71
|
try {
|
|
@@ -56,7 +75,10 @@ export class ElementExtensions {
|
|
|
56
75
|
elementApi.broker.publish('format', 'run.enter.error', { error: err }, { persistent: false });
|
|
57
76
|
}
|
|
58
77
|
}
|
|
59
|
-
/**
|
|
78
|
+
/**
|
|
79
|
+
* @internal Shared with SubProcessExtensions.
|
|
80
|
+
* @param {import('bpmn-elements').IApi<import('bpmn-elements').Activity>} elementApi
|
|
81
|
+
*/
|
|
60
82
|
async _onExecuted(elementApi) {
|
|
61
83
|
this.formatQ.queueMessage({ routingKey: 'run.end.format' }, { endRoutingKey: 'run.end.complete' }, { persistent: false });
|
|
62
84
|
try {
|
|
@@ -66,7 +88,10 @@ export class ElementExtensions {
|
|
|
66
88
|
elementApi.broker.publish('format', 'run.end.error', { error: err }, { persistent: false });
|
|
67
89
|
}
|
|
68
90
|
}
|
|
69
|
-
/**
|
|
91
|
+
/**
|
|
92
|
+
* @internal Shared with SubProcessExtensions.
|
|
93
|
+
* @param {import('bpmn-elements').IApi<import('bpmn-elements').Activity>} elementApi
|
|
94
|
+
*/
|
|
70
95
|
async _onListener(eventType, elementApi) {
|
|
71
96
|
const routingKey = `run.listener.${eventType}`;
|
|
72
97
|
this.formatQ.queueMessage({ routingKey }, { endRoutingKey: `${routingKey}.complete` }, { persistent: false });
|
|
@@ -78,13 +103,17 @@ export class ElementExtensions {
|
|
|
78
103
|
elementApi.broker.publish('format', `${routingKey}.error`, { error: err }, { persistent: false });
|
|
79
104
|
}
|
|
80
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* @param {import('bpmn-elements').IApi<import('bpmn-elements').Activity>} elementApi
|
|
108
|
+
*/
|
|
81
109
|
#formatOnEnter(elementApi) {
|
|
82
|
-
const { format, io, headers, properties, form } = this.extensions;
|
|
110
|
+
const { format, io, headers, properties, form, subscription } = this.extensions;
|
|
83
111
|
const result = { ...format.resolve(elementApi) };
|
|
84
112
|
|
|
85
113
|
if (headers) result.headers = headers.resolve();
|
|
86
114
|
if (properties) result.properties = properties.resolve(elementApi);
|
|
87
115
|
if (form) result.form = form.resolve(elementApi);
|
|
116
|
+
if (subscription) result.subscription = subscription.resolve(elementApi);
|
|
88
117
|
if (io?.hasInput) {
|
|
89
118
|
result.input = io.getInput(elementApi);
|
|
90
119
|
// A (sub) process input mapping creates local variables visible to its children; a job
|
|
@@ -96,8 +125,11 @@ export class ElementExtensions {
|
|
|
96
125
|
Object.assign(elementApi.content, result);
|
|
97
126
|
return result;
|
|
98
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* @param {import('bpmn-elements').IApi<import('bpmn-elements').Activity>} elementApi
|
|
130
|
+
*/
|
|
99
131
|
#formatOnExecuted(elementApi) {
|
|
100
|
-
const { io, script, loop } = this.extensions;
|
|
132
|
+
const { io, script, calledDecision, loop } = this.extensions;
|
|
101
133
|
let jobResult = elementApi.content.output;
|
|
102
134
|
|
|
103
135
|
// Multi-instance: aggregate the per-instance outputs into the `outputCollection` array.
|
|
@@ -113,9 +145,10 @@ export class ElementExtensions {
|
|
|
113
145
|
jobResult = jobResult.output;
|
|
114
146
|
}
|
|
115
147
|
|
|
116
|
-
// A script task
|
|
117
|
-
// an object of variables.
|
|
118
|
-
const
|
|
148
|
+
// A script task (`zeebe:script`) or business rule task (`zeebe:calledDecision`) names its single
|
|
149
|
+
// result with `resultVariable`. A plain job's result is already an object of variables.
|
|
150
|
+
const named = script || calledDecision;
|
|
151
|
+
const resultObject = named ? (named.resultVariable ? { [named.resultVariable]: jobResult } : undefined) : jobResult;
|
|
119
152
|
|
|
120
153
|
let output;
|
|
121
154
|
if (io?.hasOutput) {
|
|
@@ -131,6 +164,10 @@ export class ElementExtensions {
|
|
|
131
164
|
}
|
|
132
165
|
return {};
|
|
133
166
|
}
|
|
167
|
+
/**
|
|
168
|
+
* @param {import('bpmn-elements').IApi<import('bpmn-elements').Activity>} elementApi
|
|
169
|
+
* @param {any} output
|
|
170
|
+
*/
|
|
134
171
|
#assignOutput(elementApi, output) {
|
|
135
172
|
const environment = this.activity.environment;
|
|
136
173
|
// Visible to downstream FEEL within the process, and surfaced as process output
|
package/src/Expressions.js
CHANGED
|
@@ -7,7 +7,7 @@ import { isFeelExpression, evaluateFeel } from './feel.js';
|
|
|
7
7
|
* definition resolves FEEL expressions (`= ...`) instead of the default
|
|
8
8
|
* `${...}` template expressions.
|
|
9
9
|
*
|
|
10
|
-
* @returns {import('bpmn-elements').IExpressions}
|
|
10
|
+
* @returns {import('bpmn-elements').IExpressions & {isExpression: (text:string) => boolean, hasExpression: (text:string) => boolean}}
|
|
11
11
|
*/
|
|
12
12
|
export function FeelExpressions() {
|
|
13
13
|
return {
|
|
@@ -42,8 +42,5 @@ function resolveExpression(templatedString, context) {
|
|
|
42
42
|
* (e.g. a multi-instance item).
|
|
43
43
|
*/
|
|
44
44
|
function getScope(context) {
|
|
45
|
-
|
|
46
|
-
const variables = environment ? environment.variables : {};
|
|
47
|
-
const local = context && context.content && context.content.variables;
|
|
48
|
-
return { ...variables, ...local };
|
|
45
|
+
return { ...context?.environment?.variables, ...context?.content?.variables };
|
|
49
46
|
}
|
package/src/ProcessExtensions.js
CHANGED
|
@@ -6,8 +6,12 @@ import { getExtensions } from './getExtensions.js';
|
|
|
6
6
|
* the result to the process variables.
|
|
7
7
|
*/
|
|
8
8
|
export class ProcessExtensions {
|
|
9
|
+
/**
|
|
10
|
+
* @param {import('bpmn-elements').Process} bp
|
|
11
|
+
*/
|
|
9
12
|
constructor(bp) {
|
|
10
13
|
this.process = bp;
|
|
14
|
+
/** @type {import('./getExtensions.js').ExtensionHandlers} */
|
|
11
15
|
this.extensions = getExtensions(bp);
|
|
12
16
|
}
|
|
13
17
|
activate() {
|
|
@@ -21,6 +25,9 @@ export class ProcessExtensions {
|
|
|
21
25
|
deactivate() {
|
|
22
26
|
this.process.broker.cancel('0dep-bpmn-extensions:on-enter');
|
|
23
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* @param {import('bpmn-elements').IApi<import('bpmn-elements').Process>} elementApi
|
|
30
|
+
*/
|
|
24
31
|
#onEnter(elementApi) {
|
|
25
32
|
try {
|
|
26
33
|
// bpmn-elements (>=18.0.4) forwards a call activity's formatted input — its io mapping plus,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ElementExtensions } from './ElementExtensions.js';
|
|
1
|
+
import { ElementExtensions, ON_ENTER_TAG, ON_EXECUTED_TAG, ON_START_TAG, ON_END_TAG } from './ElementExtensions.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Sub-process extensions.
|
|
@@ -14,14 +14,14 @@ export class SubProcessExtensions extends ElementExtensions {
|
|
|
14
14
|
const listeners = this.extensions.listeners;
|
|
15
15
|
const enterKey = message.fields.redelivered && message.fields.routingKey === 'run.start' ? 'activity.start' : 'activity.enter';
|
|
16
16
|
|
|
17
|
-
this.#subscribe(enterKey, (api) => this._onEnter(api),
|
|
18
|
-
this.#subscribe('activity.execution.completed', (api) => this._onExecuted(api),
|
|
17
|
+
this.#subscribe(enterKey, (api) => this._onEnter(api), ON_ENTER_TAG);
|
|
18
|
+
this.#subscribe('activity.execution.completed', (api) => this._onExecuted(api), ON_EXECUTED_TAG);
|
|
19
19
|
|
|
20
20
|
if (listeners?.onStart) {
|
|
21
|
-
this.#subscribe('activity.start', (api) => this._onListener('start', api),
|
|
21
|
+
this.#subscribe('activity.start', (api) => this._onListener('start', api), ON_START_TAG);
|
|
22
22
|
}
|
|
23
23
|
if (listeners?.onEnd) {
|
|
24
|
-
this.#subscribe('activity.end', (api) => this._onListener('end', api),
|
|
24
|
+
this.#subscribe('activity.end', (api) => this._onListener('end', api), ON_END_TAG);
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
#subscribe(routingKey, callback, consumerTag) {
|
|
@@ -16,10 +16,18 @@ export function FeelScripts() {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
class FeelScriptRegistry {
|
|
19
|
-
register() {
|
|
19
|
+
register() {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* @param {string} _scriptFormat
|
|
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`
|
|
27
|
+
*/
|
|
20
28
|
getScript(_scriptFormat, activity) {
|
|
21
29
|
const expression = getScriptExpression(activity);
|
|
22
|
-
if (expression === undefined) return undefined;
|
|
30
|
+
if (expression === undefined) return /** @type {any} */ (undefined);
|
|
23
31
|
return new FeelScript(expression);
|
|
24
32
|
}
|
|
25
33
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { resolveValue } from '../feel.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* `zeebe:subscription` — rides on the referenced `bpmn:Message`, not on the catching element.
|
|
5
|
+
*
|
|
6
|
+
* Resolves the correlation key in the activity's variable scope on enter and exposes it on the
|
|
7
|
+
* element content as `subscription`. Correlation itself is the embedding application's job:
|
|
8
|
+
* read the resolved key off the waiting activity (`getPostponed()` → `content.subscription`)
|
|
9
|
+
* and signal the matching one (`api.signal(...)`).
|
|
10
|
+
*/
|
|
11
|
+
export class Subscription {
|
|
12
|
+
/**
|
|
13
|
+
* @param {{ id: string, name?: string }} messageRef The serialized message reference
|
|
14
|
+
* @param {{ correlationKey: string }} subscription The `zeebe:Subscription` behaviour
|
|
15
|
+
*/
|
|
16
|
+
constructor(messageRef, subscription) {
|
|
17
|
+
this.message = { id: messageRef.id, name: messageRef.name };
|
|
18
|
+
this.correlationKey = subscription.correlationKey;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* @param {import('bpmn-elements').IApi<any>} elementApi
|
|
22
|
+
* @returns {{ message: { id: string, name?: string }, correlationKey: any }}
|
|
23
|
+
*/
|
|
24
|
+
resolve(elementApi) {
|
|
25
|
+
return {
|
|
26
|
+
message: this.message,
|
|
27
|
+
correlationKey: resolveValue(this.correlationKey, elementApi.environment.variables),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -22,6 +22,12 @@ export function JobService(taskType, activity) {
|
|
|
22
22
|
this.activity = activity;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Execute
|
|
27
|
+
* @param {import('bpmn-elements').ElementBrokerMessage} executionMessage
|
|
28
|
+
* @param {CallableFunction} callback
|
|
29
|
+
* @returns {any}
|
|
30
|
+
*/
|
|
25
31
|
JobService.prototype.execute = function execute(executionMessage, callback) {
|
|
26
32
|
const activity = this.activity;
|
|
27
33
|
const environment = activity.environment;
|
|
@@ -5,10 +5,17 @@ import { resolveValue } from '../feel.js';
|
|
|
5
5
|
* for user tasks, the `zeebe:assignmentDefinition` (assignee, candidate users/groups).
|
|
6
6
|
*/
|
|
7
7
|
export class FormatActivity {
|
|
8
|
+
/**
|
|
9
|
+
* @param {import('bpmn-elements').Activity} activity
|
|
10
|
+
* @param {any} assignmentDefinition
|
|
11
|
+
*/
|
|
8
12
|
constructor(activity, assignmentDefinition) {
|
|
9
13
|
this.activity = activity;
|
|
10
14
|
this.assignmentDefinition = assignmentDefinition;
|
|
11
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* @param {import('bpmn-elements').IApi<import('bpmn-elements').Activity>} elementApi
|
|
18
|
+
*/
|
|
12
19
|
resolve(elementApi) {
|
|
13
20
|
const scope = elementApi.environment.variables;
|
|
14
21
|
const result = {};
|
|
@@ -37,9 +44,15 @@ export class FormatActivity {
|
|
|
37
44
|
* Format a process on enter: documentation.
|
|
38
45
|
*/
|
|
39
46
|
export class FormatProcess {
|
|
47
|
+
/**
|
|
48
|
+
* @param {import('bpmn-elements').Process} bp
|
|
49
|
+
*/
|
|
40
50
|
constructor(bp) {
|
|
41
51
|
this.process = bp;
|
|
42
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* @param {import('bpmn-elements').IApi<import('bpmn-elements').Process>} elementApi
|
|
55
|
+
*/
|
|
43
56
|
resolve(elementApi) {
|
|
44
57
|
const result = {};
|
|
45
58
|
const documentation = this.process.behaviour.documentation;
|
|
@@ -58,7 +71,7 @@ export class FormatProcess {
|
|
|
58
71
|
function resolveList(value, scope) {
|
|
59
72
|
if (!value) return undefined;
|
|
60
73
|
const resolved = resolveValue(value, scope);
|
|
61
|
-
if (Array.isArray(resolved)) return resolved.filter(
|
|
74
|
+
if (Array.isArray(resolved)) return resolved.filter(Boolean);
|
|
62
75
|
if (typeof resolved !== 'string') return undefined;
|
|
63
76
|
return resolved
|
|
64
77
|
.split(',')
|
package/src/feel.js
CHANGED
|
@@ -40,11 +40,11 @@ export function evaluateFeel(expression, context) {
|
|
|
40
40
|
* @param {string} expression FEEL unary test
|
|
41
41
|
* @param {any} input The value being tested, available as `?` in the test
|
|
42
42
|
* @param {Record<string, any>} [context] Additional variables in scope
|
|
43
|
-
* @returns {boolean}
|
|
43
|
+
* @returns {boolean} true only when the test is satisfied — an undecidable (null) test is false
|
|
44
44
|
*/
|
|
45
45
|
export function evaluateFeelUnaryTest(expression, input, context) {
|
|
46
|
-
const { value } = unaryTest(stripFeel(expression), { ...
|
|
47
|
-
return value;
|
|
46
|
+
const { value } = unaryTest(stripFeel(expression), { ...context, '?': input });
|
|
47
|
+
return value === true;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
/**
|
package/src/getExtensions.js
CHANGED
|
@@ -6,22 +6,31 @@ import { ExecutionListeners } from './extensions/ExecutionListeners.js';
|
|
|
6
6
|
import { Form } from './extensions/Form.js';
|
|
7
7
|
import { LoopCharacteristics } from './extensions/LoopCharacteristics.js';
|
|
8
8
|
import { JobService } from './extensions/TaskDefinition.js';
|
|
9
|
+
import { Subscription } from './extensions/Subscription.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The extension handlers assembled for one element.
|
|
13
|
+
* @typedef {object} ExtensionHandlers
|
|
14
|
+
* @property {FormatActivity | FormatProcess} format
|
|
15
|
+
* @property {IoMapping} [io]
|
|
16
|
+
* @property {TaskHeaders} [headers]
|
|
17
|
+
* @property {Properties} [properties]
|
|
18
|
+
* @property {ExecutionListeners} [listeners]
|
|
19
|
+
* @property {Form} [form]
|
|
20
|
+
* @property {LoopCharacteristics} [loop]
|
|
21
|
+
* @property {any} [script]
|
|
22
|
+
* @property {any} [calledDecision]
|
|
23
|
+
* @property {Function} [Service]
|
|
24
|
+
* @property {Subscription} [subscription]
|
|
25
|
+
*/
|
|
9
26
|
|
|
10
27
|
/**
|
|
11
28
|
* Inspect an element's extension elements and assemble the extension handlers it needs.
|
|
12
29
|
* @param {import('bpmn-elements').Activity | import('bpmn-elements').Process} element
|
|
13
|
-
* @
|
|
14
|
-
*
|
|
15
|
-
* io?: IoMapping,
|
|
16
|
-
* headers?: TaskHeaders,
|
|
17
|
-
* properties?: Properties,
|
|
18
|
-
* listeners?: ExecutionListeners,
|
|
19
|
-
* form?: Form,
|
|
20
|
-
* loop?: LoopCharacteristics,
|
|
21
|
-
* Service?: Function,
|
|
22
|
-
* }}
|
|
30
|
+
* @param {import('bpmn-elements').ContextInstance} [context]
|
|
31
|
+
* @returns {ExtensionHandlers}
|
|
23
32
|
*/
|
|
24
|
-
export function getExtensions(element) {
|
|
33
|
+
export function getExtensions(element, context) {
|
|
25
34
|
const result = {};
|
|
26
35
|
const isProcess = element.type === 'bpmn:Process';
|
|
27
36
|
|
|
@@ -51,6 +60,13 @@ export function getExtensions(element) {
|
|
|
51
60
|
case 'zeebe:Script':
|
|
52
61
|
result.script = ext;
|
|
53
62
|
break;
|
|
63
|
+
case 'zeebe:CalledDecision':
|
|
64
|
+
// A business rule task runs as a service task (bpmn-elements maps it to ServiceTask). The
|
|
65
|
+
// decision is resolved by an environment service named by the decision id; its result is
|
|
66
|
+
// named by `resultVariable`.
|
|
67
|
+
result.calledDecision = ext;
|
|
68
|
+
result.Service = JobService.bind(JobService, ext.decisionId);
|
|
69
|
+
break;
|
|
54
70
|
case 'zeebe:FormDefinition':
|
|
55
71
|
result.form = new Form(ext);
|
|
56
72
|
break;
|
|
@@ -58,6 +74,18 @@ export function getExtensions(element) {
|
|
|
58
74
|
}
|
|
59
75
|
}
|
|
60
76
|
|
|
77
|
+
// A message catch (receive task / message event) may reference a bpmn:Message carrying a
|
|
78
|
+
// zeebe:subscription with the correlation key. The subscription lives on the message element,
|
|
79
|
+
// which the instantiated bpmn-elements Message strips — read it off the serialized context.
|
|
80
|
+
const messageRef =
|
|
81
|
+
element.behaviour.messageRef ?? element.behaviour.eventDefinitions?.find((ed) => ed.behaviour?.messageRef)?.behaviour.messageRef;
|
|
82
|
+
if (messageRef?.id && context) {
|
|
83
|
+
const subscription = context.definitionContext
|
|
84
|
+
.getActivityById(messageRef.id)
|
|
85
|
+
?.behaviour.extensionElements?.values?.find((v) => v.$type === 'zeebe:Subscription');
|
|
86
|
+
if (subscription?.correlationKey) result.subscription = new Subscription(messageRef, subscription);
|
|
87
|
+
}
|
|
88
|
+
|
|
61
89
|
// Output side of a multi-instance `zeebe:loopCharacteristics` (the input side is lifted by extendFn).
|
|
62
90
|
const loopExtension = element.behaviour.loopCharacteristics?.behaviour?.extensionElements?.values?.find(
|
|
63
91
|
(v) => v.$type === 'zeebe:LoopCharacteristics'
|
package/src/index.js
CHANGED
|
@@ -12,8 +12,8 @@ export { ServiceError, FormatError } from './Errors.js';
|
|
|
12
12
|
/**
|
|
13
13
|
* A flow extension activated by bpmn-elements around an element's run.
|
|
14
14
|
* @typedef {object} FlowExtension
|
|
15
|
-
* @property {(message:
|
|
16
|
-
* @property {(message?:
|
|
15
|
+
* @property {(message: import('bpmn-elements').ElementBrokerMessage) => void} activate
|
|
16
|
+
* @property {(message?: import('bpmn-elements').ElementBrokerMessage) => void} deactivate
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
/**
|
package/types/index.d.ts
CHANGED
|
@@ -18,8 +18,8 @@ declare module '@0dep/bpmn-extensions' {
|
|
|
18
18
|
* A flow extension activated by bpmn-elements around an element's run.
|
|
19
19
|
*/
|
|
20
20
|
export type FlowExtension = {
|
|
21
|
-
activate: (message:
|
|
22
|
-
deactivate: (message?:
|
|
21
|
+
activate: (message: import("bpmn-elements").ElementBrokerMessage) => void;
|
|
22
|
+
deactivate: (message?: import("bpmn-elements").ElementBrokerMessage) => void;
|
|
23
23
|
};
|
|
24
24
|
/**
|
|
25
25
|
* FEEL-aware expressions implementation for bpmn-elements.
|
|
@@ -29,7 +29,10 @@ declare module '@0dep/bpmn-extensions' {
|
|
|
29
29
|
* `${...}` template expressions.
|
|
30
30
|
*
|
|
31
31
|
* */
|
|
32
|
-
export function FeelExpressions(): import("bpmn-elements").IExpressions
|
|
32
|
+
export function FeelExpressions(): import("bpmn-elements").IExpressions & {
|
|
33
|
+
isExpression: (text: string) => boolean;
|
|
34
|
+
hasExpression: (text: string) => boolean;
|
|
35
|
+
};
|
|
33
36
|
/**
|
|
34
37
|
* A bpmn-elements `scripts` implementation for script tasks.
|
|
35
38
|
*
|
|
@@ -75,7 +78,10 @@ declare module '@0dep/bpmn-extensions' {
|
|
|
75
78
|
type: string | undefined;
|
|
76
79
|
taskType: any;
|
|
77
80
|
activity: any;
|
|
78
|
-
|
|
81
|
+
/**
|
|
82
|
+
* Execute
|
|
83
|
+
* */
|
|
84
|
+
execute(executionMessage: import("bpmn-elements").ElementBrokerMessage, callback: CallableFunction): any;
|
|
79
85
|
}
|
|
80
86
|
/**
|
|
81
87
|
* Activity-level extensions.
|
|
@@ -85,27 +91,29 @@ declare module '@0dep/bpmn-extensions' {
|
|
|
85
91
|
* proceeding — the same mechanism bpmn-elements uses for extension formatting.
|
|
86
92
|
*/
|
|
87
93
|
export class ElementExtensions {
|
|
88
|
-
|
|
89
|
-
activity:
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
loop?: LoopCharacteristics;
|
|
99
|
-
Service?: Function;
|
|
100
|
-
};
|
|
101
|
-
activate(message: any): void;
|
|
94
|
+
|
|
95
|
+
constructor(activity: import("bpmn-elements").Activity, context: import("bpmn-elements").ContextInstance);
|
|
96
|
+
activity: import("bpmn-elements").Activity;
|
|
97
|
+
formatQ: import("smqp").Queue | undefined;
|
|
98
|
+
|
|
99
|
+
extensions: ExtensionHandlers;
|
|
100
|
+
/**
|
|
101
|
+
* Activate extensions
|
|
102
|
+
* */
|
|
103
|
+
activate(message: import("bpmn-elements").ElementBrokerMessage): void;
|
|
102
104
|
deactivate(): void;
|
|
103
|
-
/**
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
|
|
105
|
+
/**
|
|
106
|
+
* @internal Shared with SubProcessExtensions.
|
|
107
|
+
* */
|
|
108
|
+
_onEnter(elementApi: import("bpmn-elements").IApi<import("bpmn-elements").Activity>): Promise<void>;
|
|
109
|
+
/**
|
|
110
|
+
* @internal Shared with SubProcessExtensions.
|
|
111
|
+
* */
|
|
112
|
+
_onExecuted(elementApi: import("bpmn-elements").IApi<import("bpmn-elements").Activity>): Promise<void>;
|
|
113
|
+
/**
|
|
114
|
+
* @internal Shared with SubProcessExtensions.
|
|
115
|
+
* */
|
|
116
|
+
_onListener(eventType: any, elementApi: import("bpmn-elements").IApi<import("bpmn-elements").Activity>): Promise<void>;
|
|
109
117
|
#private;
|
|
110
118
|
}
|
|
111
119
|
/**
|
|
@@ -113,18 +121,11 @@ declare module '@0dep/bpmn-extensions' {
|
|
|
113
121
|
* the result to the process variables.
|
|
114
122
|
*/
|
|
115
123
|
export class ProcessExtensions {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
headers?: TaskHeaders;
|
|
122
|
-
properties?: Properties;
|
|
123
|
-
listeners?: ExecutionListeners;
|
|
124
|
-
form?: Form;
|
|
125
|
-
loop?: LoopCharacteristics;
|
|
126
|
-
Service?: Function;
|
|
127
|
-
};
|
|
124
|
+
|
|
125
|
+
constructor(bp: import("bpmn-elements").Process);
|
|
126
|
+
process: import("bpmn-elements").Process;
|
|
127
|
+
|
|
128
|
+
extensions: ExtensionHandlers;
|
|
128
129
|
activate(): void;
|
|
129
130
|
deactivate(): void;
|
|
130
131
|
#private;
|
|
@@ -139,6 +140,7 @@ declare module '@0dep/bpmn-extensions' {
|
|
|
139
140
|
* sub-process's own id.
|
|
140
141
|
*/
|
|
141
142
|
export class SubProcessExtensions extends ElementExtensions {
|
|
143
|
+
activate(message: any): void;
|
|
142
144
|
#private;
|
|
143
145
|
}
|
|
144
146
|
/**
|
|
@@ -160,7 +162,8 @@ declare module '@0dep/bpmn-extensions' {
|
|
|
160
162
|
* @param expression FEEL unary test
|
|
161
163
|
* @param input The value being tested, available as `?` in the test
|
|
162
164
|
* @param context Additional variables in scope
|
|
163
|
-
*
|
|
165
|
+
* @returns true only when the test is satisfied — an undecidable (null) test is false
|
|
166
|
+
*/
|
|
164
167
|
export function evaluateFeelUnaryTest(expression: string, input: any, context?: Record<string, any>): boolean;
|
|
165
168
|
/**
|
|
166
169
|
* Resolve a value: evaluate it as FEEL when it starts with `=`, otherwise
|
|
@@ -182,15 +185,33 @@ declare module '@0dep/bpmn-extensions' {
|
|
|
182
185
|
statusCode: number;
|
|
183
186
|
};
|
|
184
187
|
}
|
|
188
|
+
/**
|
|
189
|
+
* The extension handlers assembled for one element.
|
|
190
|
+
*/
|
|
191
|
+
type ExtensionHandlers = {
|
|
192
|
+
format: FormatActivity | FormatProcess;
|
|
193
|
+
io?: IoMapping | undefined;
|
|
194
|
+
headers?: TaskHeaders | undefined;
|
|
195
|
+
properties?: Properties | undefined;
|
|
196
|
+
listeners?: ExecutionListeners | undefined;
|
|
197
|
+
form?: Form | undefined;
|
|
198
|
+
loop?: LoopCharacteristics | undefined;
|
|
199
|
+
script?: any;
|
|
200
|
+
calledDecision?: any;
|
|
201
|
+
Service?: Function | undefined;
|
|
202
|
+
subscription?: Subscription | undefined;
|
|
203
|
+
};
|
|
185
204
|
/**
|
|
186
205
|
* Format an activity on enter from its behaviour and extensions: documentation and,
|
|
187
206
|
* for user tasks, the `zeebe:assignmentDefinition` (assignee, candidate users/groups).
|
|
188
207
|
*/
|
|
189
208
|
class FormatActivity {
|
|
190
|
-
|
|
191
|
-
activity: any;
|
|
209
|
+
|
|
210
|
+
constructor(activity: import("bpmn-elements").Activity, assignmentDefinition: any);
|
|
211
|
+
activity: import("bpmn-elements").Activity;
|
|
192
212
|
assignmentDefinition: any;
|
|
193
|
-
|
|
213
|
+
|
|
214
|
+
resolve(elementApi: import("bpmn-elements").IApi<import("bpmn-elements").Activity>): {
|
|
194
215
|
description: any;
|
|
195
216
|
assignee: any;
|
|
196
217
|
candidateUsers: any[];
|
|
@@ -201,9 +222,11 @@ declare module '@0dep/bpmn-extensions' {
|
|
|
201
222
|
* Format a process on enter: documentation.
|
|
202
223
|
*/
|
|
203
224
|
class FormatProcess {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
225
|
+
|
|
226
|
+
constructor(bp: import("bpmn-elements").Process);
|
|
227
|
+
process: import("bpmn-elements").Process;
|
|
228
|
+
|
|
229
|
+
resolve(elementApi: import("bpmn-elements").IApi<import("bpmn-elements").Process>): {
|
|
207
230
|
description: any;
|
|
208
231
|
};
|
|
209
232
|
}
|
|
@@ -319,6 +342,39 @@ declare module '@0dep/bpmn-extensions' {
|
|
|
319
342
|
* */
|
|
320
343
|
aggregate(indexedOutput: Record<string, any> | undefined, baseScope: Record<string, any>): any[];
|
|
321
344
|
}
|
|
345
|
+
/**
|
|
346
|
+
* `zeebe:subscription` — rides on the referenced `bpmn:Message`, not on the catching element.
|
|
347
|
+
*
|
|
348
|
+
* Resolves the correlation key in the activity's variable scope on enter and exposes it on the
|
|
349
|
+
* element content as `subscription`. Correlation itself is the embedding application's job:
|
|
350
|
+
* read the resolved key off the waiting activity (`getPostponed()` → `content.subscription`)
|
|
351
|
+
* and signal the matching one (`api.signal(...)`).
|
|
352
|
+
*/
|
|
353
|
+
class Subscription {
|
|
354
|
+
/**
|
|
355
|
+
* @param messageRef The serialized message reference
|
|
356
|
+
* @param subscription The `zeebe:Subscription` behaviour
|
|
357
|
+
*/
|
|
358
|
+
constructor(messageRef: {
|
|
359
|
+
id: string;
|
|
360
|
+
name?: string;
|
|
361
|
+
}, subscription: {
|
|
362
|
+
correlationKey: string;
|
|
363
|
+
});
|
|
364
|
+
message: {
|
|
365
|
+
id: string;
|
|
366
|
+
name: string | undefined;
|
|
367
|
+
};
|
|
368
|
+
correlationKey: string;
|
|
369
|
+
|
|
370
|
+
resolve(elementApi: import("bpmn-elements").IApi<any>): {
|
|
371
|
+
message: {
|
|
372
|
+
id: string;
|
|
373
|
+
name?: string;
|
|
374
|
+
};
|
|
375
|
+
correlationKey: any;
|
|
376
|
+
};
|
|
377
|
+
}
|
|
322
378
|
|
|
323
379
|
export {};
|
|
324
380
|
}
|
package/types/index.d.ts.map
CHANGED
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
"Properties",
|
|
25
25
|
"ExecutionListeners",
|
|
26
26
|
"Form",
|
|
27
|
-
"LoopCharacteristics"
|
|
27
|
+
"LoopCharacteristics",
|
|
28
|
+
"Subscription"
|
|
28
29
|
],
|
|
29
30
|
"sources": [
|
|
30
31
|
"../src/index.js",
|
|
@@ -42,7 +43,8 @@
|
|
|
42
43
|
"../src/extensions/Properties.js",
|
|
43
44
|
"../src/extensions/ExecutionListeners.js",
|
|
44
45
|
"../src/extensions/Form.js",
|
|
45
|
-
"../src/extensions/LoopCharacteristics.js"
|
|
46
|
+
"../src/extensions/LoopCharacteristics.js",
|
|
47
|
+
"../src/extensions/Subscription.js"
|
|
46
48
|
],
|
|
47
49
|
"sourcesContent": [
|
|
48
50
|
null,
|
|
@@ -60,8 +62,9 @@
|
|
|
60
62
|
null,
|
|
61
63
|
null,
|
|
62
64
|
null,
|
|
65
|
+
null,
|
|
63
66
|
null
|
|
64
67
|
],
|
|
65
|
-
"mappings": ";;;;;;;iBAwBgBA,UAAUA;;;;;;;;iBAqBVC,QAAQA;;;;;;;;;;;;;;;;iBClCRC,eAAeA
|
|
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",
|
|
66
69
|
"ignoreList": []
|
|
67
70
|
}
|