@0dep/bpmn-extensions 0.0.5 → 0.1.0
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 +80 -4
- package/dist/index.js +71 -5
- package/package.json +9 -4
- package/src/TimerEventDefinition.js +46 -0
- package/src/extensions/formatters.js +7 -2
- package/src/getExtensions.js +8 -2
- package/src/index.js +9 -1
- package/types/index.d.ts +21 -3
- package/types/index.d.ts.map +4 -1
package/README.md
CHANGED
|
@@ -9,13 +9,27 @@ It teaches a bpmn-elements engine to run BPMN that uses the `zeebe:*` extension
|
|
|
9
9
|
expressions (`= ...`) — the counterpart to [`@onify/flow-extensions`](https://github.com/onify/flow-extensions),
|
|
10
10
|
which covers the older `camunda:*` extension elements.
|
|
11
11
|
|
|
12
|
+
<!-- toc -->
|
|
13
|
+
|
|
14
|
+
- [Install](#install)
|
|
15
|
+
- [What it does](#what-it-does)
|
|
16
|
+
- [API](#api)
|
|
17
|
+
- [Usage](#usage)
|
|
18
|
+
- [Extract timers](#extract-timers)
|
|
19
|
+
- [Development](#development)
|
|
20
|
+
- [Ecosystem](#ecosystem)
|
|
21
|
+
- [License](#license)
|
|
22
|
+
|
|
23
|
+
<!-- /toc -->
|
|
24
|
+
|
|
12
25
|
## Install
|
|
13
26
|
|
|
14
27
|
```sh
|
|
15
|
-
npm install @0dep/bpmn-extensions bpmn-elements
|
|
28
|
+
npm install @0dep/bpmn-extensions bpmn-elements croner
|
|
16
29
|
```
|
|
17
30
|
|
|
18
|
-
`bpmn-elements` (>= 18)
|
|
31
|
+
`bpmn-elements` (>= 18) and [`croner`](https://www.npmjs.com/package/croner) (cron timer cycles) are
|
|
32
|
+
peer dependencies. Requires Node.js >= 22.
|
|
19
33
|
|
|
20
34
|
## What it does
|
|
21
35
|
|
|
@@ -49,6 +63,10 @@ npm install @0dep/bpmn-extensions bpmn-elements
|
|
|
49
63
|
- **`zeebe:calledElement`** — call activity target process id.
|
|
50
64
|
- **`zeebe:loopCharacteristics`** — collection-based multi-instance (`inputCollection` / `inputElement`),
|
|
51
65
|
sequential or parallel, with `outputElement` aggregated into the `outputCollection` array in input order.
|
|
66
|
+
- **Timer start events with cron** — a `TimerEventDefinition` that also parses a **cron** `timeCycle`
|
|
67
|
+
(`0 0 * * *`, as Camunda 8 schedules timer start events) besides ISO 8601 intervals. A top-level
|
|
68
|
+
timer start event's cycle is lifted onto its behaviour as `scheduledStart` by `extendFn` and exposed
|
|
69
|
+
on the start event content, so a scheduler can find the flows to start without running them.
|
|
52
70
|
- **`zeebe:subscription`** — the referenced message's `correlationKey` is resolved when the catching
|
|
53
71
|
element (receive task, message event) starts waiting, and exposed on its content as
|
|
54
72
|
`subscription: { message, correlationKey }` — route an incoming message by matching it against the
|
|
@@ -61,7 +79,10 @@ npm install @0dep/bpmn-extensions bpmn-elements
|
|
|
61
79
|
at all and run untouched; call activities and processes are always attached, since they propagate
|
|
62
80
|
io across process boundaries.
|
|
63
81
|
- `extendFn(behaviour)` — moddle-context-serializer behaviour extender (lifts the extension data
|
|
64
|
-
bpmn-elements expects on the behaviour: call activity process id
|
|
82
|
+
bpmn-elements expects on the behaviour: call activity process id, multi-instance collection, and a
|
|
83
|
+
timer start event's cycle as `scheduledStart`).
|
|
84
|
+
- `TimerEventDefinition` — a bpmn-elements timer event definition that accepts cron `timeCycle`s;
|
|
85
|
+
install it through the type resolver: `TypeResolver({ ...elements, TimerEventDefinition })`.
|
|
65
86
|
- `FeelExpressions()` — a bpmn-elements `IExpressions` implementation backed by FEEL.
|
|
66
87
|
- `FeelScripts()` — a bpmn-elements `scripts` implementation that runs `zeebe:script` FEEL expressions.
|
|
67
88
|
- FEEL helpers: `isFeelExpression`, `stripFeel`, `evaluateFeel`, `evaluateFeelUnaryTest`, `resolveValue`,
|
|
@@ -130,6 +151,60 @@ A service task's `zeebe:taskDefinition type="charge-card"` is dispatched to the
|
|
|
130
151
|
service named `charge-card`. Its callback result is the job's variables, which `zeebe:ioMapping`
|
|
131
152
|
output parameters map back into the process.
|
|
132
153
|
|
|
154
|
+
## Extract timers
|
|
155
|
+
|
|
156
|
+
List the timers of a definition without running it — e.g. to schedule flows by their timer start
|
|
157
|
+
event. The serializer collects every timer event definition; `extendFn` marks a timer start event's
|
|
158
|
+
cycle as `scheduledStart`, and the cron-capable `TimerEventDefinition` parses each one to its next
|
|
159
|
+
expiry:
|
|
160
|
+
|
|
161
|
+
```javascript
|
|
162
|
+
import { createRequire } from 'node:module';
|
|
163
|
+
import { strict as assert } from 'node:assert';
|
|
164
|
+
import { BpmnModdle } from 'bpmn-moddle';
|
|
165
|
+
import * as elements from 'bpmn-elements';
|
|
166
|
+
import { Serializer, TypeResolver } from 'moddle-context-serializer';
|
|
167
|
+
import { extendFn, TimerEventDefinition } from '@0dep/bpmn-extensions';
|
|
168
|
+
|
|
169
|
+
const require = createRequire(import.meta.url);
|
|
170
|
+
const moddle = new BpmnModdle({ zeebe: require('zeebe-bpmn-moddle/resources/zeebe.json') });
|
|
171
|
+
|
|
172
|
+
const source = `<?xml version="1.0" encoding="UTF-8"?>
|
|
173
|
+
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="def">
|
|
174
|
+
<process id="nightly" isExecutable="true">
|
|
175
|
+
<startEvent id="start">
|
|
176
|
+
<timerEventDefinition>
|
|
177
|
+
<timeCycle xsi:type="tFormalExpression">0 1 * * *</timeCycle>
|
|
178
|
+
</timerEventDefinition>
|
|
179
|
+
</startEvent>
|
|
180
|
+
<sequenceFlow id="to-task" sourceRef="start" targetRef="task" />
|
|
181
|
+
<userTask id="task" />
|
|
182
|
+
<boundaryEvent id="reminder" cancelActivity="false" attachedToRef="task">
|
|
183
|
+
<timerEventDefinition>
|
|
184
|
+
<timeDuration xsi:type="tFormalExpression">R3/PT1M</timeDuration>
|
|
185
|
+
</timerEventDefinition>
|
|
186
|
+
</boundaryEvent>
|
|
187
|
+
</process>
|
|
188
|
+
</definitions>`;
|
|
189
|
+
|
|
190
|
+
const moddleContext = await moddle.fromXML(source);
|
|
191
|
+
const serializer = Serializer(moddleContext, TypeResolver({ ...elements, TimerEventDefinition }), extendFn);
|
|
192
|
+
|
|
193
|
+
const dummyActivity = { id: 'dummy', broker: {}, environment: { Logger() {} } };
|
|
194
|
+
const timers = serializer.getTimers().map((t) => ({
|
|
195
|
+
...t,
|
|
196
|
+
parsed: new TimerEventDefinition(dummyActivity, { type: t.timer.type, behaviour: t.timer }).parse(t.timer.timerType, t.timer.value),
|
|
197
|
+
}));
|
|
198
|
+
|
|
199
|
+
console.log(timers.map((t) => [t.parent.id, t.timer.timerType, t.timer.value, t.parsed.expireAt]));
|
|
200
|
+
assert.equal(timers.length, 2);
|
|
201
|
+
assert.equal(timers[0].parent.id, 'start');
|
|
202
|
+
assert.ok(timers[0].parsed.expireAt instanceof Date);
|
|
203
|
+
|
|
204
|
+
// A timer start event is a schedule: the cycle is lifted onto the behaviour
|
|
205
|
+
assert.equal(serializer.getActivityById('start').behaviour.scheduledStart, '0 1 * * *');
|
|
206
|
+
```
|
|
207
|
+
|
|
133
208
|
## Development
|
|
134
209
|
|
|
135
210
|
```sh
|
|
@@ -145,8 +220,9 @@ in `test/helpers/factory.js`, then run on a real bpmn-elements `Definition`. The
|
|
|
145
220
|
the engine's `Logger` to the [`debug`](https://www.npmjs.com/package/debug) package, so
|
|
146
221
|
`DEBUG=bpmn-extensions:* npm test` traces the engine and extensions (`:error:*` for errors only).
|
|
147
222
|
|
|
148
|
-
|
|
223
|
+
## Ecosystem
|
|
149
224
|
|
|
225
|
+
- [0dep.se/run](https://0dep.se/run) — Run a BPMN diagram in the browser: `bpmn-elements` wired with `@0dep/bpmn-extensions`, drawn with bpmn-js; step through, signal waiting tasks, and drop DMN files for business rule tasks.
|
|
150
226
|
- [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.
|
|
151
227
|
- [bpmn-middleware](https://github.com/zerodep/bpmn-middleware) — Express middleware exposing the engine over HTTP, with pluggable state storage.
|
|
152
228
|
- [@onify/flow-extensions](https://github.com/onify/flow-extensions) — Onify Flow extensions for `bpmn-elements`.
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var croner = require('croner');
|
|
4
|
+
var bpmnElements = require('bpmn-elements');
|
|
5
|
+
|
|
3
6
|
// these aren't really private, but nor are they really useful to document
|
|
4
7
|
|
|
5
8
|
/**
|
|
@@ -16211,8 +16214,8 @@ function getFeelScope(environment, localVariables) {
|
|
|
16211
16214
|
}
|
|
16212
16215
|
|
|
16213
16216
|
/**
|
|
16214
|
-
* Format an activity on enter from its behaviour and extensions: documentation
|
|
16215
|
-
* for user tasks, the `zeebe:assignmentDefinition` (assignee, candidate users/groups),
|
|
16217
|
+
* Format an activity on enter from its behaviour and extensions: documentation, a top-level
|
|
16218
|
+
* timer start event's `scheduledStart` (lifted by `extendFn`) and, for user tasks, the `zeebe:assignmentDefinition` (assignee, candidate users/groups),
|
|
16216
16219
|
* `zeebe:priorityDefinition` (priority), and `zeebe:taskSchedule` (due/follow-up date).
|
|
16217
16220
|
*/
|
|
16218
16221
|
class FormatActivity {
|
|
@@ -16241,6 +16244,11 @@ class FormatActivity {
|
|
|
16241
16244
|
if (text) result.description = /** @type {string} */ (resolveValue(text, scope));
|
|
16242
16245
|
}
|
|
16243
16246
|
|
|
16247
|
+
// A timer start event's cycle is only a schedule when it starts the process itself — a
|
|
16248
|
+
// sub-process start event runs whenever its parent does.
|
|
16249
|
+
const scheduledStart = this.activity.behaviour.scheduledStart;
|
|
16250
|
+
if (scheduledStart && this.activity.parent?.type === 'bpmn:Process') result.scheduledStart = scheduledStart;
|
|
16251
|
+
|
|
16244
16252
|
const assignment = this.assignmentDefinition;
|
|
16245
16253
|
if (assignment) {
|
|
16246
16254
|
const { assignee, candidateUsers, candidateGroups } = assignment;
|
|
@@ -16746,12 +16754,18 @@ function getExtensions(element, context) {
|
|
|
16746
16754
|
);
|
|
16747
16755
|
if (loopExtension?.outputCollection) result.loop = new LoopCharacteristics(loopExtension);
|
|
16748
16756
|
|
|
16749
|
-
// Nothing zeebe-flavoured and nothing to format
|
|
16757
|
+
// Nothing zeebe-flavoured and nothing to format (documentation, a process-level timer start
|
|
16758
|
+
// event's `scheduledStart`) — the element needs no extension. A call
|
|
16750
16759
|
// activity is never inert: its output unwrap/merge is type-driven (the standard BPMN
|
|
16751
16760
|
// `calledElement` attribute needs no zeebe elements). Ignored for processes — a called
|
|
16752
16761
|
// process always needs its inbound input promoted, whatever it carries itself.
|
|
16753
16762
|
result.isEmpty =
|
|
16754
|
-
!foundZeebe &&
|
|
16763
|
+
!foundZeebe &&
|
|
16764
|
+
!result.subscription &&
|
|
16765
|
+
!loopExtension &&
|
|
16766
|
+
!element.behaviour.documentation &&
|
|
16767
|
+
!(element.behaviour.scheduledStart && element.parent?.type === 'bpmn:Process') &&
|
|
16768
|
+
element.type !== 'bpmn:CallActivity';
|
|
16755
16769
|
|
|
16756
16770
|
result.format = isProcess
|
|
16757
16771
|
? new FormatProcess(element)
|
|
@@ -17123,6 +17137,50 @@ function getScriptExpression(activity) {
|
|
|
17123
17137
|
return script?.expression;
|
|
17124
17138
|
}
|
|
17125
17139
|
|
|
17140
|
+
/**
|
|
17141
|
+
* bpmn-elements timer event definition that also accepts a **cron** `timeCycle` (Camunda 8
|
|
17142
|
+
* timer start events schedule with cron, e.g. `0 0 * * *`). An ISO 8601 interval is tried
|
|
17143
|
+
* first; on failure the value is parsed as cron and the next run is the expiry.
|
|
17144
|
+
*
|
|
17145
|
+
* Install it via the type resolver so it replaces the bpmn-elements default:
|
|
17146
|
+
* `TypeResolver({ ...elements, TimerEventDefinition })`.
|
|
17147
|
+
*/
|
|
17148
|
+
class TimerEventDefinition extends bpmnElements.TimerEventDefinition {
|
|
17149
|
+
/**
|
|
17150
|
+
* Supported timeCycle formats
|
|
17151
|
+
* @returns {string[]}
|
|
17152
|
+
*/
|
|
17153
|
+
get supports() {
|
|
17154
|
+
return ['cron', 'iso8601'];
|
|
17155
|
+
}
|
|
17156
|
+
/**
|
|
17157
|
+
* @param {import('bpmn-elements').TimerType} timerType
|
|
17158
|
+
* @param {string} value
|
|
17159
|
+
* @returns {import('bpmn-elements').parsedTimer}
|
|
17160
|
+
*/
|
|
17161
|
+
parse(timerType, value) {
|
|
17162
|
+
if (timerType !== 'timeCycle') return super.parse(timerType, value);
|
|
17163
|
+
|
|
17164
|
+
/** @type {any} */
|
|
17165
|
+
let isoError;
|
|
17166
|
+
try {
|
|
17167
|
+
return super.parse(timerType, value);
|
|
17168
|
+
} catch (err) {
|
|
17169
|
+
isoError = err;
|
|
17170
|
+
}
|
|
17171
|
+
|
|
17172
|
+
try {
|
|
17173
|
+
const expireAt = new croner.Cron(value).nextRun();
|
|
17174
|
+
if (!expireAt) throw new RangeError('cron has no next run');
|
|
17175
|
+
return { expireAt, delay: expireAt.getTime() - Date.now() };
|
|
17176
|
+
} catch (/** @type {any} */ err) {
|
|
17177
|
+
this.logger.error(`<${this.activity?.id}> failed to parse timeCycle: ${isoError.message}`);
|
|
17178
|
+
this.logger.error(`<${this.activity?.id}> failed to parse timeCycle as cron: ${err.message}`);
|
|
17179
|
+
throw new RangeError(`Failed to parse timeCycle <${value?.substring(0, 255)}> as ISO 8601 interval or cron`, { cause: err });
|
|
17180
|
+
}
|
|
17181
|
+
}
|
|
17182
|
+
}
|
|
17183
|
+
|
|
17126
17184
|
/**
|
|
17127
17185
|
* A flow extension activated by bpmn-elements around an element's run.
|
|
17128
17186
|
* @typedef {object} FlowExtension
|
|
@@ -17166,10 +17224,17 @@ function extensions(element, context) {
|
|
|
17166
17224
|
*
|
|
17167
17225
|
* Lifts extension data onto the places bpmn-elements expects to find it on the element
|
|
17168
17226
|
* behaviour: the call activity's called process id (`zeebe:calledElement`) and the multi-instance
|
|
17169
|
-
* input collection/element (`zeebe:loopCharacteristics`).
|
|
17227
|
+
* input collection/element (`zeebe:loopCharacteristics`). A timer start event's `timeCycle`
|
|
17228
|
+
* (ISO 8601 or cron) is lifted as `scheduledStart`, so a scheduler can find it without running
|
|
17229
|
+
* the flow.
|
|
17170
17230
|
* @param {any} behaviour
|
|
17171
17231
|
*/
|
|
17172
17232
|
function extendFn(behaviour) {
|
|
17233
|
+
if (behaviour.$type === 'bpmn:StartEvent' && Array.isArray(behaviour.eventDefinitions)) {
|
|
17234
|
+
const timer = behaviour.eventDefinitions.find((ed) => ed?.type === 'bpmn:TimerEventDefinition' && ed.behaviour?.timeCycle);
|
|
17235
|
+
if (timer) behaviour.scheduledStart = timer.behaviour.timeCycle;
|
|
17236
|
+
}
|
|
17237
|
+
|
|
17173
17238
|
const values = behaviour.extensionElements?.values;
|
|
17174
17239
|
if (Array.isArray(values)) {
|
|
17175
17240
|
for (const ext of values) {
|
|
@@ -17197,6 +17262,7 @@ exports.JobService = JobService;
|
|
|
17197
17262
|
exports.ProcessExtensions = ProcessExtensions;
|
|
17198
17263
|
exports.ServiceError = ServiceError;
|
|
17199
17264
|
exports.SubProcessExtensions = SubProcessExtensions;
|
|
17265
|
+
exports.TimerEventDefinition = TimerEventDefinition;
|
|
17200
17266
|
exports.evaluateFeel = evaluateFeel;
|
|
17201
17267
|
exports.evaluateFeelUnaryTest = evaluateFeelUnaryTest;
|
|
17202
17268
|
exports.extendFn = extendFn;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@0dep/bpmn-extensions",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
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",
|
|
@@ -22,8 +22,10 @@
|
|
|
22
22
|
"test:lcov": "c8 -r lcov mocha && npm run lint",
|
|
23
23
|
"test:md": "texample",
|
|
24
24
|
"cov:html": "c8 mocha && c8 report --reporter html",
|
|
25
|
-
"posttest": "npm run lint && npm run test:md && npm run prepack",
|
|
25
|
+
"posttest": "npm run toc && npm run lint && npm run test:md && npm run prepack",
|
|
26
26
|
"lint": "eslint . --cache && prettier . --check --cache",
|
|
27
|
+
"toc": "toc README.md",
|
|
28
|
+
"posttoc": "prettier --write README.md",
|
|
27
29
|
"format": "eslint . --fix && prettier . --write",
|
|
28
30
|
"dist": "rollup -c",
|
|
29
31
|
"types": "dts-buddy types/index.d.ts -m @0dep/bpmn-extensions:src/index.js",
|
|
@@ -51,7 +53,8 @@
|
|
|
51
53
|
"access": "public"
|
|
52
54
|
},
|
|
53
55
|
"peerDependencies": {
|
|
54
|
-
"bpmn-elements": ">=18.0.
|
|
56
|
+
"bpmn-elements": ">=18.0.25",
|
|
57
|
+
"croner": ">=9"
|
|
55
58
|
},
|
|
56
59
|
"dependencies": {
|
|
57
60
|
"feelin": "^7.0.1"
|
|
@@ -62,6 +65,7 @@
|
|
|
62
65
|
}
|
|
63
66
|
},
|
|
64
67
|
"devDependencies": {
|
|
68
|
+
"@0dep/toc": "^1.0.1",
|
|
65
69
|
"@eslint/js": "^10.0.1",
|
|
66
70
|
"@rollup/plugin-commonjs": "^29.0.3",
|
|
67
71
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
@@ -72,6 +76,7 @@
|
|
|
72
76
|
"bpmn-moddle": "^10.1.0",
|
|
73
77
|
"c8": "^12.0.0",
|
|
74
78
|
"chai": "^6.2.2",
|
|
79
|
+
"croner": "^10.0.1",
|
|
75
80
|
"debug": "^4.4.3",
|
|
76
81
|
"dts-buddy": "^0.8.2",
|
|
77
82
|
"eslint": "^10.6.0",
|
|
@@ -83,7 +88,7 @@
|
|
|
83
88
|
"rollup": "^4.62.2",
|
|
84
89
|
"texample": "^1.0.2",
|
|
85
90
|
"typescript": "^6.0.3",
|
|
86
|
-
"zeebe-bpmn-moddle": "^
|
|
91
|
+
"zeebe-bpmn-moddle": "^2.0.0"
|
|
87
92
|
},
|
|
88
93
|
"files": [
|
|
89
94
|
"src",
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Cron } from 'croner';
|
|
2
|
+
import { TimerEventDefinition as BaseTimerEventDefinition } from 'bpmn-elements';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* bpmn-elements timer event definition that also accepts a **cron** `timeCycle` (Camunda 8
|
|
6
|
+
* timer start events schedule with cron, e.g. `0 0 * * *`). An ISO 8601 interval is tried
|
|
7
|
+
* first; on failure the value is parsed as cron and the next run is the expiry.
|
|
8
|
+
*
|
|
9
|
+
* Install it via the type resolver so it replaces the bpmn-elements default:
|
|
10
|
+
* `TypeResolver({ ...elements, TimerEventDefinition })`.
|
|
11
|
+
*/
|
|
12
|
+
export class TimerEventDefinition extends BaseTimerEventDefinition {
|
|
13
|
+
/**
|
|
14
|
+
* Supported timeCycle formats
|
|
15
|
+
* @returns {string[]}
|
|
16
|
+
*/
|
|
17
|
+
get supports() {
|
|
18
|
+
return ['cron', 'iso8601'];
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* @param {import('bpmn-elements').TimerType} timerType
|
|
22
|
+
* @param {string} value
|
|
23
|
+
* @returns {import('bpmn-elements').parsedTimer}
|
|
24
|
+
*/
|
|
25
|
+
parse(timerType, value) {
|
|
26
|
+
if (timerType !== 'timeCycle') return super.parse(timerType, value);
|
|
27
|
+
|
|
28
|
+
/** @type {any} */
|
|
29
|
+
let isoError;
|
|
30
|
+
try {
|
|
31
|
+
return super.parse(timerType, value);
|
|
32
|
+
} catch (err) {
|
|
33
|
+
isoError = err;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const expireAt = new Cron(value).nextRun();
|
|
38
|
+
if (!expireAt) throw new RangeError('cron has no next run');
|
|
39
|
+
return { expireAt, delay: expireAt.getTime() - Date.now() };
|
|
40
|
+
} catch (/** @type {any} */ err) {
|
|
41
|
+
this.logger.error(`<${this.activity?.id}> failed to parse timeCycle: ${isoError.message}`);
|
|
42
|
+
this.logger.error(`<${this.activity?.id}> failed to parse timeCycle as cron: ${err.message}`);
|
|
43
|
+
throw new RangeError(`Failed to parse timeCycle <${value?.substring(0, 255)}> as ISO 8601 interval or cron`, { cause: err });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { resolveValue, getFeelScope } from '../feel.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Format an activity on enter from its behaviour and extensions: documentation
|
|
5
|
-
* for user tasks, the `zeebe:assignmentDefinition` (assignee, candidate users/groups),
|
|
4
|
+
* Format an activity on enter from its behaviour and extensions: documentation, a top-level
|
|
5
|
+
* timer start event's `scheduledStart` (lifted by `extendFn`) and, for user tasks, the `zeebe:assignmentDefinition` (assignee, candidate users/groups),
|
|
6
6
|
* `zeebe:priorityDefinition` (priority), and `zeebe:taskSchedule` (due/follow-up date).
|
|
7
7
|
*/
|
|
8
8
|
export class FormatActivity {
|
|
@@ -31,6 +31,11 @@ export class FormatActivity {
|
|
|
31
31
|
if (text) result.description = /** @type {string} */ (resolveValue(text, scope));
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
// A timer start event's cycle is only a schedule when it starts the process itself — a
|
|
35
|
+
// sub-process start event runs whenever its parent does.
|
|
36
|
+
const scheduledStart = this.activity.behaviour.scheduledStart;
|
|
37
|
+
if (scheduledStart && this.activity.parent?.type === 'bpmn:Process') result.scheduledStart = scheduledStart;
|
|
38
|
+
|
|
34
39
|
const assignment = this.assignmentDefinition;
|
|
35
40
|
if (assignment) {
|
|
36
41
|
const { assignee, candidateUsers, candidateGroups } = assignment;
|
package/src/getExtensions.js
CHANGED
|
@@ -104,12 +104,18 @@ export function getExtensions(element, context) {
|
|
|
104
104
|
);
|
|
105
105
|
if (loopExtension?.outputCollection) result.loop = new LoopCharacteristics(loopExtension);
|
|
106
106
|
|
|
107
|
-
// Nothing zeebe-flavoured and nothing to format
|
|
107
|
+
// Nothing zeebe-flavoured and nothing to format (documentation, a process-level timer start
|
|
108
|
+
// event's `scheduledStart`) — the element needs no extension. A call
|
|
108
109
|
// activity is never inert: its output unwrap/merge is type-driven (the standard BPMN
|
|
109
110
|
// `calledElement` attribute needs no zeebe elements). Ignored for processes — a called
|
|
110
111
|
// process always needs its inbound input promoted, whatever it carries itself.
|
|
111
112
|
result.isEmpty =
|
|
112
|
-
!foundZeebe &&
|
|
113
|
+
!foundZeebe &&
|
|
114
|
+
!result.subscription &&
|
|
115
|
+
!loopExtension &&
|
|
116
|
+
!element.behaviour.documentation &&
|
|
117
|
+
!(element.behaviour.scheduledStart && element.parent?.type === 'bpmn:Process') &&
|
|
118
|
+
element.type !== 'bpmn:CallActivity';
|
|
113
119
|
|
|
114
120
|
result.format = isProcess
|
|
115
121
|
? new FormatProcess(element)
|
package/src/index.js
CHANGED
|
@@ -5,6 +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 { TimerEventDefinition } from './TimerEventDefinition.js';
|
|
8
9
|
export { isFeelExpression, stripFeel, evaluateFeel, evaluateFeelUnaryTest, resolveValue, getFeelScope } from './feel.js';
|
|
9
10
|
export { JobService } from './extensions/TaskDefinition.js';
|
|
10
11
|
export { ServiceError, FormatError } from './Errors.js';
|
|
@@ -52,10 +53,17 @@ export function extensions(element, context) {
|
|
|
52
53
|
*
|
|
53
54
|
* Lifts extension data onto the places bpmn-elements expects to find it on the element
|
|
54
55
|
* behaviour: the call activity's called process id (`zeebe:calledElement`) and the multi-instance
|
|
55
|
-
* input collection/element (`zeebe:loopCharacteristics`).
|
|
56
|
+
* input collection/element (`zeebe:loopCharacteristics`). A timer start event's `timeCycle`
|
|
57
|
+
* (ISO 8601 or cron) is lifted as `scheduledStart`, so a scheduler can find it without running
|
|
58
|
+
* the flow.
|
|
56
59
|
* @param {any} behaviour
|
|
57
60
|
*/
|
|
58
61
|
export function extendFn(behaviour) {
|
|
62
|
+
if (behaviour.$type === 'bpmn:StartEvent' && Array.isArray(behaviour.eventDefinitions)) {
|
|
63
|
+
const timer = behaviour.eventDefinitions.find((ed) => ed?.type === 'bpmn:TimerEventDefinition' && ed.behaviour?.timeCycle);
|
|
64
|
+
if (timer) behaviour.scheduledStart = timer.behaviour.timeCycle;
|
|
65
|
+
}
|
|
66
|
+
|
|
59
67
|
const values = behaviour.extensionElements?.values;
|
|
60
68
|
if (Array.isArray(values)) {
|
|
61
69
|
for (const ext of values) {
|
package/types/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
declare module '@0dep/bpmn-extensions' {
|
|
2
|
+
import type { TimerEventDefinition as BaseTimerEventDefinition } from 'bpmn-elements';
|
|
2
3
|
/**
|
|
3
4
|
* A flow extension activated by bpmn-elements around an element's run.
|
|
4
5
|
* */
|
|
@@ -15,7 +16,9 @@ declare module '@0dep/bpmn-extensions' {
|
|
|
15
16
|
*
|
|
16
17
|
* Lifts extension data onto the places bpmn-elements expects to find it on the element
|
|
17
18
|
* behaviour: the call activity's called process id (`zeebe:calledElement`) and the multi-instance
|
|
18
|
-
* input collection/element (`zeebe:loopCharacteristics`).
|
|
19
|
+
* input collection/element (`zeebe:loopCharacteristics`). A timer start event's `timeCycle`
|
|
20
|
+
* (ISO 8601 or cron) is lifted as `scheduledStart`, so a scheduler can find it without running
|
|
21
|
+
* the flow.
|
|
19
22
|
* */
|
|
20
23
|
export function extendFn(behaviour: any): void;
|
|
21
24
|
/**
|
|
@@ -48,6 +51,20 @@ declare module '@0dep/bpmn-extensions' {
|
|
|
48
51
|
*
|
|
49
52
|
* */
|
|
50
53
|
export function FeelScripts(): import("bpmn-elements").IScripts;
|
|
54
|
+
/**
|
|
55
|
+
* bpmn-elements timer event definition that also accepts a **cron** `timeCycle` (Camunda 8
|
|
56
|
+
* timer start events schedule with cron, e.g. `0 0 * * *`). An ISO 8601 interval is tried
|
|
57
|
+
* first; on failure the value is parsed as cron and the next run is the expiry.
|
|
58
|
+
*
|
|
59
|
+
* Install it via the type resolver so it replaces the bpmn-elements default:
|
|
60
|
+
* `TypeResolver({ ...elements, TimerEventDefinition })`.
|
|
61
|
+
*/
|
|
62
|
+
export class TimerEventDefinition extends BaseTimerEventDefinition {
|
|
63
|
+
/**
|
|
64
|
+
* Supported timeCycle formats
|
|
65
|
+
* */
|
|
66
|
+
get supports(): string[];
|
|
67
|
+
}
|
|
51
68
|
/**
|
|
52
69
|
* `zeebe:taskDefinition`.
|
|
53
70
|
*
|
|
@@ -220,8 +237,8 @@ declare module '@0dep/bpmn-extensions' {
|
|
|
220
237
|
isEmpty?: boolean | undefined;
|
|
221
238
|
};
|
|
222
239
|
/**
|
|
223
|
-
* Format an activity on enter from its behaviour and extensions: documentation
|
|
224
|
-
* for user tasks, the `zeebe:assignmentDefinition` (assignee, candidate users/groups),
|
|
240
|
+
* Format an activity on enter from its behaviour and extensions: documentation, a top-level
|
|
241
|
+
* timer start event's `scheduledStart` (lifted by `extendFn`) and, for user tasks, the `zeebe:assignmentDefinition` (assignee, candidate users/groups),
|
|
225
242
|
* `zeebe:priorityDefinition` (priority), and `zeebe:taskSchedule` (due/follow-up date).
|
|
226
243
|
*/
|
|
227
244
|
class FormatActivity {
|
|
@@ -234,6 +251,7 @@ declare module '@0dep/bpmn-extensions' {
|
|
|
234
251
|
|
|
235
252
|
resolve(elementApi: import("bpmn-elements").IApi<import("bpmn-elements").Activity>): {
|
|
236
253
|
description: string;
|
|
254
|
+
scheduledStart: any;
|
|
237
255
|
assignee: any;
|
|
238
256
|
candidateUsers: string[];
|
|
239
257
|
candidateGroups: string[];
|
package/types/index.d.ts.map
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
"extendFn",
|
|
7
7
|
"FeelExpressions",
|
|
8
8
|
"FeelScripts",
|
|
9
|
+
"TimerEventDefinition",
|
|
9
10
|
"JobService",
|
|
10
11
|
"ElementExtensions",
|
|
11
12
|
"ProcessExtensions",
|
|
@@ -32,6 +33,7 @@
|
|
|
32
33
|
"../src/index.js",
|
|
33
34
|
"../src/Expressions.js",
|
|
34
35
|
"../src/extensions/FeelScripts.js",
|
|
36
|
+
"../src/TimerEventDefinition.js",
|
|
35
37
|
"../src/extensions/TaskDefinition.js",
|
|
36
38
|
"../src/ElementExtensions.js",
|
|
37
39
|
"../src/ProcessExtensions.js",
|
|
@@ -64,8 +66,9 @@
|
|
|
64
66
|
null,
|
|
65
67
|
null,
|
|
66
68
|
null,
|
|
69
|
+
null,
|
|
67
70
|
null
|
|
68
71
|
],
|
|
69
|
-
"mappings": "
|
|
72
|
+
"mappings": ";;;;;;;;;;;;iBA6BgBA,UAAUA;;;;;;;;;;iBA+BVC,QAAQA;;;;;;;;;;;;;;;;iBCjDRC,eAAeA;;;;;;;;;;;;;;iBCEfC,WAAWA;;;;;;;;;cCFdC,oBAAoBA;;;;;;;;;;;;;;;;;;;;iBCMjBC,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;;;;;;;;;;;;;;;;;;;;;;;OAgEdC,aAAaA;;;;;;;;;;;;;;;;;;;;OC1DbC,SAASA;;;;;;;;;;;;;;;;;;;;;;;OCPTC,WAAWA;;;;;;;;;;;OCEXC,UAAUA;;;;;;;;;;;;;;;OCIVC,kBAAkBA;;;;;;;;;;;;;;;;;;;OCFlBC,IAAIA;;;;;;;;;;;;;;;;;;;;;;OCGJC,mBAAmBA;;;;;;;;;;;;;;;;;;;OCHnBC,YAAYA",
|
|
70
73
|
"ignoreList": []
|
|
71
74
|
}
|