@onify/flow-extensions 2.0.0 → 3.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 +31 -0
- package/dist/index.js +123 -25
- package/dist/src/Connector.js +1 -1
- package/dist/src/ExecutionListeners.js +140 -0
- package/dist/src/FlowScripts.js +9 -4
- package/dist/src/IO.js +1 -1
- package/index.js +73 -13
- package/package.json +4 -4
- package/src/ExecutionListeners.js +126 -0
- package/src/IO.js +1 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
Changelog
|
|
2
|
+
=========
|
|
3
|
+
|
|
4
|
+
# 3.0.0
|
|
5
|
+
|
|
6
|
+
- Support activity script and expression execution listeners
|
|
7
|
+
- Remove default behaviour of saving activity output even if output is not declared. Output **was** saved to `environment.output._<Activity ID>` if no result variable or output was declared. The reason was that there was no easy way of getting output from SubProcess or a multi-instance task. Now SubProcess output can be defined and multi-instance output can be solved with execution listener
|
|
8
|
+
|
|
9
|
+
# 2.0.0
|
|
10
|
+
|
|
11
|
+
- fix resume extension when recovered mid formatting
|
|
12
|
+
- drop node 12 support
|
|
13
|
+
|
|
14
|
+
# 1.1.0
|
|
15
|
+
|
|
16
|
+
- allow ISO8601 repeating interval and duration in timeCycle
|
|
17
|
+
|
|
18
|
+
# 1.0.0
|
|
19
|
+
|
|
20
|
+
- proper routing keys for end formatting
|
|
21
|
+
|
|
22
|
+
# 0.1.0
|
|
23
|
+
|
|
24
|
+
- catch errors when resolving service expression
|
|
25
|
+
- test with bpmn-engine@14
|
|
26
|
+
|
|
27
|
+
# 0.0.2
|
|
28
|
+
|
|
29
|
+
- allow expressions in timeCycle
|
|
30
|
+
- test with bpmn-engine@13
|
|
31
|
+
- error message changed in node 16
|
package/dist/index.js
CHANGED
|
@@ -6,11 +6,12 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.extendFn = extendFn;
|
|
7
7
|
exports.extensions = extensions;
|
|
8
8
|
var _cronParser = _interopRequireDefault(require("cron-parser"));
|
|
9
|
-
var _IOProperties = _interopRequireDefault(require("./src/IOProperties"));
|
|
10
|
-
var _IOForm = _interopRequireDefault(require("./src/IOForm"));
|
|
11
|
-
var _Connector = _interopRequireDefault(require("./src/Connector"));
|
|
12
|
-
var _ServiceExpression = _interopRequireDefault(require("./src/ServiceExpression"));
|
|
13
|
-
var _IO = require("./src/IO");
|
|
9
|
+
var _IOProperties = _interopRequireDefault(require("./src/IOProperties.js"));
|
|
10
|
+
var _IOForm = _interopRequireDefault(require("./src/IOForm.js"));
|
|
11
|
+
var _Connector = _interopRequireDefault(require("./src/Connector.js"));
|
|
12
|
+
var _ServiceExpression = _interopRequireDefault(require("./src/ServiceExpression.js"));
|
|
13
|
+
var _IO = require("./src/IO.js");
|
|
14
|
+
var _ExecutionListeners = _interopRequireDefault(require("./src/ExecutionListeners.js"));
|
|
14
15
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
15
16
|
const iso8601cycle = /^\s*(R\d+\/)?P\w+/i;
|
|
16
17
|
class FormatError extends Error {
|
|
@@ -121,11 +122,68 @@ class OnifyElementExtensions {
|
|
|
121
122
|
}, {
|
|
122
123
|
consumerTag: '_onify-extension-on-executed'
|
|
123
124
|
});
|
|
125
|
+
const executionListeners = this.extensions.listeners;
|
|
126
|
+
if (executionListeners !== null && executionListeners !== void 0 && executionListeners.onStart) {
|
|
127
|
+
activity.on('start', async elementApi => {
|
|
128
|
+
formatQ.queueMessage({
|
|
129
|
+
routingKey: 'run.listener.start'
|
|
130
|
+
}, {
|
|
131
|
+
endRoutingKey: 'run.listener.start.complete'
|
|
132
|
+
}, {
|
|
133
|
+
persistent: false
|
|
134
|
+
});
|
|
135
|
+
try {
|
|
136
|
+
var format = await executionListeners.execute('start', elementApi);
|
|
137
|
+
} catch (err) {
|
|
138
|
+
return broker.publish('format', 'run.listener.start.error', {
|
|
139
|
+
error: err
|
|
140
|
+
}, {
|
|
141
|
+
persistent: false
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
broker.publish('format', 'run.listener.start.complete', {
|
|
145
|
+
...format
|
|
146
|
+
}, {
|
|
147
|
+
persistent: false
|
|
148
|
+
});
|
|
149
|
+
}, {
|
|
150
|
+
consumerTag: '_onify-extension-on-listenerstart'
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
if (executionListeners !== null && executionListeners !== void 0 && executionListeners.onEnd) {
|
|
154
|
+
activity.on('end', async elementApi => {
|
|
155
|
+
formatQ.queueMessage({
|
|
156
|
+
routingKey: 'run.listener.end'
|
|
157
|
+
}, {
|
|
158
|
+
endRoutingKey: 'run.listener.end.complete'
|
|
159
|
+
}, {
|
|
160
|
+
persistent: false
|
|
161
|
+
});
|
|
162
|
+
try {
|
|
163
|
+
var format = await executionListeners.execute('end', elementApi);
|
|
164
|
+
} catch (err) {
|
|
165
|
+
return broker.publish('format', 'run.listener.end.error', {
|
|
166
|
+
error: err
|
|
167
|
+
}, {
|
|
168
|
+
persistent: false
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
broker.publish('format', 'run.listener.end.complete', {
|
|
172
|
+
...format
|
|
173
|
+
}, {
|
|
174
|
+
persistent: false
|
|
175
|
+
});
|
|
176
|
+
}, {
|
|
177
|
+
consumerTag: '_onify-extension-on-listenerend'
|
|
178
|
+
});
|
|
179
|
+
}
|
|
124
180
|
}
|
|
125
181
|
deactivate() {
|
|
126
182
|
const broker = this.activity.broker;
|
|
127
183
|
broker.cancel('_onify-extension-on-enter');
|
|
128
184
|
broker.cancel('_onify-extension-on-executed');
|
|
185
|
+
broker.cancel('_onify-extension-on-listenerstart');
|
|
186
|
+
broker.cancel('_onify-extension-on-listenerend');
|
|
129
187
|
}
|
|
130
188
|
async _formatOnEnter(broker, formatQ, elementApi) {
|
|
131
189
|
formatQ.queueMessage({
|
|
@@ -165,14 +223,15 @@ class OnifyElementExtensions {
|
|
|
165
223
|
Object.assign(elementApi.content, result);
|
|
166
224
|
}
|
|
167
225
|
if (io) {
|
|
168
|
-
|
|
226
|
+
var _io$input, _io$output;
|
|
227
|
+
if ((_io$input = io.input) !== null && _io$input !== void 0 && _io$input.length) {
|
|
169
228
|
const input = await io.getInput(this.activity, elementApi);
|
|
170
229
|
Object.assign(result, {
|
|
171
230
|
input
|
|
172
231
|
});
|
|
173
232
|
Object.assign(elementApi.content, result);
|
|
174
233
|
}
|
|
175
|
-
if (io.output
|
|
234
|
+
if ((_io$output = io.output) !== null && _io$output !== void 0 && _io$output.length) {
|
|
176
235
|
result.assignToOutput = true;
|
|
177
236
|
}
|
|
178
237
|
}
|
|
@@ -189,7 +248,7 @@ class OnifyElementExtensions {
|
|
|
189
248
|
io
|
|
190
249
|
} = this.extensions;
|
|
191
250
|
const result = {};
|
|
192
|
-
if (io
|
|
251
|
+
if (io !== null && io !== void 0 && io.output.length) {
|
|
193
252
|
const output = await io.getOutput(this.activity, elementApi);
|
|
194
253
|
Object.assign(result, {
|
|
195
254
|
output
|
|
@@ -222,23 +281,26 @@ class OnifyElementExtensions {
|
|
|
222
281
|
}
|
|
223
282
|
}
|
|
224
283
|
function getExtensions(element, context) {
|
|
284
|
+
var _element$behaviour$ex, _ext$values, _ext$fields;
|
|
225
285
|
const result = {
|
|
226
286
|
format: element.type === 'bpmn:Process' ? new FormatProcess(element) : new FormatActivity(element)
|
|
227
287
|
};
|
|
228
288
|
const expression = element.behaviour.expression;
|
|
229
289
|
if (expression) result.Service = _ServiceExpression.default;
|
|
230
|
-
const extensions = element.behaviour.extensionElements
|
|
290
|
+
const extensions = (_element$behaviour$ex = element.behaviour.extensionElements) === null || _element$behaviour$ex === void 0 ? void 0 : _element$behaviour$ex.values;
|
|
231
291
|
if (!extensions) return result;
|
|
292
|
+
const listeners = new _ExecutionListeners.default(element, context);
|
|
293
|
+
let listener = 0;
|
|
232
294
|
for (const ext of extensions) {
|
|
233
295
|
switch (ext.$type) {
|
|
234
296
|
case 'camunda:Properties':
|
|
235
|
-
if (ext.values
|
|
297
|
+
if ((_ext$values = ext.values) !== null && _ext$values !== void 0 && _ext$values.length) result.properties = new _IOProperties.default(element, ext);
|
|
236
298
|
break;
|
|
237
299
|
case 'camunda:InputOutput':
|
|
238
300
|
result.io = new _IO.InputOutput(element.id, ext, context);
|
|
239
301
|
break;
|
|
240
302
|
case 'camunda:FormData':
|
|
241
|
-
if (ext.fields
|
|
303
|
+
if ((_ext$fields = ext.fields) !== null && _ext$fields !== void 0 && _ext$fields.length) result.form = new _IOForm.default(element, ext);
|
|
242
304
|
break;
|
|
243
305
|
case 'camunda:Connector':
|
|
244
306
|
{
|
|
@@ -250,14 +312,18 @@ function getExtensions(element, context) {
|
|
|
250
312
|
result.Service = _Connector.default.bind(_Connector.default, connectorId, io);
|
|
251
313
|
break;
|
|
252
314
|
}
|
|
315
|
+
case 'camunda:ExecutionListener':
|
|
316
|
+
listeners.add(ext, listener++);
|
|
317
|
+
break;
|
|
253
318
|
}
|
|
254
319
|
}
|
|
320
|
+
if (listeners.length) result.listeners = listeners;
|
|
255
321
|
return result;
|
|
256
322
|
}
|
|
257
323
|
class FormatActivity {
|
|
258
324
|
constructor(activity) {
|
|
259
325
|
this.activity = activity;
|
|
260
|
-
this.resultVariable = activity.behaviour.resultVariable
|
|
326
|
+
this.resultVariable = activity.behaviour.resultVariable;
|
|
261
327
|
let timeCycles;
|
|
262
328
|
if (activity.eventDefinitions) {
|
|
263
329
|
for (const ed of activity.eventDefinitions.filter(e => e.type === 'bpmn:TimerEventDefinition')) {
|
|
@@ -269,6 +335,7 @@ class FormatActivity {
|
|
|
269
335
|
this.timeCycles = timeCycles;
|
|
270
336
|
}
|
|
271
337
|
resolve(elementApi) {
|
|
338
|
+
var _documentation$, _user, _groups;
|
|
272
339
|
let user, groups, assigneeValue, description;
|
|
273
340
|
const activity = this.activity;
|
|
274
341
|
const {
|
|
@@ -281,7 +348,7 @@ class FormatActivity {
|
|
|
281
348
|
if (candidateUsers) user = resolveAndSplit(elementApi, candidateUsers);
|
|
282
349
|
if (candidateGroups) groups = resolveAndSplit(elementApi, candidateGroups);
|
|
283
350
|
if (assignee) assigneeValue = elementApi.resolveExpression(assignee);
|
|
284
|
-
if (documentation) description = documentation[0]
|
|
351
|
+
if (documentation) description = (_documentation$ = documentation[0]) === null || _documentation$ === void 0 ? void 0 : _documentation$.text;
|
|
285
352
|
let expireAt;
|
|
286
353
|
let timeCycles = this.timeCycles;
|
|
287
354
|
if (timeCycles) {
|
|
@@ -293,14 +360,16 @@ class FormatActivity {
|
|
|
293
360
|
}
|
|
294
361
|
}
|
|
295
362
|
return {
|
|
296
|
-
|
|
363
|
+
...(this.resultVariable && {
|
|
364
|
+
resultVariable: this.resultVariable
|
|
365
|
+
}),
|
|
297
366
|
...(scheduledStart && activity.parent.type === 'bpmn:Process' && {
|
|
298
367
|
scheduledStart
|
|
299
368
|
}),
|
|
300
|
-
...(user
|
|
369
|
+
...(((_user = user) === null || _user === void 0 ? void 0 : _user.length) && {
|
|
301
370
|
candidateUsers: user
|
|
302
371
|
}),
|
|
303
|
-
...(groups
|
|
372
|
+
...(((_groups = groups) === null || _groups === void 0 ? void 0 : _groups.length) && {
|
|
304
373
|
candidateGroups: groups
|
|
305
374
|
}),
|
|
306
375
|
...(!elementApi.content.description && description && {
|
|
@@ -320,6 +389,7 @@ class FormatProcess {
|
|
|
320
389
|
this.process = bp;
|
|
321
390
|
}
|
|
322
391
|
resolve(elementApi) {
|
|
392
|
+
var _documentation$2, _user2, _groups2;
|
|
323
393
|
let user, groups, description;
|
|
324
394
|
const bp = this.process;
|
|
325
395
|
const {
|
|
@@ -329,13 +399,12 @@ class FormatProcess {
|
|
|
329
399
|
} = bp.behaviour;
|
|
330
400
|
if (candidateStarterUsers) user = resolveAndSplit(elementApi, candidateStarterUsers);
|
|
331
401
|
if (candidateStarterGroups) groups = resolveAndSplit(elementApi, candidateStarterGroups);
|
|
332
|
-
if (documentation) description = documentation[0]
|
|
402
|
+
if (documentation) description = (_documentation$2 = documentation[0]) === null || _documentation$2 === void 0 ? void 0 : _documentation$2.text;
|
|
333
403
|
return {
|
|
334
|
-
|
|
335
|
-
...(user?.length && {
|
|
404
|
+
...(((_user2 = user) === null || _user2 === void 0 ? void 0 : _user2.length) && {
|
|
336
405
|
candidateStarterUsers: user
|
|
337
406
|
}),
|
|
338
|
-
...(groups
|
|
407
|
+
...(((_groups2 = groups) === null || _groups2 === void 0 ? void 0 : _groups2.length) && {
|
|
339
408
|
candidateStarterGroups: groups
|
|
340
409
|
}),
|
|
341
410
|
...(!elementApi.content.description && description && {
|
|
@@ -353,6 +422,7 @@ function resolveAndSplit(elementApi, str) {
|
|
|
353
422
|
return resolved.split(',').map(g => g.trim && g.trim().toLowerCase()).filter(Boolean);
|
|
354
423
|
}
|
|
355
424
|
function extendFn(behaviour, context) {
|
|
425
|
+
var _behaviour$extensionE;
|
|
356
426
|
if (behaviour.$type === 'bpmn:StartEvent' && behaviour.eventDefinitions) {
|
|
357
427
|
const timer = behaviour.eventDefinitions.find(({
|
|
358
428
|
type,
|
|
@@ -362,11 +432,21 @@ function extendFn(behaviour, context) {
|
|
|
362
432
|
scheduledStart: timer.behaviour.timeCycle
|
|
363
433
|
});
|
|
364
434
|
}
|
|
365
|
-
if (!Array.isArray(behaviour.extensionElements
|
|
366
|
-
|
|
367
|
-
const
|
|
368
|
-
|
|
369
|
-
|
|
435
|
+
if (!Array.isArray((_behaviour$extensionE = behaviour.extensionElements) === null || _behaviour$extensionE === void 0 ? void 0 : _behaviour$extensionE.values)) return;
|
|
436
|
+
let listener = 0;
|
|
437
|
+
for (const extension of behaviour.extensionElements.values) {
|
|
438
|
+
switch (extension.$type) {
|
|
439
|
+
case 'camunda:InputOutput':
|
|
440
|
+
registerIOScripts(behaviour.id, context, extension.$type, extension);
|
|
441
|
+
break;
|
|
442
|
+
case 'camunda:Connector':
|
|
443
|
+
registerIOScripts(behaviour.id, context, extension.$type, extension.inputOutput);
|
|
444
|
+
break;
|
|
445
|
+
case 'camunda:ExecutionListener':
|
|
446
|
+
registerListenerScript(behaviour.id, context, extension.$type, extension, listener++);
|
|
447
|
+
break;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
370
450
|
}
|
|
371
451
|
function registerIOScripts(parentId, context, type, ioBehaviour) {
|
|
372
452
|
if (!ioBehaviour) return;
|
|
@@ -393,4 +473,22 @@ function registerIOScripts(parentId, context, type, ioBehaviour) {
|
|
|
393
473
|
})
|
|
394
474
|
});
|
|
395
475
|
}
|
|
476
|
+
}
|
|
477
|
+
function registerListenerScript(parentId, context, type, listener, pos) {
|
|
478
|
+
const {
|
|
479
|
+
event,
|
|
480
|
+
script
|
|
481
|
+
} = listener;
|
|
482
|
+
if (!script) return;
|
|
483
|
+
const id = `${parentId}/${type}/${event}/${pos}`;
|
|
484
|
+
context.addScript(id, {
|
|
485
|
+
id,
|
|
486
|
+
scriptFormat: script.scriptFormat,
|
|
487
|
+
...(script.value && {
|
|
488
|
+
body: script.value
|
|
489
|
+
}),
|
|
490
|
+
...(script.resource && {
|
|
491
|
+
resource: script.resource
|
|
492
|
+
})
|
|
493
|
+
});
|
|
396
494
|
}
|
package/dist/src/Connector.js
CHANGED
|
@@ -30,7 +30,7 @@ Connector.prototype.execute = async function execute(...args) {
|
|
|
30
30
|
}
|
|
31
31
|
async function formatCallback(serviceErr, result) {
|
|
32
32
|
if (serviceErr) return callback(serviceErr);
|
|
33
|
-
if (!io
|
|
33
|
+
if (!(io !== null && io !== void 0 && io.output.length)) return callback(null, result);
|
|
34
34
|
try {
|
|
35
35
|
const formattedResult = await io.getOutput(activity, {
|
|
36
36
|
...executionMessage,
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
class Listener {
|
|
8
|
+
constructor(activity, context, extension) {
|
|
9
|
+
this.activity = activity;
|
|
10
|
+
this.environment = this.activity.environment;
|
|
11
|
+
this.context = context;
|
|
12
|
+
this.extension = extension;
|
|
13
|
+
this.type = extension.$type;
|
|
14
|
+
this.event = extension.event;
|
|
15
|
+
}
|
|
16
|
+
_getScope(message, extend) {
|
|
17
|
+
const environment = this.environment;
|
|
18
|
+
const {
|
|
19
|
+
fields,
|
|
20
|
+
content,
|
|
21
|
+
properties
|
|
22
|
+
} = message;
|
|
23
|
+
const scope = {
|
|
24
|
+
...extend,
|
|
25
|
+
type: this.type,
|
|
26
|
+
listener: {
|
|
27
|
+
event: this.event
|
|
28
|
+
},
|
|
29
|
+
fields,
|
|
30
|
+
content,
|
|
31
|
+
properties,
|
|
32
|
+
environment,
|
|
33
|
+
logger: this.activity.logger
|
|
34
|
+
};
|
|
35
|
+
const listenerFields = this._getFields(environment, scope);
|
|
36
|
+
if (listenerFields) scope.listener.fields = listenerFields;
|
|
37
|
+
return scope;
|
|
38
|
+
}
|
|
39
|
+
_getFields(environment, scope) {
|
|
40
|
+
const fields = this.extension.fields;
|
|
41
|
+
if (!(fields !== null && fields !== void 0 && fields.length)) return;
|
|
42
|
+
const result = {};
|
|
43
|
+
for (const {
|
|
44
|
+
name,
|
|
45
|
+
expression,
|
|
46
|
+
string
|
|
47
|
+
} of fields) {
|
|
48
|
+
result['' + name] = expression ? environment.resolveExpression(expression, scope) : string;
|
|
49
|
+
}
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
class ScriptListener extends Listener {
|
|
54
|
+
constructor(activity, context, extension, pos) {
|
|
55
|
+
super(activity, context, extension);
|
|
56
|
+
const id = this.id = `${activity.id}/${extension.script.$type}/${this.event}/${pos}`;
|
|
57
|
+
this._register(context, id, extension.script);
|
|
58
|
+
}
|
|
59
|
+
execute(api) {
|
|
60
|
+
const environment = this.environment;
|
|
61
|
+
const scope = this._getScope(api, {
|
|
62
|
+
id: this.id,
|
|
63
|
+
resolveExpression
|
|
64
|
+
});
|
|
65
|
+
const script = this.environment.scripts.getScript(this.extension.scriptFormat, {
|
|
66
|
+
id: this.id
|
|
67
|
+
});
|
|
68
|
+
return new Promise((resolve, reject) => {
|
|
69
|
+
return script.execute(scope, (err, result) => {
|
|
70
|
+
if (err) return reject(err);
|
|
71
|
+
resolve(result);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
function resolveExpression(expression) {
|
|
75
|
+
return environment.resolveExpression(expression, scope);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
_register(context, id, script) {
|
|
79
|
+
const {
|
|
80
|
+
scriptFormat,
|
|
81
|
+
value,
|
|
82
|
+
resource
|
|
83
|
+
} = script;
|
|
84
|
+
context.environment.scripts.register({
|
|
85
|
+
id,
|
|
86
|
+
type: this.type,
|
|
87
|
+
behaviour: {
|
|
88
|
+
scriptFormat,
|
|
89
|
+
...(value && {
|
|
90
|
+
script: value
|
|
91
|
+
}),
|
|
92
|
+
...(resource && {
|
|
93
|
+
resource
|
|
94
|
+
})
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
class ExpressionListener extends Listener {
|
|
100
|
+
execute(message) {
|
|
101
|
+
const scope = this._getScope(message);
|
|
102
|
+
return {
|
|
103
|
+
expression: this.environment.resolveExpression(this.extension.expression, scope)
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
class ExecutionListeners {
|
|
108
|
+
constructor(activity, context) {
|
|
109
|
+
this.activity = activity;
|
|
110
|
+
this.context = context;
|
|
111
|
+
this.listeners = [];
|
|
112
|
+
this.onStart = false;
|
|
113
|
+
this.onEnd = false;
|
|
114
|
+
}
|
|
115
|
+
get length() {
|
|
116
|
+
return this.listeners.length;
|
|
117
|
+
}
|
|
118
|
+
add(extension, pos) {
|
|
119
|
+
const {
|
|
120
|
+
event,
|
|
121
|
+
script,
|
|
122
|
+
expression
|
|
123
|
+
} = extension;
|
|
124
|
+
if (!script && !expression) return;
|
|
125
|
+
const list = this.listeners;
|
|
126
|
+
if (script && (script.value || script.resource)) list.push(new ScriptListener(this.activity, this.context, extension, pos));else if (expression) list.push(new ExpressionListener(this.activity, this.context, extension));
|
|
127
|
+
if (event === 'start') this.onStart = true;
|
|
128
|
+
if (event === 'end') this.onEnd = true;
|
|
129
|
+
}
|
|
130
|
+
async execute(event, message) {
|
|
131
|
+
const found = this.listeners.filter(l => l.event === event);
|
|
132
|
+
const format = {};
|
|
133
|
+
for (const f of found) {
|
|
134
|
+
const result = await f.execute(message);
|
|
135
|
+
if (result !== null && typeof result === 'object') Object.assign(format, result);
|
|
136
|
+
}
|
|
137
|
+
return format;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
exports.default = ExecutionListeners;
|
package/dist/src/FlowScripts.js
CHANGED
|
@@ -105,7 +105,7 @@ FlowScripts.prototype.getScript = function getScript(scriptType, {
|
|
|
105
105
|
function JavaScript(flowName, scriptBody, runContext, options) {
|
|
106
106
|
this.flowName = flowName;
|
|
107
107
|
this._runContext = runContext;
|
|
108
|
-
this.timeout = options
|
|
108
|
+
this.timeout = options === null || options === void 0 ? void 0 : options.timeout;
|
|
109
109
|
try {
|
|
110
110
|
this.script = new _vm.Script(scriptBody, options);
|
|
111
111
|
} catch (err) {
|
|
@@ -151,17 +151,22 @@ function JavaScriptResource(flowName, resource, resourceBase, runContext, option
|
|
|
151
151
|
this[kResources] = resourceBase;
|
|
152
152
|
}
|
|
153
153
|
JavaScriptResource.prototype.execute = async function execute(executionContext, callback) {
|
|
154
|
+
let resource;
|
|
154
155
|
try {
|
|
155
|
-
|
|
156
|
+
resource = executionContext.resolveExpression(this.resource);
|
|
157
|
+
var scriptBody = await _fs.promises.readFile((0, _path.join)(this[kResources], resource)); // eslint-disable-line no-var
|
|
156
158
|
} catch (err) {
|
|
159
|
+
if (err instanceof SyntaxError) {
|
|
160
|
+
return callback(err);
|
|
161
|
+
}
|
|
157
162
|
const {
|
|
158
163
|
filename
|
|
159
164
|
} = this.options;
|
|
160
|
-
return callback(new Error(`${filename}: script resource ${this.resource} not found`));
|
|
165
|
+
return callback(new Error(`${filename}: script resource ${resource || this.resource} not found`));
|
|
161
166
|
}
|
|
162
167
|
const script = new JavaScript(this.flowName, scriptBody, this._runContext, {
|
|
163
168
|
...this.options,
|
|
164
|
-
filename: this.resource
|
|
169
|
+
filename: `${this.options.filename}/${resource}`
|
|
165
170
|
});
|
|
166
171
|
return script.execute(executionContext, callback);
|
|
167
172
|
};
|
package/dist/src/IO.js
CHANGED
package/index.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import cronParser from 'cron-parser';
|
|
2
|
-
import IOProperties from './src/IOProperties';
|
|
3
|
-
import IOForm from './src/IOForm';
|
|
4
|
-
import Connector from './src/Connector';
|
|
5
|
-
import ServiceExpression from './src/ServiceExpression';
|
|
6
|
-
import {InputOutput} from './src/IO';
|
|
2
|
+
import IOProperties from './src/IOProperties.js';
|
|
3
|
+
import IOForm from './src/IOForm.js';
|
|
4
|
+
import Connector from './src/Connector.js';
|
|
5
|
+
import ServiceExpression from './src/ServiceExpression.js';
|
|
6
|
+
import {InputOutput} from './src/IO.js';
|
|
7
|
+
import ExtensionListeners from './src/ExecutionListeners.js';
|
|
7
8
|
|
|
8
9
|
const iso8601cycle = /^\s*(R\d+\/)?P\w+/i;
|
|
9
10
|
|
|
@@ -98,11 +99,41 @@ class OnifyElementExtensions {
|
|
|
98
99
|
|
|
99
100
|
broker.publish('format', 'run.end.complete', {...format}, {persistent: false});
|
|
100
101
|
}, {consumerTag: '_onify-extension-on-executed'});
|
|
102
|
+
|
|
103
|
+
const executionListeners = this.extensions.listeners;
|
|
104
|
+
if (executionListeners?.onStart) {
|
|
105
|
+
activity.on('start', async (elementApi) => {
|
|
106
|
+
formatQ.queueMessage({routingKey: 'run.listener.start'}, {endRoutingKey: 'run.listener.start.complete'}, {persistent: false});
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
var format = await executionListeners.execute('start', elementApi);
|
|
110
|
+
} catch (err) {
|
|
111
|
+
return broker.publish('format', 'run.listener.start.error', {error: err}, {persistent: false});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
broker.publish('format', 'run.listener.start.complete', {...format}, {persistent: false});
|
|
115
|
+
}, {consumerTag: '_onify-extension-on-listenerstart'});
|
|
116
|
+
}
|
|
117
|
+
if (executionListeners?.onEnd) {
|
|
118
|
+
activity.on('end', async (elementApi) => {
|
|
119
|
+
formatQ.queueMessage({routingKey: 'run.listener.end'}, {endRoutingKey: 'run.listener.end.complete'}, {persistent: false});
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
var format = await executionListeners.execute('end', elementApi);
|
|
123
|
+
} catch (err) {
|
|
124
|
+
return broker.publish('format', 'run.listener.end.error', {error: err}, {persistent: false});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
broker.publish('format', 'run.listener.end.complete', {...format}, {persistent: false});
|
|
128
|
+
}, {consumerTag: '_onify-extension-on-listenerend'});
|
|
129
|
+
}
|
|
101
130
|
}
|
|
102
131
|
deactivate() {
|
|
103
132
|
const broker = this.activity.broker;
|
|
104
133
|
broker.cancel('_onify-extension-on-enter');
|
|
105
134
|
broker.cancel('_onify-extension-on-executed');
|
|
135
|
+
broker.cancel('_onify-extension-on-listenerstart');
|
|
136
|
+
broker.cancel('_onify-extension-on-listenerend');
|
|
106
137
|
}
|
|
107
138
|
async _formatOnEnter(broker, formatQ, elementApi) {
|
|
108
139
|
formatQ.queueMessage({routingKey: 'run.enter.format'}, {endRoutingKey: 'run.enter.complete'}, {persistent: false});
|
|
@@ -185,6 +216,9 @@ function getExtensions(element, context) {
|
|
|
185
216
|
const extensions = element.behaviour.extensionElements?.values;
|
|
186
217
|
if (!extensions) return result;
|
|
187
218
|
|
|
219
|
+
const listeners = new ExtensionListeners(element, context);
|
|
220
|
+
|
|
221
|
+
let listener = 0;
|
|
188
222
|
for (const ext of extensions) {
|
|
189
223
|
switch (ext.$type) {
|
|
190
224
|
case 'camunda:Properties':
|
|
@@ -202,16 +236,21 @@ function getExtensions(element, context) {
|
|
|
202
236
|
result.Service = Connector.bind(Connector, connectorId, io);
|
|
203
237
|
break;
|
|
204
238
|
}
|
|
239
|
+
case 'camunda:ExecutionListener':
|
|
240
|
+
listeners.add(ext, listener++);
|
|
241
|
+
break;
|
|
205
242
|
}
|
|
206
243
|
}
|
|
207
244
|
|
|
245
|
+
if (listeners.length) result.listeners = listeners;
|
|
246
|
+
|
|
208
247
|
return result;
|
|
209
248
|
}
|
|
210
249
|
|
|
211
250
|
class FormatActivity {
|
|
212
251
|
constructor(activity) {
|
|
213
252
|
this.activity = activity;
|
|
214
|
-
this.resultVariable = activity.behaviour.resultVariable
|
|
253
|
+
this.resultVariable = activity.behaviour.resultVariable;
|
|
215
254
|
|
|
216
255
|
let timeCycles;
|
|
217
256
|
if (activity.eventDefinitions) {
|
|
@@ -252,7 +291,7 @@ class FormatActivity {
|
|
|
252
291
|
}
|
|
253
292
|
|
|
254
293
|
return {
|
|
255
|
-
resultVariable: this.resultVariable,
|
|
294
|
+
...(this.resultVariable && {resultVariable: this.resultVariable}),
|
|
256
295
|
...(scheduledStart && activity.parent.type === 'bpmn:Process' && {scheduledStart}),
|
|
257
296
|
...(user?.length && {candidateUsers: user}),
|
|
258
297
|
...(groups?.length && {candidateGroups: groups}),
|
|
@@ -281,7 +320,6 @@ class FormatProcess {
|
|
|
281
320
|
if (documentation) description = documentation[0]?.text;
|
|
282
321
|
|
|
283
322
|
return {
|
|
284
|
-
resultVariable: this.resultVariable,
|
|
285
323
|
...(user?.length && {candidateStarterUsers: user}),
|
|
286
324
|
...(groups?.length && {candidateStarterGroups: groups}),
|
|
287
325
|
...(!elementApi.content.description && description && {description: elementApi.resolveExpression(description)}),
|
|
@@ -311,11 +349,20 @@ function extendFn(behaviour, context) {
|
|
|
311
349
|
|
|
312
350
|
if (!Array.isArray(behaviour.extensionElements?.values)) return;
|
|
313
351
|
|
|
314
|
-
|
|
315
|
-
const
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
352
|
+
let listener = 0;
|
|
353
|
+
for (const extension of behaviour.extensionElements.values) {
|
|
354
|
+
switch (extension.$type) {
|
|
355
|
+
case 'camunda:InputOutput':
|
|
356
|
+
registerIOScripts(behaviour.id, context, extension.$type, extension);
|
|
357
|
+
break;
|
|
358
|
+
case 'camunda:Connector':
|
|
359
|
+
registerIOScripts(behaviour.id, context, extension.$type, extension.inputOutput);
|
|
360
|
+
break;
|
|
361
|
+
case 'camunda:ExecutionListener':
|
|
362
|
+
registerListenerScript(behaviour.id, context, extension.$type, extension, listener++);
|
|
363
|
+
break;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
319
366
|
}
|
|
320
367
|
|
|
321
368
|
function registerIOScripts(parentId, context, type, ioBehaviour) {
|
|
@@ -336,3 +383,16 @@ function registerIOScripts(parentId, context, type, ioBehaviour) {
|
|
|
336
383
|
});
|
|
337
384
|
}
|
|
338
385
|
}
|
|
386
|
+
|
|
387
|
+
function registerListenerScript(parentId, context, type, listener, pos) {
|
|
388
|
+
const {event, script} = listener;
|
|
389
|
+
if (!script) return;
|
|
390
|
+
|
|
391
|
+
const id = `${parentId}/${type}/${event}/${pos}`;
|
|
392
|
+
context.addScript(id, {
|
|
393
|
+
id,
|
|
394
|
+
scriptFormat: script.scriptFormat,
|
|
395
|
+
...(script.value && {body: script.value}),
|
|
396
|
+
...(script.resource && {resource: script.resource}),
|
|
397
|
+
});
|
|
398
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onify/flow-extensions",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Onify Flow extensions",
|
|
5
5
|
"module": "index.js",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"@babel/preset-env": "^7.20.2",
|
|
41
41
|
"@babel/register": "^7.18.9",
|
|
42
42
|
"bpmn-elements-8-1": "npm:bpmn-elements@8.1",
|
|
43
|
-
"bpmn-engine": "^15.1.
|
|
43
|
+
"bpmn-engine": "^15.1.2",
|
|
44
44
|
"bpmn-engine-14": "npm:bpmn-engine@14",
|
|
45
45
|
"bpmn-moddle": "^7.1.3",
|
|
46
46
|
"c8": "^7.12.0",
|
|
@@ -48,13 +48,13 @@
|
|
|
48
48
|
"chai": "^4.3.7",
|
|
49
49
|
"chronokinesis": "^3.1.2",
|
|
50
50
|
"debug": "^4.3.4",
|
|
51
|
-
"eslint": "^8.
|
|
51
|
+
"eslint": "^8.28.0",
|
|
52
52
|
"mocha": "^10.1.0",
|
|
53
53
|
"mocha-cakes-2": "^3.3.0",
|
|
54
54
|
"moddle-context-serializer": "^2.1.0"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"cron-parser": "^4.
|
|
57
|
+
"cron-parser": "^4.7.0"
|
|
58
58
|
},
|
|
59
59
|
"files": [
|
|
60
60
|
"src",
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
class Listener {
|
|
2
|
+
constructor(activity, context, extension) {
|
|
3
|
+
this.activity = activity;
|
|
4
|
+
this.environment = this.activity.environment;
|
|
5
|
+
this.context = context;
|
|
6
|
+
this.extension = extension;
|
|
7
|
+
this.type = extension.$type;
|
|
8
|
+
this.event = extension.event;
|
|
9
|
+
}
|
|
10
|
+
_getScope(message, extend) {
|
|
11
|
+
const environment = this.environment;
|
|
12
|
+
|
|
13
|
+
const {fields, content, properties} = message;
|
|
14
|
+
const scope = {
|
|
15
|
+
...extend,
|
|
16
|
+
type: this.type,
|
|
17
|
+
listener: {
|
|
18
|
+
event: this.event,
|
|
19
|
+
},
|
|
20
|
+
fields,
|
|
21
|
+
content,
|
|
22
|
+
properties,
|
|
23
|
+
environment,
|
|
24
|
+
logger: this.activity.logger,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const listenerFields = this._getFields(environment, scope);
|
|
28
|
+
if (listenerFields) scope.listener.fields = listenerFields;
|
|
29
|
+
|
|
30
|
+
return scope;
|
|
31
|
+
}
|
|
32
|
+
_getFields(environment, scope) {
|
|
33
|
+
const fields = this.extension.fields;
|
|
34
|
+
if (!fields?.length) return;
|
|
35
|
+
const result = {};
|
|
36
|
+
for (const {name, expression, string} of fields) {
|
|
37
|
+
result['' + name] = expression ? environment.resolveExpression(expression, scope) : string;
|
|
38
|
+
}
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
class ScriptListener extends Listener {
|
|
44
|
+
constructor(activity, context, extension, pos) {
|
|
45
|
+
super(activity, context, extension);
|
|
46
|
+
const id = this.id = `${activity.id}/${extension.script.$type}/${this.event}/${pos}`;
|
|
47
|
+
this._register(context, id, extension.script);
|
|
48
|
+
}
|
|
49
|
+
execute(api) {
|
|
50
|
+
const environment = this.environment;
|
|
51
|
+
const scope = this._getScope(api, {id: this.id, resolveExpression});
|
|
52
|
+
const script = this.environment.scripts.getScript(this.extension.scriptFormat, {id: this.id});
|
|
53
|
+
|
|
54
|
+
return new Promise((resolve, reject) => {
|
|
55
|
+
return script.execute(scope, (err, result) => {
|
|
56
|
+
if (err) return reject(err);
|
|
57
|
+
resolve(result);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
function resolveExpression(expression) {
|
|
62
|
+
return environment.resolveExpression(expression, scope);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
_register(context, id, script) {
|
|
66
|
+
const {
|
|
67
|
+
scriptFormat,
|
|
68
|
+
value,
|
|
69
|
+
resource
|
|
70
|
+
} = script;
|
|
71
|
+
|
|
72
|
+
context.environment.scripts.register({
|
|
73
|
+
id,
|
|
74
|
+
type: this.type,
|
|
75
|
+
behaviour: {
|
|
76
|
+
scriptFormat,
|
|
77
|
+
...(value && {
|
|
78
|
+
script: value
|
|
79
|
+
}),
|
|
80
|
+
...(resource && {
|
|
81
|
+
resource
|
|
82
|
+
})
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
class ExpressionListener extends Listener {
|
|
89
|
+
execute(message) {
|
|
90
|
+
const scope = this._getScope(message);
|
|
91
|
+
return {expression: this.environment.resolveExpression(this.extension.expression, scope)};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export default class ExecutionListeners {
|
|
96
|
+
constructor(activity, context) {
|
|
97
|
+
this.activity = activity;
|
|
98
|
+
this.context = context;
|
|
99
|
+
this.listeners = [];
|
|
100
|
+
this.onStart = false;
|
|
101
|
+
this.onEnd = false;
|
|
102
|
+
}
|
|
103
|
+
get length() {
|
|
104
|
+
return this.listeners.length;
|
|
105
|
+
}
|
|
106
|
+
add(extension, pos) {
|
|
107
|
+
const {event, script, expression} = extension;
|
|
108
|
+
if (!script && !expression) return;
|
|
109
|
+
|
|
110
|
+
const list = this.listeners;
|
|
111
|
+
if (script && (script.value || script.resource)) list.push(new ScriptListener(this.activity, this.context, extension, pos));
|
|
112
|
+
else if (expression) list.push(new ExpressionListener(this.activity, this.context, extension));
|
|
113
|
+
|
|
114
|
+
if (event === 'start') this.onStart = true;
|
|
115
|
+
if (event === 'end') this.onEnd = true;
|
|
116
|
+
}
|
|
117
|
+
async execute(event, message) {
|
|
118
|
+
const found = this.listeners.filter((l) => l.event === event);
|
|
119
|
+
const format = {};
|
|
120
|
+
for (const f of found) {
|
|
121
|
+
const result = await f.execute(message);
|
|
122
|
+
if (result !== null && typeof result === 'object') Object.assign(format, result);
|
|
123
|
+
}
|
|
124
|
+
return format;
|
|
125
|
+
}
|
|
126
|
+
}
|