bpmn-elements 9.1.3 → 10.0.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/CHANGELOG.md +11 -0
- package/README.md +4 -0
- package/dist/Environment.js +1 -1
- package/dist/Timers.js +63 -43
- package/dist/activity/Activity.js +4 -17
- package/dist/eventDefinitions/TimerEventDefinition.js +51 -41
- package/dist/flows/SequenceFlow.js +11 -1
- package/dist/index.js +12 -0
- package/dist/iso-duration.js +88 -0
- package/package.json +6 -7
- package/src/Environment.js +1 -1
- package/src/Timers.js +71 -40
- package/src/activity/Activity.js +3 -11
- package/src/eventDefinitions/TimerEventDefinition.js +49 -40
- package/src/flows/SequenceFlow.js +14 -1
- package/src/index.js +4 -0
- package/src/iso-duration.js +91 -0
- package/types/index.d.ts +105 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
Changelog
|
|
2
2
|
=========
|
|
3
3
|
|
|
4
|
+
# 10.0.0
|
|
5
|
+
|
|
6
|
+
- drop iso8601-duration dependency and copy source (with licence). Export as `ISODuration`. Extend with repeat pattern parsing, e.g. `R3/PT1H` that corresponds to three repetitions every one hour
|
|
7
|
+
- expose `TimerEventDefinition.parse(timerType, value)` function for extension purposes
|
|
8
|
+
- prototype and export built-in `Timers`
|
|
9
|
+
|
|
10
|
+
# 9.2.0
|
|
11
|
+
|
|
12
|
+
- move outbound sequence flow evaluation logic from activity to sequence flow, where it belongs
|
|
13
|
+
- spread sequence flow evaluation result, if object, to sequence flow take message
|
|
14
|
+
|
|
4
15
|
# 9.1.3
|
|
5
16
|
|
|
6
17
|
- type declare execution scope
|
package/README.md
CHANGED
|
@@ -77,3 +77,7 @@ The following elements are tested and supported.
|
|
|
77
77
|
- Transaction
|
|
78
78
|
|
|
79
79
|
All activities share the same [base](/docs/Activity.md) and and [api](/docs/SharedApi.md).
|
|
80
|
+
|
|
81
|
+
# Acknowledgments
|
|
82
|
+
|
|
83
|
+
ISO 8601 duration parser [iso8601-duration](https://www.npmjs.com/package/iso8601-duration) source is copied and extended with repeat pattern. License [MIT @ tolu](https://tolu.mit-license.org/)
|
package/dist/Environment.js
CHANGED
|
@@ -17,7 +17,7 @@ function Environment(options = {}) {
|
|
|
17
17
|
this.extensions = options.extensions;
|
|
18
18
|
this.output = options.output || {};
|
|
19
19
|
this.scripts = options.scripts || (0, _Scripts.Scripts)();
|
|
20
|
-
this.timers = options.timers ||
|
|
20
|
+
this.timers = options.timers || new _Timers.Timers();
|
|
21
21
|
this.settings = {
|
|
22
22
|
...options.settings
|
|
23
23
|
};
|
package/dist/Timers.js
CHANGED
|
@@ -4,57 +4,77 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.Timers = Timers;
|
|
7
|
+
const kExecuting = Symbol.for('executing');
|
|
8
|
+
const kTimerApi = Symbol.for('timers api');
|
|
9
|
+
const MAX_DELAY = 2147483647;
|
|
7
10
|
function Timers(options) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
options = {
|
|
11
|
+
this.count = 0;
|
|
12
|
+
this.options = {
|
|
11
13
|
setTimeout,
|
|
12
14
|
clearTimeout,
|
|
13
15
|
...options
|
|
14
16
|
};
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
};
|
|
23
|
-
return timersApi;
|
|
24
|
-
function register(owner) {
|
|
25
|
-
return {
|
|
26
|
-
setTimeout: registerTimeout(owner),
|
|
27
|
-
clearTimeout: timersApi.clearTimeout
|
|
28
|
-
};
|
|
17
|
+
this[kExecuting] = [];
|
|
18
|
+
this.setTimeout = this.setTimeout.bind(this);
|
|
19
|
+
this.clearTimeout = this.clearTimeout.bind(this);
|
|
20
|
+
}
|
|
21
|
+
Object.defineProperty(Timers.prototype, 'executing', {
|
|
22
|
+
get() {
|
|
23
|
+
return this[kExecuting].slice();
|
|
29
24
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
25
|
+
});
|
|
26
|
+
Timers.prototype.register = function register(owner) {
|
|
27
|
+
return new RegisteredTimers(this, owner);
|
|
28
|
+
};
|
|
29
|
+
Timers.prototype.setTimeout = function wrappedSetTimeout(callback, delay, ...args) {
|
|
30
|
+
return this._setTimeout(null, callback, delay, ...args);
|
|
31
|
+
};
|
|
32
|
+
Timers.prototype.clearTimeout = function wrappedClearTimeout(ref) {
|
|
33
|
+
const executing = this[kExecuting];
|
|
34
|
+
const idx = executing.indexOf(ref);
|
|
35
|
+
if (idx > -1) {
|
|
36
|
+
executing.splice(idx, 1);
|
|
37
|
+
ref.timerRef = this.options.clearTimeout(ref.timerRef);
|
|
38
|
+
return;
|
|
34
39
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
executing.push(ref);
|
|
44
|
-
ref.timerRef = options.setTimeout.call(null, onTimeout, delay, ...args);
|
|
45
|
-
return ref;
|
|
46
|
-
function onTimeout(...rargs) {
|
|
47
|
-
const idx = executing.indexOf(ref);
|
|
48
|
-
if (idx > -1) executing.splice(idx, 1);
|
|
49
|
-
return callback(...rargs);
|
|
50
|
-
}
|
|
40
|
+
return this.options.clearTimeout(ref);
|
|
41
|
+
};
|
|
42
|
+
Timers.prototype._setTimeout = function setTimeout(owner, callback, delay, ...args) {
|
|
43
|
+
const executing = this[kExecuting];
|
|
44
|
+
const ref = this._getReference(owner, callback, delay, args);
|
|
45
|
+
executing.push(ref);
|
|
46
|
+
if (delay < MAX_DELAY) {
|
|
47
|
+
ref.timerRef = this.options.setTimeout(onTimeout, ref.delay, ...ref.args);
|
|
51
48
|
}
|
|
52
|
-
|
|
49
|
+
return ref;
|
|
50
|
+
function onTimeout(...rargs) {
|
|
53
51
|
const idx = executing.indexOf(ref);
|
|
54
|
-
if (idx > -1)
|
|
55
|
-
|
|
56
|
-
return options.clearTimeout.call(null, ref.timerRef);
|
|
57
|
-
}
|
|
58
|
-
return options.clearTimeout.call(null, ref);
|
|
52
|
+
if (idx > -1) executing.splice(idx, 1);
|
|
53
|
+
return callback(...rargs);
|
|
59
54
|
}
|
|
55
|
+
};
|
|
56
|
+
Timers.prototype._getReference = function getReference(owner, callback, delay, args) {
|
|
57
|
+
return new Timer(owner, `timer_${this.count++}`, callback, delay, args);
|
|
58
|
+
};
|
|
59
|
+
function RegisteredTimers(timersApi, owner) {
|
|
60
|
+
this[kTimerApi] = timersApi;
|
|
61
|
+
this.owner = owner;
|
|
62
|
+
this.setTimeout = this.setTimeout.bind(this);
|
|
63
|
+
this.clearTimeout = this.clearTimeout.bind(this);
|
|
64
|
+
}
|
|
65
|
+
RegisteredTimers.prototype.setTimeout = function registeredSetTimeout(callback, delay, ...args) {
|
|
66
|
+
const timersApi = this[kTimerApi];
|
|
67
|
+
return timersApi._setTimeout(this.owner, callback, delay, ...args);
|
|
68
|
+
};
|
|
69
|
+
RegisteredTimers.prototype.clearTimeout = function registeredClearTimeout(ref) {
|
|
70
|
+
this[kTimerApi].clearTimeout(ref);
|
|
71
|
+
};
|
|
72
|
+
function Timer(owner, timerId, callback, delay, args) {
|
|
73
|
+
this.callback = callback;
|
|
74
|
+
this.delay = delay;
|
|
75
|
+
this.args = args;
|
|
76
|
+
this.owner = owner;
|
|
77
|
+
this.timerId = timerId;
|
|
78
|
+
this.expireAt = new Date(Date.now() + delay);
|
|
79
|
+
this.timerRef = null;
|
|
60
80
|
}
|
|
@@ -837,10 +837,12 @@ Activity.prototype._doRunOutbound = function doRunOutbound(outboundList, content
|
|
|
837
837
|
for (const outboundFlow of outboundList) {
|
|
838
838
|
const {
|
|
839
839
|
id: flowId,
|
|
840
|
-
action
|
|
840
|
+
action,
|
|
841
|
+
result
|
|
841
842
|
} = outboundFlow;
|
|
842
843
|
this.broker.publish('run', 'run.outbound.' + action, (0, _messageHelper.cloneContent)(content, {
|
|
843
844
|
flow: {
|
|
845
|
+
...(result && typeof result === 'object' && result),
|
|
844
846
|
...outboundFlow,
|
|
845
847
|
sequenceId: (0, _shared.getUniqueId)(`${flowId}_${action}`),
|
|
846
848
|
...(discardSequence && {
|
|
@@ -1027,26 +1029,11 @@ OutboundEvaluator.prototype.onEvaluated = function onEvaluated(routingKey, messa
|
|
|
1027
1029
|
};
|
|
1028
1030
|
OutboundEvaluator.prototype.evaluateFlow = function evaluateFlow(flow) {
|
|
1029
1031
|
const broker = this.broker;
|
|
1030
|
-
if (flow.isDefault) {
|
|
1031
|
-
return broker.publish('execution', 'evaluate.flow.take', formatFlowAction(flow, {
|
|
1032
|
-
action: 'take'
|
|
1033
|
-
}), {
|
|
1034
|
-
persistent: false
|
|
1035
|
-
});
|
|
1036
|
-
}
|
|
1037
|
-
const flowCondition = flow.getCondition();
|
|
1038
|
-
if (!flowCondition) {
|
|
1039
|
-
return broker.publish('execution', 'evaluate.flow.take', formatFlowAction(flow, {
|
|
1040
|
-
action: 'take'
|
|
1041
|
-
}), {
|
|
1042
|
-
persistent: false
|
|
1043
|
-
});
|
|
1044
|
-
}
|
|
1045
1032
|
const {
|
|
1046
1033
|
fromMessage,
|
|
1047
1034
|
evaluationId
|
|
1048
1035
|
} = this.evaluateArgs;
|
|
1049
|
-
|
|
1036
|
+
flow.evaluate((0, _messageHelper.cloneMessage)(fromMessage), (err, result) => {
|
|
1050
1037
|
if (err) return this.completed(err);
|
|
1051
1038
|
const action = result ? 'take' : 'discard';
|
|
1052
1039
|
return broker.publish('execution', 'evaluate.flow.' + action, formatFlowAction(flow, {
|
|
@@ -5,13 +5,12 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.default = TimerEventDefinition;
|
|
7
7
|
var _messageHelper = require("../messageHelper.js");
|
|
8
|
-
var
|
|
8
|
+
var _isoDuration = require("../iso-duration.js");
|
|
9
9
|
const kStopped = Symbol.for('stopped');
|
|
10
10
|
const kTimerContent = Symbol.for('timerContent');
|
|
11
11
|
const kTimer = Symbol.for('timer');
|
|
12
|
-
const repeatPattern = /^\s*R(\d+)\//;
|
|
13
12
|
function TimerEventDefinition(activity, eventDefinition) {
|
|
14
|
-
const type = this.type = eventDefinition.type || 'TimerEventDefinition
|
|
13
|
+
const type = this.type = eventDefinition.type || 'TimerEventDefinition';
|
|
15
14
|
this.activity = activity;
|
|
16
15
|
const environment = this.environment = activity.environment;
|
|
17
16
|
this.eventDefinition = eventDefinition;
|
|
@@ -85,12 +84,14 @@ TimerEventDefinition.prototype.execute = function execute(executeMessage) {
|
|
|
85
84
|
if (timerContent.timeout === undefined) return this._debug(`waiting for ${timerContent.timerType || 'signal'}`);
|
|
86
85
|
if (timerContent.timeout <= 0) return this._completed();
|
|
87
86
|
const timers = this.environment.timers.register(timerContent);
|
|
88
|
-
|
|
87
|
+
const delay = timerContent.timeout;
|
|
88
|
+
this[kTimer] = timers.setTimeout(this._completed.bind(this), delay, {
|
|
89
89
|
id: content.id,
|
|
90
90
|
type: this.type,
|
|
91
91
|
executionId,
|
|
92
92
|
state: 'timeout'
|
|
93
93
|
});
|
|
94
|
+
this._debug(`set timeout with delay ${delay}`);
|
|
94
95
|
};
|
|
95
96
|
TimerEventDefinition.prototype.stop = function stopTimer() {
|
|
96
97
|
const timer = this[kTimer];
|
|
@@ -188,75 +189,84 @@ TimerEventDefinition.prototype._stop = function stop() {
|
|
|
188
189
|
broker.cancel(`_api-${this.executionId}`);
|
|
189
190
|
broker.cancel(`_api-delegated-${this.executionId}`);
|
|
190
191
|
};
|
|
192
|
+
TimerEventDefinition.prototype.parse = function parse(timerType, value) {
|
|
193
|
+
let repeat, delay, expireAt;
|
|
194
|
+
switch (timerType) {
|
|
195
|
+
case 'timeCycle':
|
|
196
|
+
case 'timeDuration':
|
|
197
|
+
{
|
|
198
|
+
const parsed = (0, _isoDuration.parse)(value);
|
|
199
|
+
if (parsed.repeat) repeat = parsed.repeat;
|
|
200
|
+
delay = (0, _isoDuration.toSeconds)(parsed) * 1000;
|
|
201
|
+
expireAt = new Date(Date.now() + delay);
|
|
202
|
+
break;
|
|
203
|
+
}
|
|
204
|
+
case 'timeDate':
|
|
205
|
+
{
|
|
206
|
+
const ms = Date.parse(value);
|
|
207
|
+
if (!isNaN(ms)) {
|
|
208
|
+
expireAt = new Date(ms);
|
|
209
|
+
delay = Date.now() - expireAt;
|
|
210
|
+
} else {
|
|
211
|
+
throw new TypeError(`invalid timeDate >${value}<`);
|
|
212
|
+
}
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return {
|
|
217
|
+
expireAt,
|
|
218
|
+
repeat,
|
|
219
|
+
delay
|
|
220
|
+
};
|
|
221
|
+
};
|
|
191
222
|
TimerEventDefinition.prototype._getTimers = function getTimers(executeMessage) {
|
|
192
223
|
const content = executeMessage.content;
|
|
193
|
-
const now = Date.now();
|
|
194
224
|
const result = {
|
|
195
225
|
...('expireAt' in content && {
|
|
196
226
|
expireAt: new Date(content.expireAt)
|
|
197
227
|
})
|
|
198
228
|
};
|
|
229
|
+
let parseErr;
|
|
199
230
|
for (const t of ['timeDuration', 'timeDate', 'timeCycle']) {
|
|
200
231
|
if (t in content) result[t] = content[t];else if (t in this) result[t] = this.environment.resolveExpression(this[t], executeMessage);else continue;
|
|
201
232
|
let expireAtDate, repeat;
|
|
202
233
|
const timerStr = result[t];
|
|
203
234
|
if (timerStr) {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
if (delay !== undefined) expireAtDate = new Date(now + delay);
|
|
214
|
-
break;
|
|
215
|
-
}
|
|
216
|
-
case 'timeDate':
|
|
217
|
-
{
|
|
218
|
-
const dateStr = result[t];
|
|
219
|
-
const ms = Date.parse(dateStr);
|
|
220
|
-
if (!isNaN(ms)) {
|
|
221
|
-
expireAtDate = new Date(ms);
|
|
222
|
-
} else {
|
|
223
|
-
this._warn(`invalid timeDate >${dateStr}<`);
|
|
224
|
-
}
|
|
225
|
-
break;
|
|
226
|
-
}
|
|
235
|
+
try {
|
|
236
|
+
const {
|
|
237
|
+
repeat: parsedRepeat,
|
|
238
|
+
expireAt: parsedExpireAt
|
|
239
|
+
} = this.parse(t, timerStr);
|
|
240
|
+
repeat = parsedRepeat;
|
|
241
|
+
expireAtDate = parsedExpireAt;
|
|
242
|
+
} catch (err) {
|
|
243
|
+
parseErr = err;
|
|
227
244
|
}
|
|
228
245
|
} else {
|
|
229
|
-
expireAtDate = new Date(
|
|
246
|
+
expireAtDate = new Date();
|
|
230
247
|
}
|
|
231
248
|
if (!expireAtDate) continue;
|
|
232
249
|
if (!('expireAt' in result) || result.expireAt > expireAtDate) {
|
|
233
250
|
result.timerType = t;
|
|
234
251
|
result.expireAt = expireAtDate;
|
|
235
|
-
|
|
252
|
+
result.repeat = repeat;
|
|
236
253
|
}
|
|
237
254
|
}
|
|
238
255
|
if ('expireAt' in result) {
|
|
239
|
-
result.timeout = result.expireAt - now;
|
|
256
|
+
result.timeout = result.expireAt - Date.now();
|
|
240
257
|
} else if ('timeout' in content) {
|
|
241
258
|
result.timeout = content.timeout;
|
|
242
259
|
} else if (!Object.keys(result).length) {
|
|
243
260
|
result.timeout = 0;
|
|
244
261
|
}
|
|
262
|
+
if (!('timeout' in result) && parseErr) {
|
|
263
|
+
this.logger.warn(`<${this.activity.id}> failed to parse timer: ${parseErr.message}`);
|
|
264
|
+
}
|
|
245
265
|
if (content.inbound && 'repeat' in content.inbound[0]) {
|
|
246
266
|
result.repeat = content.inbound[0].repeat;
|
|
247
267
|
}
|
|
248
268
|
return result;
|
|
249
269
|
};
|
|
250
|
-
TimerEventDefinition.prototype._getDurationInMilliseconds = function getDurationInMilliseconds(duration) {
|
|
251
|
-
try {
|
|
252
|
-
return (0, _iso8601Duration.toSeconds)((0, _iso8601Duration.parse)(duration)) * 1000;
|
|
253
|
-
} catch (err) {
|
|
254
|
-
this._warn(`failed to parse ${this.timerType} >${duration}<: ${err.message}`);
|
|
255
|
-
}
|
|
256
|
-
};
|
|
257
270
|
TimerEventDefinition.prototype._debug = function debug(msg) {
|
|
258
271
|
this.logger.debug(`<${this.executionId} (${this.activity.id})> ${msg}`);
|
|
259
|
-
};
|
|
260
|
-
TimerEventDefinition.prototype._warn = function debug(msg) {
|
|
261
|
-
this.logger.warn(`<${this.executionId} (${this.activity.id})> ${msg}`);
|
|
262
272
|
};
|
|
@@ -124,7 +124,7 @@ SequenceFlow.prototype.shake = function shake(message) {
|
|
|
124
124
|
persistent: false,
|
|
125
125
|
type: 'shake'
|
|
126
126
|
});
|
|
127
|
-
for (const s of message.content.sequence) {
|
|
127
|
+
for (const s of message.content.sequence || []) {
|
|
128
128
|
if (s.id === this.id) return this.broker.publish('event', 'flow.shake.loop', content, {
|
|
129
129
|
persistent: false,
|
|
130
130
|
type: 'shake'
|
|
@@ -164,6 +164,16 @@ SequenceFlow.prototype.createMessage = function createMessage(override) {
|
|
|
164
164
|
parent: (0, _messageHelper.cloneParent)(this.parent)
|
|
165
165
|
};
|
|
166
166
|
};
|
|
167
|
+
SequenceFlow.prototype.evaluate = function evaluate(fromMessage, callback) {
|
|
168
|
+
if (this.isDefault) {
|
|
169
|
+
return callback(null, true);
|
|
170
|
+
}
|
|
171
|
+
const flowCondition = this.getCondition();
|
|
172
|
+
if (!flowCondition) {
|
|
173
|
+
return callback(null, true);
|
|
174
|
+
}
|
|
175
|
+
flowCondition.execute(fromMessage, callback);
|
|
176
|
+
};
|
|
167
177
|
SequenceFlow.prototype._publishEvent = function publishEvent(action, content) {
|
|
168
178
|
const eventContent = this.createMessage({
|
|
169
179
|
action,
|
package/dist/index.js
CHANGED
|
@@ -147,6 +147,7 @@ Object.defineProperty(exports, "Group", {
|
|
|
147
147
|
return _Dummy.default;
|
|
148
148
|
}
|
|
149
149
|
});
|
|
150
|
+
exports.ISODuration = void 0;
|
|
150
151
|
Object.defineProperty(exports, "InclusiveGateway", {
|
|
151
152
|
enumerable: true,
|
|
152
153
|
get: function () {
|
|
@@ -321,6 +322,12 @@ Object.defineProperty(exports, "TimerEventDefinition", {
|
|
|
321
322
|
return _TimerEventDefinition.default;
|
|
322
323
|
}
|
|
323
324
|
});
|
|
325
|
+
Object.defineProperty(exports, "Timers", {
|
|
326
|
+
enumerable: true,
|
|
327
|
+
get: function () {
|
|
328
|
+
return _Timers.Timers;
|
|
329
|
+
}
|
|
330
|
+
});
|
|
324
331
|
Object.defineProperty(exports, "Transaction", {
|
|
325
332
|
enumerable: true,
|
|
326
333
|
get: function () {
|
|
@@ -381,4 +388,9 @@ var _Task = _interopRequireDefault(require("./tasks/Task.js"));
|
|
|
381
388
|
var _TerminateEventDefinition = _interopRequireDefault(require("./eventDefinitions/TerminateEventDefinition.js"));
|
|
382
389
|
var _TimerEventDefinition = _interopRequireDefault(require("./eventDefinitions/TimerEventDefinition.js"));
|
|
383
390
|
var _Transaction = _interopRequireDefault(require("./tasks/Transaction.js"));
|
|
391
|
+
var _Timers = require("./Timers.js");
|
|
392
|
+
var ISODuration = _interopRequireWildcard(require("./iso-duration.js"));
|
|
393
|
+
exports.ISODuration = ISODuration;
|
|
394
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
395
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
384
396
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.end = end;
|
|
7
|
+
exports.parse = parse;
|
|
8
|
+
exports.toSeconds = toSeconds;
|
|
9
|
+
// License MIT @ https://tolu.mit-license.org/
|
|
10
|
+
|
|
11
|
+
const numbers = '\\d+';
|
|
12
|
+
const fractionalNumbers = ''.concat(numbers, '(?:[\\.,]').concat(numbers, ')?');
|
|
13
|
+
const datePattern = '('.concat(numbers, 'Y)?(').concat(numbers, 'M)?(').concat(numbers, 'W)?(').concat(fractionalNumbers, 'D)?');
|
|
14
|
+
const timePattern = 'T('.concat(fractionalNumbers, 'H)?(').concat(fractionalNumbers, 'M)?(').concat(fractionalNumbers, 'S)?');
|
|
15
|
+
const rPattern = '(?:R('.concat(numbers).concat(')/)?');
|
|
16
|
+
const iso8601 = rPattern.concat('P(?:').concat(datePattern, '(?:').concat(timePattern, ')?)');
|
|
17
|
+
const objMap = ['years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds'];
|
|
18
|
+
const defaultDuration = Object.freeze({
|
|
19
|
+
years: 0,
|
|
20
|
+
months: 0,
|
|
21
|
+
weeks: 0,
|
|
22
|
+
days: 0,
|
|
23
|
+
hours: 0,
|
|
24
|
+
minutes: 0,
|
|
25
|
+
seconds: 0
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The ISO8601 regex for matching / testing durations
|
|
30
|
+
*/
|
|
31
|
+
const pattern = new RegExp(iso8601);
|
|
32
|
+
|
|
33
|
+
/** Parse PnYnMnDTnHnMnS format to object */
|
|
34
|
+
function parse(durationString) {
|
|
35
|
+
const matches = durationString.replace(/,/g, '.').match(pattern);
|
|
36
|
+
if (!matches) {
|
|
37
|
+
throw new RangeError('invalid duration: ' + durationString);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Slice away repeat and first entry in match-array (the input string)
|
|
41
|
+
const slicedMatches = matches.slice(2);
|
|
42
|
+
if (slicedMatches.filter(Boolean).length === 0) {
|
|
43
|
+
throw new RangeError('invalid duration: ' + durationString);
|
|
44
|
+
}
|
|
45
|
+
// Check only one fraction is used
|
|
46
|
+
if (slicedMatches.filter(v => {
|
|
47
|
+
return /\./.test(v || '');
|
|
48
|
+
}).length > 1) {
|
|
49
|
+
throw new RangeError('Fractions are allowed on the smallest unit in the string, e.g. P0.5D or PT1.0001S but not PT0.5M0.1S: ' + durationString);
|
|
50
|
+
}
|
|
51
|
+
const result = {};
|
|
52
|
+
if (matches[1]) result.repeat = Number(matches[1]);
|
|
53
|
+
return slicedMatches.reduce((prev, next, idx) => {
|
|
54
|
+
prev[objMap[idx]] = parseFloat(next || '0') || 0;
|
|
55
|
+
return prev;
|
|
56
|
+
}, result);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Convert ISO8601 duration object to an end Date. */
|
|
60
|
+
function end(durationInput, startDate) {
|
|
61
|
+
const duration = Object.assign({}, defaultDuration, durationInput);
|
|
62
|
+
// Create two equal timestamps, add duration to 'then' and return time difference
|
|
63
|
+
const timestamp = startDate.getTime();
|
|
64
|
+
const then = new Date(timestamp);
|
|
65
|
+
then.setFullYear(then.getFullYear() + duration.years);
|
|
66
|
+
then.setMonth(then.getMonth() + duration.months);
|
|
67
|
+
then.setDate(then.getDate() + duration.days);
|
|
68
|
+
// set time as milliseconds to get fractions working for minutes/hours
|
|
69
|
+
const hoursInMs = duration.hours * 3600 * 1000;
|
|
70
|
+
const minutesInMs = duration.minutes * 60 * 1000;
|
|
71
|
+
then.setMilliseconds(then.getMilliseconds() + duration.seconds * 1000 + hoursInMs + minutesInMs);
|
|
72
|
+
// Special case weeks
|
|
73
|
+
then.setDate(then.getDate() + duration.weeks * 7);
|
|
74
|
+
return then;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Convert ISO8601 duration object to seconds */
|
|
78
|
+
function toSeconds(durationInput, startDate) {
|
|
79
|
+
if (startDate === void 0) {
|
|
80
|
+
startDate = new Date();
|
|
81
|
+
}
|
|
82
|
+
const duration = Object.assign({}, defaultDuration, durationInput);
|
|
83
|
+
const timestamp = startDate.getTime();
|
|
84
|
+
const now = new Date(timestamp);
|
|
85
|
+
const then = end(duration, now);
|
|
86
|
+
const seconds = (then.getTime() - now.getTime()) / 1000;
|
|
87
|
+
return seconds;
|
|
88
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bpmn-elements",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "10.0.0",
|
|
4
4
|
"description": "Executable workflow elements based on BPMN 2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -45,9 +45,9 @@
|
|
|
45
45
|
],
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@aircall/expression-parser": "^1.0.4",
|
|
48
|
-
"@babel/cli": "^7.21.
|
|
49
|
-
"@babel/core": "^7.21.
|
|
50
|
-
"@babel/preset-env": "^7.21.
|
|
48
|
+
"@babel/cli": "^7.21.5",
|
|
49
|
+
"@babel/core": "^7.21.8",
|
|
50
|
+
"@babel/preset-env": "^7.21.5",
|
|
51
51
|
"@babel/register": "^7.21.0",
|
|
52
52
|
"bpmn-moddle": "^8.0.1",
|
|
53
53
|
"c8": "^7.13.0",
|
|
@@ -55,16 +55,15 @@
|
|
|
55
55
|
"chai": "^4.3.7",
|
|
56
56
|
"chronokinesis": "^5.0.2",
|
|
57
57
|
"debug": "^4.3.4",
|
|
58
|
-
"eslint": "^8.
|
|
58
|
+
"eslint": "^8.41.0",
|
|
59
59
|
"eslint-plugin-import": "^2.27.5",
|
|
60
60
|
"got": "^12.6.0",
|
|
61
61
|
"mocha": "^10.1.0",
|
|
62
62
|
"mocha-cakes-2": "^3.3.0",
|
|
63
63
|
"moddle-context-serializer": "^3.2.2",
|
|
64
|
-
"nock": "^13.
|
|
64
|
+
"nock": "^13.3.1"
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"iso8601-duration": "^2.1.1",
|
|
68
67
|
"smqp": "^7.1.4"
|
|
69
68
|
}
|
|
70
69
|
}
|
package/src/Environment.js
CHANGED
|
@@ -24,7 +24,7 @@ export default function Environment(options = {}) {
|
|
|
24
24
|
this.extensions = options.extensions;
|
|
25
25
|
this.output = options.output || {};
|
|
26
26
|
this.scripts = options.scripts || IScripts();
|
|
27
|
-
this.timers = options.timers || Timers();
|
|
27
|
+
this.timers = options.timers || new Timers();
|
|
28
28
|
this.settings = {...options.settings};
|
|
29
29
|
this.Logger = options.Logger || DummyLogger;
|
|
30
30
|
this[kServices] = options.services || {};
|
package/src/Timers.js
CHANGED
|
@@ -1,56 +1,87 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
const kExecuting = Symbol.for('executing');
|
|
2
|
+
const kTimerApi = Symbol.for('timers api');
|
|
3
|
+
|
|
4
|
+
const MAX_DELAY = 2147483647;
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
export function Timers(options) {
|
|
7
|
+
this.count = 0;
|
|
8
|
+
this.options = {
|
|
6
9
|
setTimeout,
|
|
7
10
|
clearTimeout,
|
|
8
11
|
...options,
|
|
9
12
|
};
|
|
13
|
+
this[kExecuting] = [];
|
|
14
|
+
this.setTimeout = this.setTimeout.bind(this);
|
|
15
|
+
this.clearTimeout = this.clearTimeout.bind(this);
|
|
16
|
+
}
|
|
10
17
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
setTimeout: wrappedSetTimeout,
|
|
17
|
-
clearTimeout: wrappedClearTimeout,
|
|
18
|
-
};
|
|
18
|
+
Object.defineProperty(Timers.prototype, 'executing', {
|
|
19
|
+
get() {
|
|
20
|
+
return this[kExecuting].slice();
|
|
21
|
+
},
|
|
22
|
+
});
|
|
19
23
|
|
|
20
|
-
|
|
24
|
+
Timers.prototype.register = function register(owner) {
|
|
25
|
+
return new RegisteredTimers(this, owner);
|
|
26
|
+
};
|
|
21
27
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
clearTimeout: timersApi.clearTimeout,
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
+
Timers.prototype.setTimeout = function wrappedSetTimeout(callback, delay, ...args) {
|
|
29
|
+
return this._setTimeout(null, callback, delay, ...args);
|
|
30
|
+
};
|
|
28
31
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
Timers.prototype.clearTimeout = function wrappedClearTimeout(ref) {
|
|
33
|
+
const executing = this[kExecuting];
|
|
34
|
+
const idx = executing.indexOf(ref);
|
|
35
|
+
if (idx > -1) {
|
|
36
|
+
executing.splice(idx, 1);
|
|
37
|
+
ref.timerRef = this.options.clearTimeout(ref.timerRef);
|
|
38
|
+
return;
|
|
33
39
|
}
|
|
40
|
+
return this.options.clearTimeout(ref);
|
|
41
|
+
};
|
|
34
42
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
function onTimeout(...rargs) {
|
|
42
|
-
const idx = executing.indexOf(ref);
|
|
43
|
-
if (idx > -1) executing.splice(idx, 1);
|
|
44
|
-
return callback(...rargs);
|
|
45
|
-
}
|
|
43
|
+
Timers.prototype._setTimeout = function setTimeout(owner, callback, delay, ...args) {
|
|
44
|
+
const executing = this[kExecuting];
|
|
45
|
+
const ref = this._getReference(owner, callback, delay, args);
|
|
46
|
+
executing.push(ref);
|
|
47
|
+
if (delay < MAX_DELAY) {
|
|
48
|
+
ref.timerRef = this.options.setTimeout(onTimeout, ref.delay, ...ref.args);
|
|
46
49
|
}
|
|
50
|
+
return ref;
|
|
47
51
|
|
|
48
|
-
function
|
|
52
|
+
function onTimeout(...rargs) {
|
|
49
53
|
const idx = executing.indexOf(ref);
|
|
50
|
-
if (idx > -1)
|
|
51
|
-
|
|
52
|
-
return options.clearTimeout.call(null, ref.timerRef);
|
|
53
|
-
}
|
|
54
|
-
return options.clearTimeout.call(null, ref);
|
|
54
|
+
if (idx > -1) executing.splice(idx, 1);
|
|
55
|
+
return callback(...rargs);
|
|
55
56
|
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
Timers.prototype._getReference = function getReference(owner, callback, delay, args) {
|
|
60
|
+
return new Timer(owner, `timer_${this.count++}`, callback, delay, args);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
function RegisteredTimers(timersApi, owner) {
|
|
64
|
+
this[kTimerApi] = timersApi;
|
|
65
|
+
this.owner = owner;
|
|
66
|
+
this.setTimeout = this.setTimeout.bind(this);
|
|
67
|
+
this.clearTimeout = this.clearTimeout.bind(this);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
RegisteredTimers.prototype.setTimeout = function registeredSetTimeout(callback, delay, ...args) {
|
|
71
|
+
const timersApi = this[kTimerApi];
|
|
72
|
+
return timersApi._setTimeout(this.owner, callback, delay, ...args);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
RegisteredTimers.prototype.clearTimeout = function registeredClearTimeout(ref) {
|
|
76
|
+
this[kTimerApi].clearTimeout(ref);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
function Timer(owner, timerId, callback, delay, args) {
|
|
80
|
+
this.callback = callback;
|
|
81
|
+
this.delay = delay;
|
|
82
|
+
this.args = args;
|
|
83
|
+
this.owner = owner;
|
|
84
|
+
this.timerId = timerId;
|
|
85
|
+
this.expireAt = new Date(Date.now() + delay);
|
|
86
|
+
this.timerRef = null;
|
|
56
87
|
}
|
package/src/activity/Activity.js
CHANGED
|
@@ -807,9 +807,10 @@ Activity.prototype._doOutbound = function doOutbound(fromMessage, isDiscarded, c
|
|
|
807
807
|
|
|
808
808
|
Activity.prototype._doRunOutbound = function doRunOutbound(outboundList, content, discardSequence) {
|
|
809
809
|
for (const outboundFlow of outboundList) {
|
|
810
|
-
const {id: flowId, action} = outboundFlow;
|
|
810
|
+
const {id: flowId, action, result} = outboundFlow;
|
|
811
811
|
this.broker.publish('run', 'run.outbound.' + action, cloneContent(content, {
|
|
812
812
|
flow: {
|
|
813
|
+
...(result && typeof result === 'object' && result),
|
|
813
814
|
...outboundFlow,
|
|
814
815
|
sequenceId: getUniqueId(`${flowId}_${action}`),
|
|
815
816
|
...(discardSequence && {discardSequence: discardSequence.slice()}),
|
|
@@ -1000,17 +1001,8 @@ OutboundEvaluator.prototype.onEvaluated = function onEvaluated(routingKey, messa
|
|
|
1000
1001
|
|
|
1001
1002
|
OutboundEvaluator.prototype.evaluateFlow = function evaluateFlow(flow) {
|
|
1002
1003
|
const broker = this.broker;
|
|
1003
|
-
if (flow.isDefault) {
|
|
1004
|
-
return broker.publish('execution', 'evaluate.flow.take', formatFlowAction(flow, {action: 'take'}), {persistent: false});
|
|
1005
|
-
}
|
|
1006
|
-
|
|
1007
|
-
const flowCondition = flow.getCondition();
|
|
1008
|
-
if (!flowCondition) {
|
|
1009
|
-
return broker.publish('execution', 'evaluate.flow.take', formatFlowAction(flow, {action: 'take'}), {persistent: false});
|
|
1010
|
-
}
|
|
1011
|
-
|
|
1012
1004
|
const {fromMessage, evaluationId} = this.evaluateArgs;
|
|
1013
|
-
|
|
1005
|
+
flow.evaluate(cloneMessage(fromMessage), (err, result) => {
|
|
1014
1006
|
if (err) return this.completed(err);
|
|
1015
1007
|
const action = result ? 'take' : 'discard';
|
|
1016
1008
|
return broker.publish('execution', 'evaluate.flow.' + action, formatFlowAction(flow, {
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import {cloneContent} from '../messageHelper.js';
|
|
2
|
-
import {toSeconds, parse} from '
|
|
2
|
+
import {toSeconds, parse as parseIsoDuration} from '../iso-duration.js';
|
|
3
3
|
|
|
4
4
|
const kStopped = Symbol.for('stopped');
|
|
5
5
|
const kTimerContent = Symbol.for('timerContent');
|
|
6
6
|
const kTimer = Symbol.for('timer');
|
|
7
|
-
const repeatPattern = /^\s*R(\d+)\//;
|
|
8
7
|
|
|
9
8
|
export default function TimerEventDefinition(activity, eventDefinition) {
|
|
10
|
-
const type = this.type = eventDefinition.type || 'TimerEventDefinition
|
|
9
|
+
const type = this.type = eventDefinition.type || 'TimerEventDefinition';
|
|
11
10
|
this.activity = activity;
|
|
12
11
|
const environment = this.environment = activity.environment;
|
|
13
12
|
this.eventDefinition = eventDefinition;
|
|
@@ -85,12 +84,14 @@ TimerEventDefinition.prototype.execute = function execute(executeMessage) {
|
|
|
85
84
|
if (timerContent.timeout <= 0) return this._completed();
|
|
86
85
|
|
|
87
86
|
const timers = this.environment.timers.register(timerContent);
|
|
88
|
-
|
|
87
|
+
const delay = timerContent.timeout;
|
|
88
|
+
this[kTimer] = timers.setTimeout(this._completed.bind(this), delay, {
|
|
89
89
|
id: content.id,
|
|
90
90
|
type: this.type,
|
|
91
91
|
executionId,
|
|
92
92
|
state: 'timeout',
|
|
93
93
|
});
|
|
94
|
+
this._debug(`set timeout with delay ${delay}`);
|
|
94
95
|
};
|
|
95
96
|
|
|
96
97
|
TimerEventDefinition.prototype.stop = function stopTimer() {
|
|
@@ -175,14 +176,44 @@ TimerEventDefinition.prototype._stop = function stop() {
|
|
|
175
176
|
broker.cancel(`_api-delegated-${this.executionId}`);
|
|
176
177
|
};
|
|
177
178
|
|
|
179
|
+
TimerEventDefinition.prototype.parse = function parse(timerType, value) {
|
|
180
|
+
let repeat, delay, expireAt;
|
|
181
|
+
switch (timerType) {
|
|
182
|
+
case 'timeCycle':
|
|
183
|
+
case 'timeDuration': {
|
|
184
|
+
const parsed = parseIsoDuration(value);
|
|
185
|
+
if (parsed.repeat) repeat = parsed.repeat;
|
|
186
|
+
delay = toSeconds(parsed) * 1000;
|
|
187
|
+
expireAt = new Date(Date.now() + delay);
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
case 'timeDate': {
|
|
191
|
+
const ms = Date.parse(value);
|
|
192
|
+
if (!isNaN(ms)) {
|
|
193
|
+
expireAt = new Date(ms);
|
|
194
|
+
delay = Date.now() - expireAt;
|
|
195
|
+
} else {
|
|
196
|
+
throw new TypeError(`invalid timeDate >${value}<`);
|
|
197
|
+
}
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return {
|
|
203
|
+
expireAt,
|
|
204
|
+
repeat,
|
|
205
|
+
delay,
|
|
206
|
+
};
|
|
207
|
+
};
|
|
208
|
+
|
|
178
209
|
TimerEventDefinition.prototype._getTimers = function getTimers(executeMessage) {
|
|
179
210
|
const content = executeMessage.content;
|
|
180
211
|
|
|
181
|
-
const now = Date.now();
|
|
182
212
|
const result = {
|
|
183
213
|
...('expireAt' in content && {expireAt: new Date(content.expireAt)}),
|
|
184
214
|
};
|
|
185
215
|
|
|
216
|
+
let parseErr;
|
|
186
217
|
for (const t of ['timeDuration', 'timeDate', 'timeCycle']) {
|
|
187
218
|
if (t in content) result[t] = content[t];
|
|
188
219
|
else if (t in this) result[t] = this.environment.resolveExpression(this[t], executeMessage);
|
|
@@ -191,47 +222,37 @@ TimerEventDefinition.prototype._getTimers = function getTimers(executeMessage) {
|
|
|
191
222
|
let expireAtDate, repeat;
|
|
192
223
|
const timerStr = result[t];
|
|
193
224
|
if (timerStr) {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
const delay = this._getDurationInMilliseconds(timerStr);
|
|
201
|
-
if (delay !== undefined) expireAtDate = new Date(now + delay);
|
|
202
|
-
break;
|
|
203
|
-
}
|
|
204
|
-
case 'timeDate': {
|
|
205
|
-
const dateStr = result[t];
|
|
206
|
-
const ms = Date.parse(dateStr);
|
|
207
|
-
if (!isNaN(ms)) {
|
|
208
|
-
expireAtDate = new Date(ms);
|
|
209
|
-
} else {
|
|
210
|
-
this._warn(`invalid timeDate >${dateStr}<`);
|
|
211
|
-
}
|
|
212
|
-
break;
|
|
213
|
-
}
|
|
225
|
+
try {
|
|
226
|
+
const {repeat: parsedRepeat, expireAt: parsedExpireAt} = this.parse(t, timerStr);
|
|
227
|
+
repeat = parsedRepeat;
|
|
228
|
+
expireAtDate = parsedExpireAt;
|
|
229
|
+
} catch (err) {
|
|
230
|
+
parseErr = err;
|
|
214
231
|
}
|
|
215
232
|
} else {
|
|
216
|
-
expireAtDate = new Date(
|
|
233
|
+
expireAtDate = new Date();
|
|
217
234
|
}
|
|
218
235
|
|
|
219
236
|
if (!expireAtDate) continue;
|
|
220
237
|
if (!('expireAt' in result) || result.expireAt > expireAtDate) {
|
|
221
238
|
result.timerType = t;
|
|
222
239
|
result.expireAt = expireAtDate;
|
|
223
|
-
|
|
240
|
+
result.repeat = repeat;
|
|
224
241
|
}
|
|
225
242
|
}
|
|
226
243
|
|
|
227
244
|
if ('expireAt' in result) {
|
|
228
|
-
result.timeout = result.expireAt - now;
|
|
245
|
+
result.timeout = result.expireAt - Date.now();
|
|
229
246
|
} else if ('timeout' in content) {
|
|
230
247
|
result.timeout = content.timeout;
|
|
231
248
|
} else if (!Object.keys(result).length) {
|
|
232
249
|
result.timeout = 0;
|
|
233
250
|
}
|
|
234
251
|
|
|
252
|
+
if (!('timeout' in result) && parseErr) {
|
|
253
|
+
this.logger.warn(`<${this.activity.id}> failed to parse timer: ${parseErr.message}`);
|
|
254
|
+
}
|
|
255
|
+
|
|
235
256
|
if (content.inbound && 'repeat' in content.inbound[0]) {
|
|
236
257
|
result.repeat = content.inbound[0].repeat;
|
|
237
258
|
}
|
|
@@ -239,18 +260,6 @@ TimerEventDefinition.prototype._getTimers = function getTimers(executeMessage) {
|
|
|
239
260
|
return result;
|
|
240
261
|
};
|
|
241
262
|
|
|
242
|
-
TimerEventDefinition.prototype._getDurationInMilliseconds = function getDurationInMilliseconds(duration) {
|
|
243
|
-
try {
|
|
244
|
-
return toSeconds(parse(duration)) * 1000;
|
|
245
|
-
} catch (err) {
|
|
246
|
-
this._warn(`failed to parse ${this.timerType} >${duration}<: ${err.message}`);
|
|
247
|
-
}
|
|
248
|
-
};
|
|
249
|
-
|
|
250
263
|
TimerEventDefinition.prototype._debug = function debug(msg) {
|
|
251
264
|
this.logger.debug(`<${this.executionId} (${this.activity.id})> ${msg}`);
|
|
252
265
|
};
|
|
253
|
-
|
|
254
|
-
TimerEventDefinition.prototype._warn = function debug(msg) {
|
|
255
|
-
this.logger.warn(`<${this.executionId} (${this.activity.id})> ${msg}`);
|
|
256
|
-
};
|
|
@@ -101,7 +101,7 @@ SequenceFlow.prototype.shake = function shake(message) {
|
|
|
101
101
|
|
|
102
102
|
if (content.id === this.targetId) return this.broker.publish('event', 'flow.shake.loop', content, {persistent: false, type: 'shake'});
|
|
103
103
|
|
|
104
|
-
for (const s of message.content.sequence) {
|
|
104
|
+
for (const s of message.content.sequence || []) {
|
|
105
105
|
if (s.id === this.id) return this.broker.publish('event', 'flow.shake.loop', content, {persistent: false, type: 'shake'});
|
|
106
106
|
}
|
|
107
107
|
|
|
@@ -140,6 +140,19 @@ SequenceFlow.prototype.createMessage = function createMessage(override) {
|
|
|
140
140
|
};
|
|
141
141
|
};
|
|
142
142
|
|
|
143
|
+
SequenceFlow.prototype.evaluate = function evaluate(fromMessage, callback) {
|
|
144
|
+
if (this.isDefault) {
|
|
145
|
+
return callback(null, true);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const flowCondition = this.getCondition();
|
|
149
|
+
if (!flowCondition) {
|
|
150
|
+
return callback(null, true);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
flowCondition.execute(fromMessage, callback);
|
|
154
|
+
};
|
|
155
|
+
|
|
143
156
|
SequenceFlow.prototype._publishEvent = function publishEvent(action, content) {
|
|
144
157
|
const eventContent = this.createMessage({
|
|
145
158
|
action,
|
package/src/index.js
CHANGED
|
@@ -46,6 +46,8 @@ import Task from './tasks/Task.js';
|
|
|
46
46
|
import TerminateEventDefinition from './eventDefinitions/TerminateEventDefinition.js';
|
|
47
47
|
import TimerEventDefinition from './eventDefinitions/TimerEventDefinition.js';
|
|
48
48
|
import Transaction from './tasks/Transaction.js';
|
|
49
|
+
import {Timers} from './Timers.js';
|
|
50
|
+
import * as ISODuration from './iso-duration.js';
|
|
49
51
|
|
|
50
52
|
export {
|
|
51
53
|
Association,
|
|
@@ -103,4 +105,6 @@ export {
|
|
|
103
105
|
TerminateEventDefinition,
|
|
104
106
|
TimerEventDefinition,
|
|
105
107
|
Transaction,
|
|
108
|
+
Timers,
|
|
109
|
+
ISODuration,
|
|
106
110
|
};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// License MIT @ https://tolu.mit-license.org/
|
|
2
|
+
|
|
3
|
+
const numbers = '\\d+';
|
|
4
|
+
const fractionalNumbers = ''.concat(numbers, '(?:[\\.,]').concat(numbers, ')?');
|
|
5
|
+
const datePattern = '('.concat(numbers, 'Y)?(').concat(numbers, 'M)?(').concat(numbers, 'W)?(').concat(fractionalNumbers, 'D)?');
|
|
6
|
+
const timePattern = 'T('.concat(fractionalNumbers, 'H)?(').concat(fractionalNumbers, 'M)?(').concat(fractionalNumbers, 'S)?');
|
|
7
|
+
|
|
8
|
+
const rPattern = '(?:R('.concat(numbers).concat(')/)?');
|
|
9
|
+
const iso8601 = rPattern.concat('P(?:').concat(datePattern, '(?:').concat(timePattern, ')?)');
|
|
10
|
+
const objMap = [
|
|
11
|
+
'years',
|
|
12
|
+
'months',
|
|
13
|
+
'weeks',
|
|
14
|
+
'days',
|
|
15
|
+
'hours',
|
|
16
|
+
'minutes',
|
|
17
|
+
'seconds',
|
|
18
|
+
];
|
|
19
|
+
const defaultDuration = Object.freeze({
|
|
20
|
+
years: 0,
|
|
21
|
+
months: 0,
|
|
22
|
+
weeks: 0,
|
|
23
|
+
days: 0,
|
|
24
|
+
hours: 0,
|
|
25
|
+
minutes: 0,
|
|
26
|
+
seconds: 0,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The ISO8601 regex for matching / testing durations
|
|
31
|
+
*/
|
|
32
|
+
const pattern = new RegExp(iso8601);
|
|
33
|
+
|
|
34
|
+
/** Parse PnYnMnDTnHnMnS format to object */
|
|
35
|
+
export function parse(durationString) {
|
|
36
|
+
const matches = durationString.replace(/,/g, '.').match(pattern);
|
|
37
|
+
if (!matches) {
|
|
38
|
+
throw new RangeError('invalid duration: ' + durationString);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Slice away repeat and first entry in match-array (the input string)
|
|
42
|
+
const slicedMatches = matches.slice(2);
|
|
43
|
+
if (slicedMatches.filter(Boolean).length === 0) {
|
|
44
|
+
throw new RangeError('invalid duration: ' + durationString);
|
|
45
|
+
}
|
|
46
|
+
// Check only one fraction is used
|
|
47
|
+
if (slicedMatches.filter((v) => {
|
|
48
|
+
return /\./.test(v || '');
|
|
49
|
+
}).length > 1) {
|
|
50
|
+
throw new RangeError('Fractions are allowed on the smallest unit in the string, e.g. P0.5D or PT1.0001S but not PT0.5M0.1S: ' + durationString);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const result = {};
|
|
54
|
+
if (matches[1]) result.repeat = Number(matches[1]);
|
|
55
|
+
|
|
56
|
+
return slicedMatches.reduce((prev, next, idx) => {
|
|
57
|
+
prev[objMap[idx]] = parseFloat(next || '0') || 0;
|
|
58
|
+
return prev;
|
|
59
|
+
}, result);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Convert ISO8601 duration object to an end Date. */
|
|
63
|
+
export function end(durationInput, startDate) {
|
|
64
|
+
const duration = Object.assign({}, defaultDuration, durationInput);
|
|
65
|
+
// Create two equal timestamps, add duration to 'then' and return time difference
|
|
66
|
+
const timestamp = startDate.getTime();
|
|
67
|
+
const then = new Date(timestamp);
|
|
68
|
+
then.setFullYear(then.getFullYear() + duration.years);
|
|
69
|
+
then.setMonth(then.getMonth() + duration.months);
|
|
70
|
+
then.setDate(then.getDate() + duration.days);
|
|
71
|
+
// set time as milliseconds to get fractions working for minutes/hours
|
|
72
|
+
const hoursInMs = duration.hours * 3600 * 1000;
|
|
73
|
+
const minutesInMs = duration.minutes * 60 * 1000;
|
|
74
|
+
then.setMilliseconds(then.getMilliseconds() + duration.seconds * 1000 + hoursInMs + minutesInMs);
|
|
75
|
+
// Special case weeks
|
|
76
|
+
then.setDate(then.getDate() + duration.weeks * 7);
|
|
77
|
+
return then;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Convert ISO8601 duration object to seconds */
|
|
81
|
+
export function toSeconds(durationInput, startDate) {
|
|
82
|
+
if (startDate === void 0) {
|
|
83
|
+
startDate = new Date();
|
|
84
|
+
}
|
|
85
|
+
const duration = Object.assign({}, defaultDuration, durationInput);
|
|
86
|
+
const timestamp = startDate.getTime();
|
|
87
|
+
const now = new Date(timestamp);
|
|
88
|
+
const then = end(duration, now);
|
|
89
|
+
const seconds = (then.getTime() - now.getTime()) / 1000;
|
|
90
|
+
return seconds;
|
|
91
|
+
}
|
package/types/index.d.ts
CHANGED
|
@@ -37,7 +37,8 @@ declare module 'bpmn-elements' {
|
|
|
37
37
|
content: ElementMessageContent,
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
class EventDefinition {
|
|
41
|
+
constructor(activity: Activity, eventDefinitionElement: SerializableElement)
|
|
41
42
|
get id(): string;
|
|
42
43
|
get type(): string;
|
|
43
44
|
get executionId(): string;
|
|
@@ -481,6 +482,13 @@ declare module 'bpmn-elements' {
|
|
|
481
482
|
shake(message: any): number;
|
|
482
483
|
getCondition(): any;
|
|
483
484
|
createMessage(override?: any): object;
|
|
485
|
+
/**
|
|
486
|
+
* Evaluate flow
|
|
487
|
+
* Executes condition if any, default flow is
|
|
488
|
+
* @param fromMessage Activity message
|
|
489
|
+
* @param {evaluateCallback} callback Callback with evaluation result, if truthy flow should be taken
|
|
490
|
+
*/
|
|
491
|
+
evaluate(fromMessage: ElementBrokerMessage, callback: (err: Error, result: any) => void): void;
|
|
484
492
|
}
|
|
485
493
|
|
|
486
494
|
interface MessageFlowReference {
|
|
@@ -514,15 +522,53 @@ declare module 'bpmn-elements' {
|
|
|
514
522
|
[x: string]: any,
|
|
515
523
|
}
|
|
516
524
|
|
|
517
|
-
type wrappedSetTimeout = (handler:
|
|
518
|
-
type wrappedClearTimeout = (
|
|
525
|
+
type wrappedSetTimeout = (handler: TimerHandler, delay: number, ...args: any[]) => Timer;
|
|
526
|
+
type wrappedClearTimeout = (ref: any) => void;
|
|
527
|
+
|
|
528
|
+
interface Timer {
|
|
529
|
+
/** The function to call when the timer elapses */
|
|
530
|
+
readonly callback: TimerHandler;
|
|
531
|
+
/** The number of milliseconds to wait before calling the callback */
|
|
532
|
+
readonly delay: number;
|
|
533
|
+
/** Optional arguments to pass when the callback is called */
|
|
534
|
+
readonly args?: any[];
|
|
535
|
+
/** Timer owner if any */
|
|
536
|
+
readonly owner?: any;
|
|
537
|
+
/** Timer Id */
|
|
538
|
+
readonly timerId: string;
|
|
539
|
+
/** Timeout, return from setTimeout */
|
|
540
|
+
readonly timerRef: any;
|
|
541
|
+
[x: string]: any;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
interface RegisteredTimer {
|
|
545
|
+
owner?: any;
|
|
546
|
+
get setTimeout(): wrappedSetTimeout;
|
|
547
|
+
get clearTimeout(): wrappedClearTimeout;
|
|
548
|
+
}
|
|
519
549
|
|
|
520
550
|
interface ITimers {
|
|
521
|
-
get executing(): any[];
|
|
522
551
|
get setTimeout(): wrappedSetTimeout;
|
|
523
552
|
get clearTimeout(): wrappedClearTimeout;
|
|
524
|
-
register(owner?: any):
|
|
525
|
-
[x: string]: any
|
|
553
|
+
register(owner?: any): RegisteredTimer;
|
|
554
|
+
[x: string]: any;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
interface TimersOptions {
|
|
558
|
+
/** Defaults to builtin setTimeout */
|
|
559
|
+
setTimeout?: typeof setTimeout;
|
|
560
|
+
/** Defaults to builtin clearTimeout */
|
|
561
|
+
clearTimeout?: typeof clearTimeout;
|
|
562
|
+
[x: string]: any;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
class Timers implements ITimers {
|
|
566
|
+
options: TimersOptions;
|
|
567
|
+
constructor(options?: TimersOptions);
|
|
568
|
+
get executing(): Timer[];
|
|
569
|
+
get setTimeout(): wrappedSetTimeout;
|
|
570
|
+
get clearTimeout(): wrappedClearTimeout;
|
|
571
|
+
register(owner?: any): RegisteredTimer;
|
|
526
572
|
}
|
|
527
573
|
|
|
528
574
|
interface IScripts {
|
|
@@ -595,7 +641,30 @@ declare module 'bpmn-elements' {
|
|
|
595
641
|
var MessageEventDefinition: EventDefinition;
|
|
596
642
|
var SignalEventDefinition: EventDefinition;
|
|
597
643
|
var TerminateEventDefinition: EventDefinition;
|
|
598
|
-
|
|
644
|
+
|
|
645
|
+
const enum TimerType {
|
|
646
|
+
TimeCycle = 'timeCycle',
|
|
647
|
+
TimeDuration = 'timeDuration',
|
|
648
|
+
TimeDate = 'timeDate',
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
type parsedTimer = {
|
|
652
|
+
/** Expires at date time */
|
|
653
|
+
expireAt?: Date,
|
|
654
|
+
/** Repeat number of times */
|
|
655
|
+
repeat?: number,
|
|
656
|
+
/** Delay in milliseconds */
|
|
657
|
+
delay?: number,
|
|
658
|
+
};
|
|
659
|
+
|
|
660
|
+
class TimerEventDefinition extends EventDefinition {
|
|
661
|
+
/**
|
|
662
|
+
* Parse timer type
|
|
663
|
+
* @param timerType type of timer
|
|
664
|
+
* @param timerValue resolved expression timer string
|
|
665
|
+
*/
|
|
666
|
+
parse(timerType: TimerType, timerValue: string): parsedTimer;
|
|
667
|
+
}
|
|
599
668
|
|
|
600
669
|
class BpmnError {
|
|
601
670
|
get id(): string;
|
|
@@ -634,4 +703,33 @@ declare module 'bpmn-elements' {
|
|
|
634
703
|
code?: string;
|
|
635
704
|
constructor(description: string, sourceMessage: MessageMessage, inner?: Error);
|
|
636
705
|
}
|
|
706
|
+
|
|
707
|
+
interface Duration {
|
|
708
|
+
years?: number;
|
|
709
|
+
months?: number;
|
|
710
|
+
weeks?: number;
|
|
711
|
+
days?: number;
|
|
712
|
+
hours?: number;
|
|
713
|
+
minutes?: number;
|
|
714
|
+
seconds?: number;
|
|
715
|
+
repeat?: number;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
type ISODurationApi = {
|
|
719
|
+
/** Parse PnYnMnDTnHnMnS format to object */
|
|
720
|
+
parse: (durationString: string) => Duration,
|
|
721
|
+
/** Convert ISO8601 duration object to an end Date. */
|
|
722
|
+
end: (durationInput: Duration, startDate?: Date) => Date,
|
|
723
|
+
/** Convert ISO8601 duration object to seconds */
|
|
724
|
+
toSeconds: (durationInput: Duration, startDate?: Date) => number,
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
const ISODuration: ISODurationApi;
|
|
637
728
|
}
|
|
729
|
+
|
|
730
|
+
/**
|
|
731
|
+
* Evaluate flow callback
|
|
732
|
+
* @callback evaluateCallback
|
|
733
|
+
* @param {Error} err Evaluation error
|
|
734
|
+
* @param {boolean|object} evaluationResult If thruthy flow should be taken
|
|
735
|
+
*/
|