@onify/flow-extensions 2.0.0 → 4.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 +38 -0
- package/dist/index.js +42 -351
- package/dist/src/Connector.js +2 -2
- package/dist/src/Errors.js +12 -2
- package/dist/src/ExecutionListeners.js +140 -0
- package/dist/src/FlowScripts.js +9 -4
- package/dist/src/IO.js +76 -77
- package/dist/src/OnifyElementExtensions.js +223 -0
- package/dist/src/OnifyProcessExtensions.js +51 -0
- package/dist/src/ServiceExpression.js +1 -1
- package/dist/src/formatters.js +112 -0
- package/dist/src/getExtensions.js +54 -0
- package/index.js +32 -299
- package/package.json +9 -9
- package/src/Connector.js +1 -1
- package/src/Errors.js +8 -4
- package/src/ExecutionListeners.js +126 -0
- package/src/IO.js +67 -75
- package/src/OnifyElementExtensions.js +150 -0
- package/src/OnifyProcessExtensions.js +40 -0
- package/src/ServiceExpression.js +1 -1
- package/src/formatters.js +97 -0
- package/src/getExtensions.js +49 -0
package/index.js
CHANGED
|
@@ -1,19 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import IOForm from './src/IOForm';
|
|
4
|
-
import Connector from './src/Connector';
|
|
5
|
-
import ServiceExpression from './src/ServiceExpression';
|
|
6
|
-
import {InputOutput} from './src/IO';
|
|
7
|
-
|
|
8
|
-
const iso8601cycle = /^\s*(R\d+\/)?P\w+/i;
|
|
9
|
-
|
|
10
|
-
class FormatError extends Error {
|
|
11
|
-
constructor(elementId, err) {
|
|
12
|
-
super(`<${elementId}> ${err.message}`);
|
|
13
|
-
this.code = 'EFLOW_FORMAT';
|
|
14
|
-
this.output = {statusCode: 500};
|
|
15
|
-
}
|
|
16
|
-
}
|
|
1
|
+
import {OnifyProcessExtensions} from './src/OnifyProcessExtensions.js';
|
|
2
|
+
import {OnifyElementExtensions} from './src/OnifyElementExtensions.js';
|
|
17
3
|
|
|
18
4
|
export {
|
|
19
5
|
extensions,
|
|
@@ -25,297 +11,28 @@ function extensions(element, context) {
|
|
|
25
11
|
return new OnifyElementExtensions(element, context);
|
|
26
12
|
}
|
|
27
13
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
this.extensions = getExtensions(bp, context);
|
|
33
|
-
this._activate();
|
|
34
|
-
}
|
|
35
|
-
_activate() {
|
|
36
|
-
const bp = this.process;
|
|
37
|
-
bp.on('process.enter', (elementApi) => {
|
|
38
|
-
try {
|
|
39
|
-
const result = this._onEnter(elementApi);
|
|
40
|
-
const environment = elementApi.environment;
|
|
41
|
-
environment.assignVariables(result);
|
|
42
|
-
} catch (err) {
|
|
43
|
-
elementApi.broker.publish('event', 'process.error', {
|
|
44
|
-
...elementApi.content,
|
|
45
|
-
error: new FormatError(bp.id, err)
|
|
46
|
-
}, {mandatory: true, type: 'error'});
|
|
47
|
-
}
|
|
48
|
-
}, {consumerTag: '_onify-extension-on-enter'});
|
|
49
|
-
}
|
|
50
|
-
_onEnter(elementApi) {
|
|
51
|
-
const {format, properties} = this.extensions;
|
|
52
|
-
const result = {};
|
|
53
|
-
|
|
54
|
-
Object.assign(result, format.resolve(elementApi));
|
|
55
|
-
Object.assign(elementApi.content, result);
|
|
56
|
-
|
|
57
|
-
if (properties) {
|
|
58
|
-
Object.assign(result, properties.resolve(elementApi));
|
|
59
|
-
Object.assign(elementApi.content, result);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return result;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
class OnifyElementExtensions {
|
|
67
|
-
constructor(activity, context) {
|
|
68
|
-
this.activity = activity;
|
|
69
|
-
this.context = context;
|
|
70
|
-
const {Service} = this.extensions = getExtensions(activity, context);
|
|
71
|
-
if (Service) {
|
|
72
|
-
activity.behaviour.Service = Service;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
activate(message) {
|
|
76
|
-
const activity = this.activity;
|
|
77
|
-
const broker = activity.broker;
|
|
78
|
-
const formatQ = activity.broker.getQueue('format-run-q');
|
|
79
|
-
|
|
80
|
-
if (message.fields.redelivered && message.fields.routingKey === 'run.start') {
|
|
81
|
-
activity.on('start', (elementApi) => {
|
|
82
|
-
this._formatOnEnter(broker, formatQ, elementApi);
|
|
83
|
-
}, {consumerTag: '_onify-extension-on-enter'});
|
|
84
|
-
} else {
|
|
85
|
-
activity.on('enter', (elementApi) => {
|
|
86
|
-
this._formatOnEnter(broker, formatQ, elementApi);
|
|
87
|
-
}, {consumerTag: '_onify-extension-on-enter'});
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
activity.on('activity.execution.completed', async (elementApi) => {
|
|
91
|
-
formatQ.queueMessage({routingKey: 'run.end.format'}, {endRoutingKey: 'run.end.complete'}, {persistent: false});
|
|
92
|
-
|
|
93
|
-
try {
|
|
94
|
-
var format = await this._onExecuted(elementApi);
|
|
95
|
-
} catch (err) {
|
|
96
|
-
return broker.publish('format', 'run.end.error', {error: err}, {persistent: false});
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
broker.publish('format', 'run.end.complete', {...format}, {persistent: false});
|
|
100
|
-
}, {consumerTag: '_onify-extension-on-executed'});
|
|
101
|
-
}
|
|
102
|
-
deactivate() {
|
|
103
|
-
const broker = this.activity.broker;
|
|
104
|
-
broker.cancel('_onify-extension-on-enter');
|
|
105
|
-
broker.cancel('_onify-extension-on-executed');
|
|
106
|
-
}
|
|
107
|
-
async _formatOnEnter(broker, formatQ, elementApi) {
|
|
108
|
-
formatQ.queueMessage({routingKey: 'run.enter.format'}, {endRoutingKey: 'run.enter.complete'}, {persistent: false});
|
|
109
|
-
|
|
110
|
-
try {
|
|
111
|
-
var format = await this._onEnter(elementApi);
|
|
112
|
-
} catch (err) {
|
|
113
|
-
return broker.publish('format', 'run.enter.error', {error: err}, {persistent: false});
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
broker.publish('format', 'run.enter.complete', format, {persistent: false});
|
|
117
|
-
}
|
|
118
|
-
async _onEnter(elementApi) {
|
|
119
|
-
const {format, properties, io, form} = this.extensions;
|
|
120
|
-
|
|
121
|
-
const result = {};
|
|
122
|
-
Object.assign(result, format.resolve(elementApi));
|
|
123
|
-
Object.assign(elementApi.content, result);
|
|
124
|
-
|
|
125
|
-
if (properties) {
|
|
126
|
-
Object.assign(result, {properties: properties.resolve(elementApi)});
|
|
127
|
-
Object.assign(elementApi.content, result);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if (io) {
|
|
131
|
-
if (io.input?.length) {
|
|
132
|
-
const input = await io.getInput(this.activity, elementApi);
|
|
133
|
-
Object.assign(result, {input});
|
|
134
|
-
Object.assign(elementApi.content, result);
|
|
135
|
-
}
|
|
136
|
-
if (io.output?.length) {
|
|
137
|
-
result.assignToOutput = true;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
if (form) {
|
|
142
|
-
Object.assign(result, {form: form.resolve(elementApi)});
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
return result;
|
|
146
|
-
}
|
|
147
|
-
async _onExecuted(elementApi) {
|
|
148
|
-
const {properties, io} = this.extensions;
|
|
149
|
-
|
|
150
|
-
const result = {};
|
|
151
|
-
if (io?.output.length) {
|
|
152
|
-
const output = await io.getOutput(this.activity, elementApi);
|
|
153
|
-
Object.assign(result, {output});
|
|
154
|
-
Object.assign(elementApi.content, {output});
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
if (properties) {
|
|
158
|
-
const props = properties.resolve(elementApi);
|
|
159
|
-
Object.assign(result, {properties: props});
|
|
160
|
-
Object.assign(elementApi.content, {properties: props});
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const {output, assignToOutput, resultVariable} = elementApi.content;
|
|
164
|
-
|
|
165
|
-
if (output === undefined || output === null) return result;
|
|
166
|
-
|
|
167
|
-
if (assignToOutput && typeof output === 'object') {
|
|
168
|
-
Object.assign(this.activity.environment.output, output);
|
|
169
|
-
} else if (resultVariable) {
|
|
170
|
-
elementApi.environment.output[resultVariable] = output;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
return result;
|
|
14
|
+
function extendFn(behaviour, context) {
|
|
15
|
+
if (behaviour.$type === 'bpmn:StartEvent' && behaviour.eventDefinitions) {
|
|
16
|
+
const timer = behaviour.eventDefinitions.find(({type, behaviour: edBehaviour}) => edBehaviour && type === 'bpmn:TimerEventDefinition');
|
|
17
|
+
if (timer && timer.behaviour.timeCycle) Object.assign(behaviour, {scheduledStart: timer.behaviour.timeCycle});
|
|
174
18
|
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
function getExtensions(element, context) {
|
|
178
|
-
const result = {
|
|
179
|
-
format: element.type === 'bpmn:Process' ? new FormatProcess(element) : new FormatActivity(element),
|
|
180
|
-
};
|
|
181
19
|
|
|
182
|
-
|
|
183
|
-
if (expression) result.Service = ServiceExpression;
|
|
184
|
-
|
|
185
|
-
const extensions = element.behaviour.extensionElements?.values;
|
|
186
|
-
if (!extensions) return result;
|
|
20
|
+
if (!Array.isArray(behaviour.extensionElements?.values)) return;
|
|
187
21
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
if (ext.values?.length) result.properties = new IOProperties(element, ext);
|
|
192
|
-
break;
|
|
22
|
+
let listener = 0;
|
|
23
|
+
for (const extension of behaviour.extensionElements.values) {
|
|
24
|
+
switch (extension.$type) {
|
|
193
25
|
case 'camunda:InputOutput':
|
|
194
|
-
|
|
26
|
+
registerIOScripts(behaviour.id, context, extension.$type, extension);
|
|
195
27
|
break;
|
|
196
|
-
case 'camunda:
|
|
197
|
-
|
|
28
|
+
case 'camunda:Connector':
|
|
29
|
+
registerIOScripts(behaviour.id, context, extension.$type, extension.inputOutput);
|
|
198
30
|
break;
|
|
199
|
-
case 'camunda:
|
|
200
|
-
|
|
201
|
-
const io = inputOutput && new InputOutput(`${element.id}/${ext.$type.toLowerCase()}`, inputOutput, context);
|
|
202
|
-
result.Service = Connector.bind(Connector, connectorId, io);
|
|
31
|
+
case 'camunda:ExecutionListener':
|
|
32
|
+
registerListenerScript(behaviour.id, context, extension.$type, extension, listener++);
|
|
203
33
|
break;
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
return result;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
class FormatActivity {
|
|
212
|
-
constructor(activity) {
|
|
213
|
-
this.activity = activity;
|
|
214
|
-
this.resultVariable = activity.behaviour.resultVariable || '_' + activity.id;
|
|
215
|
-
|
|
216
|
-
let timeCycles;
|
|
217
|
-
if (activity.eventDefinitions) {
|
|
218
|
-
for (const ed of activity.eventDefinitions.filter((e) => e.type === 'bpmn:TimerEventDefinition')) {
|
|
219
|
-
if (!('timeCycle' in ed)) continue;
|
|
220
|
-
timeCycles = timeCycles || [];
|
|
221
|
-
timeCycles.push(ed.timeCycle);
|
|
222
|
-
}
|
|
223
34
|
}
|
|
224
|
-
this.timeCycles = timeCycles;
|
|
225
|
-
}
|
|
226
|
-
resolve(elementApi) {
|
|
227
|
-
let user, groups, assigneeValue, description;
|
|
228
|
-
const activity = this.activity;
|
|
229
|
-
const {
|
|
230
|
-
documentation,
|
|
231
|
-
candidateUsers,
|
|
232
|
-
candidateGroups,
|
|
233
|
-
scheduledStart,
|
|
234
|
-
assignee,
|
|
235
|
-
} = activity.behaviour;
|
|
236
|
-
|
|
237
|
-
if (candidateUsers) user = resolveAndSplit(elementApi, candidateUsers);
|
|
238
|
-
if (candidateGroups) groups = resolveAndSplit(elementApi, candidateGroups);
|
|
239
|
-
if (assignee) assigneeValue = elementApi.resolveExpression(assignee);
|
|
240
|
-
if (documentation) description = documentation[0]?.text;
|
|
241
|
-
|
|
242
|
-
let expireAt;
|
|
243
|
-
let timeCycles = this.timeCycles;
|
|
244
|
-
if (timeCycles) {
|
|
245
|
-
for (const cycle of timeCycles) {
|
|
246
|
-
const cron = elementApi.resolveExpression(cycle);
|
|
247
|
-
if (!cron || iso8601cycle.test(cron)) continue;
|
|
248
|
-
|
|
249
|
-
const expireAtDt = cronParser.parseExpression(cron).next().toDate();
|
|
250
|
-
if (!expireAt || expireAtDt < expireAt) expireAt = expireAtDt;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
return {
|
|
255
|
-
resultVariable: this.resultVariable,
|
|
256
|
-
...(scheduledStart && activity.parent.type === 'bpmn:Process' && {scheduledStart}),
|
|
257
|
-
...(user?.length && {candidateUsers: user}),
|
|
258
|
-
...(groups?.length && {candidateGroups: groups}),
|
|
259
|
-
...(!elementApi.content.description && description && {description: elementApi.resolveExpression(description)}),
|
|
260
|
-
...(expireAt && {expireAt}),
|
|
261
|
-
...(assigneeValue && {assignee: assigneeValue}),
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
class FormatProcess {
|
|
267
|
-
constructor(bp) {
|
|
268
|
-
this.process = bp;
|
|
269
|
-
}
|
|
270
|
-
resolve(elementApi) {
|
|
271
|
-
let user, groups, description;
|
|
272
|
-
const bp = this.process;
|
|
273
|
-
const {
|
|
274
|
-
documentation,
|
|
275
|
-
candidateStarterUsers,
|
|
276
|
-
candidateStarterGroups,
|
|
277
|
-
} = bp.behaviour;
|
|
278
|
-
|
|
279
|
-
if (candidateStarterUsers) user = resolveAndSplit(elementApi, candidateStarterUsers);
|
|
280
|
-
if (candidateStarterGroups) groups = resolveAndSplit(elementApi, candidateStarterGroups);
|
|
281
|
-
if (documentation) description = documentation[0]?.text;
|
|
282
|
-
|
|
283
|
-
return {
|
|
284
|
-
resultVariable: this.resultVariable,
|
|
285
|
-
...(user?.length && {candidateStarterUsers: user}),
|
|
286
|
-
...(groups?.length && {candidateStarterGroups: groups}),
|
|
287
|
-
...(!elementApi.content.description && description && {description: elementApi.resolveExpression(description)}),
|
|
288
|
-
};
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
function resolveAndSplit(elementApi, str) {
|
|
293
|
-
if (Array.isArray(str)) return str.filter(Boolean);
|
|
294
|
-
if (typeof str !== 'string') return;
|
|
295
|
-
|
|
296
|
-
const resolved = elementApi.resolveExpression(str);
|
|
297
|
-
if (Array.isArray(resolved)) return resolved.filter(Boolean);
|
|
298
|
-
if (typeof resolved !== 'string') return;
|
|
299
|
-
|
|
300
|
-
return resolved
|
|
301
|
-
.split(',')
|
|
302
|
-
.map((g) => g.trim && g.trim().toLowerCase())
|
|
303
|
-
.filter(Boolean);
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
function extendFn(behaviour, context) {
|
|
307
|
-
if (behaviour.$type === 'bpmn:StartEvent' && behaviour.eventDefinitions) {
|
|
308
|
-
const timer = behaviour.eventDefinitions.find(({type, behaviour: edBehaviour}) => edBehaviour && type === 'bpmn:TimerEventDefinition');
|
|
309
|
-
if (timer && timer.behaviour.timeCycle) Object.assign(behaviour, {scheduledStart: timer.behaviour.timeCycle});
|
|
310
35
|
}
|
|
311
|
-
|
|
312
|
-
if (!Array.isArray(behaviour.extensionElements?.values)) return;
|
|
313
|
-
|
|
314
|
-
const inputOutput = behaviour.extensionElements.values.find((el) => el.$type === 'camunda:InputOutput');
|
|
315
|
-
const connector = behaviour.extensionElements.values.find((el) => el.$type === 'camunda:Connector');
|
|
316
|
-
|
|
317
|
-
if (inputOutput) registerIOScripts(behaviour.id, context, inputOutput.$type, inputOutput);
|
|
318
|
-
if (connector) registerIOScripts(behaviour.id, context, connector.$type, connector.inputOutput);
|
|
319
36
|
}
|
|
320
37
|
|
|
321
38
|
function registerIOScripts(parentId, context, type, ioBehaviour) {
|
|
@@ -326,13 +43,29 @@ function registerIOScripts(parentId, context, type, ioBehaviour) {
|
|
|
326
43
|
if (!definition) continue;
|
|
327
44
|
if (definition.$type !== 'camunda:Script') continue;
|
|
328
45
|
|
|
329
|
-
const
|
|
46
|
+
const ioType = `${type}/${$type}`;
|
|
47
|
+
const filename = `${parentId}/${ioType}/${name}`;
|
|
330
48
|
|
|
331
49
|
context.addScript(filename, {
|
|
332
50
|
id: filename,
|
|
333
51
|
scriptFormat: definition.scriptFormat,
|
|
52
|
+
type: ioType,
|
|
334
53
|
...(definition.value && {body: definition.value}),
|
|
335
54
|
...(definition.resource && {resource: definition.resource}),
|
|
336
55
|
});
|
|
337
56
|
}
|
|
338
57
|
}
|
|
58
|
+
|
|
59
|
+
function registerListenerScript(parentId, context, type, listener, pos) {
|
|
60
|
+
const {event, script} = listener;
|
|
61
|
+
if (!script) return;
|
|
62
|
+
|
|
63
|
+
const id = `${parentId}/${type}/${event}/${pos}`;
|
|
64
|
+
context.addScript(id, {
|
|
65
|
+
id,
|
|
66
|
+
scriptFormat: script.scriptFormat,
|
|
67
|
+
type,
|
|
68
|
+
...(script.value && {body: script.value}),
|
|
69
|
+
...(script.resource && {resource: script.resource}),
|
|
70
|
+
});
|
|
71
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onify/flow-extensions",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.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.20.
|
|
38
|
+
"@babel/cli": "^7.20.7",
|
|
39
|
+
"@babel/core": "^7.20.12",
|
|
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",
|
|
47
47
|
"camunda-bpmn-moddle": "^7.0.1",
|
|
48
48
|
"chai": "^4.3.7",
|
|
49
|
-
"chronokinesis": "^
|
|
49
|
+
"chronokinesis": "^4.0.1",
|
|
50
50
|
"debug": "^4.3.4",
|
|
51
|
-
"eslint": "^8.
|
|
52
|
-
"mocha": "^10.
|
|
51
|
+
"eslint": "^8.32.0",
|
|
52
|
+
"mocha": "^10.2.0",
|
|
53
53
|
"mocha-cakes-2": "^3.3.0",
|
|
54
|
-
"moddle-context-serializer": "^
|
|
54
|
+
"moddle-context-serializer": "^3.1.1"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"cron-parser": "^4.
|
|
57
|
+
"cron-parser": "^4.7.1"
|
|
58
58
|
},
|
|
59
59
|
"files": [
|
|
60
60
|
"src",
|
package/src/Connector.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {NotImplemented} from './Errors';
|
|
1
|
+
import {NotImplemented} from './Errors.js';
|
|
2
2
|
|
|
3
3
|
export default function Connector(connectorId, io, activity, executionMessage) {
|
|
4
4
|
if (!(this instanceof Connector)) return new Connector(connectorId, io, activity, executionMessage);
|
package/src/Errors.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
class NotImplemented extends Error {
|
|
1
|
+
export class NotImplemented extends Error {
|
|
2
2
|
constructor(serviceId) {
|
|
3
3
|
super(`${serviceId} service function not found`);
|
|
4
4
|
this.code = 'EFLOW_NOT_IMPLEMENTED';
|
|
@@ -6,6 +6,10 @@ class NotImplemented extends Error {
|
|
|
6
6
|
}
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
export {
|
|
10
|
-
|
|
11
|
-
};
|
|
9
|
+
export class FormatError extends Error {
|
|
10
|
+
constructor(elementId, err) {
|
|
11
|
+
super(`<${elementId}> ${err.message}`);
|
|
12
|
+
this.code = 'EFLOW_FORMAT';
|
|
13
|
+
this.output = {statusCode: 500};
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -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
|
+
}
|