@onify/flow-extensions 1.1.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 +11 -1
- package/dist/index.js +141 -104
- package/dist/src/Connector.js +2 -7
- package/dist/src/Errors.js +0 -3
- package/dist/src/ExecutionListeners.js +140 -0
- package/dist/src/FlowScripts.js +15 -37
- package/dist/src/IO.js +1 -36
- package/dist/src/IOForm.js +2 -10
- package/dist/src/IOProperties.js +0 -6
- package/dist/src/ServiceExpression.js +0 -4
- package/index.js +93 -28
- package/package.json +16 -16
- package/src/ExecutionListeners.js +126 -0
- package/src/IO.js +1 -1
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
|
|
|
@@ -72,26 +73,22 @@ class OnifyElementExtensions {
|
|
|
72
73
|
activity.behaviour.Service = Service;
|
|
73
74
|
}
|
|
74
75
|
}
|
|
75
|
-
activate() {
|
|
76
|
+
activate(message) {
|
|
76
77
|
const activity = this.activity;
|
|
77
78
|
const broker = activity.broker;
|
|
78
79
|
const formatQ = activity.broker.getQueue('format-run-q');
|
|
79
80
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
broker.publish('format', 'run.enter.complete', format, {persistent: false});
|
|
90
|
-
}, {consumerTag: '_onify-extension-on-enter'});
|
|
81
|
+
if (message.fields.redelivered && message.fields.routingKey === 'run.start') {
|
|
82
|
+
activity.on('start', (elementApi) => {
|
|
83
|
+
this._formatOnEnter(broker, formatQ, elementApi);
|
|
84
|
+
}, {consumerTag: '_onify-extension-on-enter'});
|
|
85
|
+
} else {
|
|
86
|
+
activity.on('enter', (elementApi) => {
|
|
87
|
+
this._formatOnEnter(broker, formatQ, elementApi);
|
|
88
|
+
}, {consumerTag: '_onify-extension-on-enter'});
|
|
89
|
+
}
|
|
91
90
|
|
|
92
91
|
activity.on('activity.execution.completed', async (elementApi) => {
|
|
93
|
-
if (elementApi.fields.redelivered) return;
|
|
94
|
-
|
|
95
92
|
formatQ.queueMessage({routingKey: 'run.end.format'}, {endRoutingKey: 'run.end.complete'}, {persistent: false});
|
|
96
93
|
|
|
97
94
|
try {
|
|
@@ -102,11 +99,52 @@ class OnifyElementExtensions {
|
|
|
102
99
|
|
|
103
100
|
broker.publish('format', 'run.end.complete', {...format}, {persistent: false});
|
|
104
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
|
+
}
|
|
105
130
|
}
|
|
106
131
|
deactivate() {
|
|
107
132
|
const broker = this.activity.broker;
|
|
108
133
|
broker.cancel('_onify-extension-on-enter');
|
|
109
134
|
broker.cancel('_onify-extension-on-executed');
|
|
135
|
+
broker.cancel('_onify-extension-on-listenerstart');
|
|
136
|
+
broker.cancel('_onify-extension-on-listenerend');
|
|
137
|
+
}
|
|
138
|
+
async _formatOnEnter(broker, formatQ, elementApi) {
|
|
139
|
+
formatQ.queueMessage({routingKey: 'run.enter.format'}, {endRoutingKey: 'run.enter.complete'}, {persistent: false});
|
|
140
|
+
|
|
141
|
+
try {
|
|
142
|
+
var format = await this._onEnter(elementApi);
|
|
143
|
+
} catch (err) {
|
|
144
|
+
return broker.publish('format', 'run.enter.error', {error: err}, {persistent: false});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
broker.publish('format', 'run.enter.complete', format, {persistent: false});
|
|
110
148
|
}
|
|
111
149
|
async _onEnter(elementApi) {
|
|
112
150
|
const {format, properties, io, form} = this.extensions;
|
|
@@ -178,7 +216,9 @@ function getExtensions(element, context) {
|
|
|
178
216
|
const extensions = element.behaviour.extensionElements?.values;
|
|
179
217
|
if (!extensions) return result;
|
|
180
218
|
|
|
219
|
+
const listeners = new ExtensionListeners(element, context);
|
|
181
220
|
|
|
221
|
+
let listener = 0;
|
|
182
222
|
for (const ext of extensions) {
|
|
183
223
|
switch (ext.$type) {
|
|
184
224
|
case 'camunda:Properties':
|
|
@@ -196,16 +236,21 @@ function getExtensions(element, context) {
|
|
|
196
236
|
result.Service = Connector.bind(Connector, connectorId, io);
|
|
197
237
|
break;
|
|
198
238
|
}
|
|
239
|
+
case 'camunda:ExecutionListener':
|
|
240
|
+
listeners.add(ext, listener++);
|
|
241
|
+
break;
|
|
199
242
|
}
|
|
200
243
|
}
|
|
201
244
|
|
|
245
|
+
if (listeners.length) result.listeners = listeners;
|
|
246
|
+
|
|
202
247
|
return result;
|
|
203
248
|
}
|
|
204
249
|
|
|
205
250
|
class FormatActivity {
|
|
206
251
|
constructor(activity) {
|
|
207
252
|
this.activity = activity;
|
|
208
|
-
this.resultVariable = activity.behaviour.resultVariable
|
|
253
|
+
this.resultVariable = activity.behaviour.resultVariable;
|
|
209
254
|
|
|
210
255
|
let timeCycles;
|
|
211
256
|
if (activity.eventDefinitions) {
|
|
@@ -246,7 +291,7 @@ class FormatActivity {
|
|
|
246
291
|
}
|
|
247
292
|
|
|
248
293
|
return {
|
|
249
|
-
resultVariable: this.resultVariable,
|
|
294
|
+
...(this.resultVariable && {resultVariable: this.resultVariable}),
|
|
250
295
|
...(scheduledStart && activity.parent.type === 'bpmn:Process' && {scheduledStart}),
|
|
251
296
|
...(user?.length && {candidateUsers: user}),
|
|
252
297
|
...(groups?.length && {candidateGroups: groups}),
|
|
@@ -270,13 +315,11 @@ class FormatProcess {
|
|
|
270
315
|
candidateStarterGroups,
|
|
271
316
|
} = bp.behaviour;
|
|
272
317
|
|
|
273
|
-
|
|
274
318
|
if (candidateStarterUsers) user = resolveAndSplit(elementApi, candidateStarterUsers);
|
|
275
319
|
if (candidateStarterGroups) groups = resolveAndSplit(elementApi, candidateStarterGroups);
|
|
276
320
|
if (documentation) description = documentation[0]?.text;
|
|
277
321
|
|
|
278
322
|
return {
|
|
279
|
-
resultVariable: this.resultVariable,
|
|
280
323
|
...(user?.length && {candidateStarterUsers: user}),
|
|
281
324
|
...(groups?.length && {candidateStarterGroups: groups}),
|
|
282
325
|
...(!elementApi.content.description && description && {description: elementApi.resolveExpression(description)}),
|
|
@@ -306,11 +349,20 @@ function extendFn(behaviour, context) {
|
|
|
306
349
|
|
|
307
350
|
if (!Array.isArray(behaviour.extensionElements?.values)) return;
|
|
308
351
|
|
|
309
|
-
|
|
310
|
-
const
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
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
|
+
}
|
|
314
366
|
}
|
|
315
367
|
|
|
316
368
|
function registerIOScripts(parentId, context, type, ioBehaviour) {
|
|
@@ -331,3 +383,16 @@ function registerIOScripts(parentId, context, type, ioBehaviour) {
|
|
|
331
383
|
});
|
|
332
384
|
}
|
|
333
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",
|
|
@@ -35,26 +35,26 @@
|
|
|
35
35
|
"license": "MIT",
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@aircall/expression-parser": "^1.0.4",
|
|
38
|
-
"@babel/cli": "^7.
|
|
39
|
-
"@babel/core": "^7.
|
|
40
|
-
"@babel/preset-env": "^7.
|
|
41
|
-
"@babel/register": "^7.18.
|
|
42
|
-
"bpmn-elements": "
|
|
43
|
-
"bpmn-engine": "^
|
|
44
|
-
"bpmn-
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
38
|
+
"@babel/cli": "^7.19.3",
|
|
39
|
+
"@babel/core": "^7.20.2",
|
|
40
|
+
"@babel/preset-env": "^7.20.2",
|
|
41
|
+
"@babel/register": "^7.18.9",
|
|
42
|
+
"bpmn-elements-8-1": "npm:bpmn-elements@8.1",
|
|
43
|
+
"bpmn-engine": "^15.1.2",
|
|
44
|
+
"bpmn-engine-14": "npm:bpmn-engine@14",
|
|
45
|
+
"bpmn-moddle": "^7.1.3",
|
|
46
|
+
"c8": "^7.12.0",
|
|
47
|
+
"camunda-bpmn-moddle": "^7.0.1",
|
|
48
|
+
"chai": "^4.3.7",
|
|
48
49
|
"chronokinesis": "^3.1.2",
|
|
49
50
|
"debug": "^4.3.4",
|
|
50
|
-
"eslint": "^
|
|
51
|
-
"mocha": "^10.
|
|
51
|
+
"eslint": "^8.28.0",
|
|
52
|
+
"mocha": "^10.1.0",
|
|
52
53
|
"mocha-cakes-2": "^3.3.0",
|
|
53
|
-
"moddle-context-serializer": "^2.1.0"
|
|
54
|
-
"nock": "^13.2.8"
|
|
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
|
+
}
|