react 0.3.0 → 0.5.1
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/.npmignore +2 -1
- package/README.md +99 -155
- package/doc/advanced.md +166 -0
- package/doc/color-def.graffle +938 -0
- package/doc/color-def.png +0 -0
- package/doc/default-simple.dot +19 -0
- package/doc/default-simple.dot.png +0 -0
- package/examples/{default1.js → longer-example.js} +0 -0
- package/examples/simple.js +45 -0
- package/examples/{ast1.js → using-ast-directly.js} +4 -0
- package/examples/using-events1.js +79 -0
- package/examples/{default-events1.js → using-log-events.js} +5 -14
- package/lib/base-task.js +7 -6
- package/lib/core.js +33 -14
- package/lib/event-collector.js +68 -0
- package/lib/event-manager.js +16 -13
- package/lib/finalcb-first-task.js +14 -11
- package/lib/finalcb-task.js +15 -11
- package/lib/id.js +1 -0
- package/lib/log-events.js +86 -0
- package/{promise-resolve.js → lib/promise-resolve.js} +5 -5
- package/lib/task.js +18 -8
- package/lib/track-tasks.js +60 -0
- package/lib/vcon.js +1 -1
- package/package.json +2 -2
- package/react.js +33 -1
- package/test/ast.test.js +27 -1
- package/test/core.test.js +71 -57
- package/test/dsl.test.js +2 -2
- package/test/module-use.test.js +14 -9
- package/test/promise-auto-resolve.test.js +2 -1
- package/Jakefile.js +0 -8
- package/dsl/chain.js +0 -150
- package/dsl/fstr.js +0 -121
- package/dsl/pcode.js +0 -175
- package/examples/chain-events1.js +0 -34
- package/examples/chain1.js +0 -19
- package/examples/fstr-events1.js +0 -52
- package/examples/fstr1.js +0 -37
- package/examples/pcode1.js +0 -22
- package/jake-tasks/jake-test.js +0 -64
- package/test/dsl/chain.test.js +0 -323
- package/test/dsl/fstr.test.js +0 -300
- package/test/dsl/pcode.test.js +0 -456
|
Binary file
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
digraph simple {
|
|
2
|
+
inputs [shape=box];
|
|
3
|
+
loadFoo [shape=box];
|
|
4
|
+
loadBar [shape=box];
|
|
5
|
+
render [shape=box];
|
|
6
|
+
outputs[shape=box];
|
|
7
|
+
inputs -> fooPath;
|
|
8
|
+
inputs -> barPath;
|
|
9
|
+
inputs -> barP2;
|
|
10
|
+
fooPath -> loadFoo;
|
|
11
|
+
loadFoo -> foo;
|
|
12
|
+
barPath -> loadBar;
|
|
13
|
+
loadBar -> bar;
|
|
14
|
+
barP2 -> loadBar;
|
|
15
|
+
foo -> render;
|
|
16
|
+
bar -> render;
|
|
17
|
+
render -> renderedOut;
|
|
18
|
+
renderedOut -> outputs;
|
|
19
|
+
}
|
|
Binary file
|
|
File without changes
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
Simple example showing flow definition of two async functions feeding a
|
|
5
|
+
synchronous function.
|
|
6
|
+
|
|
7
|
+
First two async functions inputs are satisfied by the flow inputs, so
|
|
8
|
+
they will both run immediately in parallel.
|
|
9
|
+
|
|
10
|
+
The last function waits for the outputs of the previous ones, then
|
|
11
|
+
executes synchronously.
|
|
12
|
+
|
|
13
|
+
Finally the flow calls the callback with the output values once all
|
|
14
|
+
the tasks have completed.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
var react = require('../'); // require('react');
|
|
18
|
+
|
|
19
|
+
function loadFoo(fooPath, cb) {
|
|
20
|
+
setTimeout(function () {
|
|
21
|
+
cb(null, [fooPath, 'data'].join(':'));
|
|
22
|
+
}, 10);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function loadBar(barPath, barP2, cb) {
|
|
26
|
+
setTimeout(function () {
|
|
27
|
+
cb(null, [barPath, barP2, 'data'].join(':'));
|
|
28
|
+
}, 10);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function render(foo, bar) {
|
|
32
|
+
return ['<html>', foo, '/', bar, '</html>'].join('');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
var fn = react('loadRender', 'fooPath, barPath, barP2, cb -> err, renderedOut',
|
|
37
|
+
loadFoo, 'fooPath, cb -> err, foo',
|
|
38
|
+
loadBar, 'barPath, barP2, cb -> err, bar',
|
|
39
|
+
render, 'foo, bar -> renderedOut'
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
fn('foo.txt', 'bar.txt', 'BBB', function (err, renderedOut) {
|
|
44
|
+
console.error('results:', renderedOut);
|
|
45
|
+
});
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
Advanced example using the AST directly which most users will not do.
|
|
5
|
+
For general use, see other examples like simple.js
|
|
6
|
+
*/
|
|
3
7
|
var react = require('../'); // require('react');
|
|
4
8
|
|
|
5
9
|
function load(res, cb) { setTimeout(cb, 100, null, res + '-loaded'); }
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/*jshint white: false */
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
Default DSL, showing use of events
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
var react = require('../'); // require('react');
|
|
9
|
+
require('../lib/track-tasks'); // require('react/lib/track-tasks'); // turn on tracking
|
|
10
|
+
|
|
11
|
+
//output events as tasks start and complete
|
|
12
|
+
react.events.on('flow.*', function (obj) {
|
|
13
|
+
/*jshint validthis: true */
|
|
14
|
+
var time = new Date();
|
|
15
|
+
time.setTime(obj.time);
|
|
16
|
+
var argsNoCb = obj.args.filter(function (a) { return (typeof(a) !== 'function'); });
|
|
17
|
+
var eventTimeStr = time.toISOString();
|
|
18
|
+
if (this.event === 'flow.complete') {
|
|
19
|
+
var env = obj;
|
|
20
|
+
console.error('%s: %s \tmsecs:(%s) \n\targs:(%s) \n\tresults:(%s)\n',
|
|
21
|
+
this.event, env.name, env.elapsedTime, argsNoCb, env.results);
|
|
22
|
+
} else {
|
|
23
|
+
var name = obj.name;
|
|
24
|
+
var args = obj.args;
|
|
25
|
+
console.error('%s: %s \n\targs:(%s)\n', this.event, name, argsNoCb);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
react.events.on('task.*', function (obj) {
|
|
30
|
+
/*jshint validthis: true */
|
|
31
|
+
var time = new Date();
|
|
32
|
+
time.setTime(obj.time);
|
|
33
|
+
var argsNoCb = obj.args.filter(function (a) { return (typeof(a) !== 'function'); });
|
|
34
|
+
var eventTimeStr = time.toISOString();
|
|
35
|
+
if (this.event === 'task.complete') {
|
|
36
|
+
var task = obj;
|
|
37
|
+
console.error('%s: %s \tmsecs:(%s) \n\targs:(%s) \n\tresults:(%s)\n',
|
|
38
|
+
this.event, task.name, task.elapsedTime, argsNoCb, task.results);
|
|
39
|
+
} else {
|
|
40
|
+
var name = obj.name;
|
|
41
|
+
var args = obj.args;
|
|
42
|
+
console.error('%s: %s \n\targs:(%s)\n', this.event, name, argsNoCb);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
function loadUser(uid, cb){ setTimeout(cb, 100, null, "User"+uid); }
|
|
49
|
+
function loadFile(filename, cb){ setTimeout(cb, 100, null, 'Filedata'+filename); }
|
|
50
|
+
function markdown(filedata) { return 'html'+filedata; }
|
|
51
|
+
function prepareDirectory(outDirname, cb){ setTimeout(cb, 200, null, 'dircreated-'+outDirname); }
|
|
52
|
+
function writeOutput(html, user, cb){ setTimeout(cb, 300, null, html+'_bytesWritten'); }
|
|
53
|
+
function loadEmailTemplate(cb) { setTimeout(cb, 50, null, 'emailmd'); }
|
|
54
|
+
function customizeEmail(user, emailHtml) { return 'cust-'+user+emailHtml; }
|
|
55
|
+
function deliverEmail(custEmailHtml, cb) { setTimeout(cb, 100, null, 'delivered-'+custEmailHtml); }
|
|
56
|
+
|
|
57
|
+
function useHtml(err, html, user, bytesWritten) {
|
|
58
|
+
if (err) {
|
|
59
|
+
console.log('***Error: %s', err);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
console.log('final result: %s, user: %s, written:%s', html, user, bytesWritten);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
var loadAndSave = react('loadAndSave', 'filename, uid, outDirname, cb -> err, html, user, bytesWritten', // name, in/out params
|
|
66
|
+
loadUser, 'uid, cb -> err, user', // calling async fn loadUser with uid, callback is called with err and user
|
|
67
|
+
loadFile, 'filename, cb -> err, filedata',
|
|
68
|
+
markdown, 'filedata -> html', // using a sync function
|
|
69
|
+
prepareDirectory, 'outDirname, cb -> err, dircreated',
|
|
70
|
+
writeOutput, 'html, user, cb -> err, bytesWritten', { after: prepareDirectory }, // only after prepareDirectory done
|
|
71
|
+
loadEmailTemplate, 'cb -> err, emailmd',
|
|
72
|
+
markdown, 'emailmd -> emailHtml', // using a sync function
|
|
73
|
+
customizeEmail, 'user, emailHtml -> custEmailHtml', // sync fn
|
|
74
|
+
deliverEmail, 'custEmailHtml, cb -> err, deliveredEmail', { after: writeOutput } // only after writeOutput is done
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
loadAndSave('file.md', 100, '/tmp/foo', useHtml); // executing the flow
|
|
78
|
+
|
|
79
|
+
|
|
@@ -1,22 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
/*jshint white: false */
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
Default DSL, showing use of events
|
|
6
|
+
*/
|
|
7
|
+
|
|
4
8
|
var react = require('../'); // require('react');
|
|
9
|
+
react.logEvents(); // turn on logging of all flow and task events for all react functions
|
|
5
10
|
|
|
6
|
-
//output events as tasks start and complete
|
|
7
|
-
react.events.on('task.*', function (obj) {
|
|
8
|
-
var time = new Date();
|
|
9
|
-
time.setTime(obj.time);
|
|
10
|
-
var eventTimeStr = time.toISOString();
|
|
11
|
-
var argsNoCb = obj.args.filter(function (a) { return (typeof(a) !== 'function'); });
|
|
12
|
-
if (obj.event === 'task.complete') {
|
|
13
|
-
console.error('%s: %s \tmsecs:(%s) \n\targs:(%s) \n\tresults:(%s)\n',
|
|
14
|
-
obj.event, obj.name, obj.elapsedTime, argsNoCb, obj.results);
|
|
15
|
-
} else {
|
|
16
|
-
console.error('%s: %s \n\targs:(%s)\n', obj.event, obj.name, argsNoCb);
|
|
17
|
-
}
|
|
18
|
-
});
|
|
19
|
-
|
|
20
11
|
|
|
21
12
|
function loadUser(uid, cb){ setTimeout(cb, 100, null, "User"+uid); }
|
|
22
13
|
function loadFile(filename, cb){ setTimeout(cb, 100, null, 'Filedata'+filename); }
|
package/lib/base-task.js
CHANGED
|
@@ -19,17 +19,18 @@ BaseTask.prototype.isComplete = function () {
|
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
BaseTask.prototype.start = function (args) { // mark task as started with args and note time
|
|
22
|
+
/*jshint validthis: true */
|
|
22
23
|
this.args = args;
|
|
23
|
-
this.
|
|
24
|
-
|
|
24
|
+
this.env.currentTask = this;
|
|
25
|
+
this.env.flowEmitter.emit(EventManager.TYPES.EXEC_TASK_START, this);
|
|
25
26
|
};
|
|
26
27
|
|
|
27
28
|
BaseTask.prototype.complete = function (args) { //args that were used are available
|
|
28
|
-
|
|
29
|
-
this.endTime = Date.now();
|
|
30
|
-
this.elapsedTime = this.endTime - this.startTime;
|
|
31
|
-
if (this.flowEmitter) this.flowEmitter.emitObject(EventManager.TYPES.TASK_COMPLETE, this);
|
|
29
|
+
/*jshint validthis: true */
|
|
32
30
|
this.status = STATUS.COMPLETE;
|
|
31
|
+
this.results = args;
|
|
32
|
+
this.env.currentTask = this;
|
|
33
|
+
this.env.flowEmitter.emit(EventManager.TYPES.EXEC_TASK_COMPLETE, this);
|
|
33
34
|
};
|
|
34
35
|
|
|
35
36
|
BaseTask.prototype.functionExists = function (vCon) {
|
package/lib/core.js
CHANGED
|
@@ -10,6 +10,7 @@ var VContext = require('./vcon.js');
|
|
|
10
10
|
var EventManager = require('./event-manager.js');
|
|
11
11
|
var inputParser = require('./input-parser.js');
|
|
12
12
|
var idGenerator = require('./id.js');
|
|
13
|
+
var sprintf = require('sprintf').sprintf;
|
|
13
14
|
|
|
14
15
|
var reactOptions = {
|
|
15
16
|
stackTraceLimitMin: 30
|
|
@@ -27,6 +28,13 @@ function mergeOptions(parsedOptions) {
|
|
|
27
28
|
}, parsedOptions);
|
|
28
29
|
}
|
|
29
30
|
|
|
31
|
+
/**
|
|
32
|
+
generate a flow name when one is not provided
|
|
33
|
+
*/
|
|
34
|
+
function generateFlowName() {
|
|
35
|
+
return sprintf('flow_%s', idGenerator.createUniqueId());
|
|
36
|
+
}
|
|
37
|
+
|
|
30
38
|
/**
|
|
31
39
|
Creates react function which the AST can be manipulated and then
|
|
32
40
|
is ready to be executed. Can be used directly or a DSL can wrap this
|
|
@@ -64,44 +72,55 @@ function reactFactory() {
|
|
|
64
72
|
function setAndValidateAST(newAST) { //set AST then validate, ret error[]
|
|
65
73
|
Object.keys(newAST).forEach(function (k) { ast[k] = newAST[k]; }); // copy all properties
|
|
66
74
|
var errors = validate(ast);
|
|
67
|
-
if (!errors.length)
|
|
75
|
+
if (!errors.length) {
|
|
76
|
+
if (!ast.name) ast.name = generateFlowName();
|
|
77
|
+
tskutil.nameTasks(ast.tasks); //run this so names can be checked in ast
|
|
78
|
+
}
|
|
68
79
|
if (Object.freeze) { //lets freeze the AST so plugin writers don't accidentally manip the ast
|
|
69
80
|
Object.keys(newAST).forEach(function (k) {
|
|
70
81
|
if (typeof(newAST[k]) === 'object') Object.freeze(newAST[k]);
|
|
71
82
|
});
|
|
72
83
|
Object.freeze(newAST);
|
|
73
84
|
}
|
|
85
|
+
flowEmitter.emit(EventManager.TYPES.AST_DEFINED, ast);
|
|
74
86
|
return errors;
|
|
75
87
|
}
|
|
76
88
|
|
|
77
89
|
function exec(arg1, arg2, argN, cb) { // called to execute the flow
|
|
78
90
|
/*jshint validthis: true */
|
|
79
|
-
var
|
|
91
|
+
var args = Array.prototype.slice.call(arguments);
|
|
92
|
+
var env = {
|
|
93
|
+
execId: idGenerator.createUniqueId(),
|
|
94
|
+
args: args,
|
|
95
|
+
ast: ast,
|
|
96
|
+
flowEmitter: flowEmitter
|
|
97
|
+
};
|
|
98
|
+
env.name = ast.name || env.execId;
|
|
99
|
+
flowEmitter.emit(EventManager.TYPES.EXEC_FLOW_START, env); // hook
|
|
100
|
+
var parsedInput = inputParser(args, ast);
|
|
80
101
|
var vCon = VContext.create(parsedInput.args, ast.inParams, ast.locals, this); // create var ctx with in args & locals
|
|
81
102
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
};
|
|
89
|
-
reactEmitter.emit(EventManager.TYPES.EXEC_TASKS_PRECREATE, taskEnv); // hook
|
|
103
|
+
env.parsedInput = parsedInput;
|
|
104
|
+
env.options = mergeOptions(parsedInput.options);
|
|
105
|
+
env.vCon = vCon;
|
|
106
|
+
env.taskDefs = ast.tasks.slice(); // create copy
|
|
107
|
+
env.outTaskDef = Object.create(ast.outTask); // create copy
|
|
108
|
+
reactEmitter.emit(EventManager.TYPES.EXEC_TASKS_PRECREATE, env); // hook
|
|
90
109
|
|
|
91
|
-
var tasks =
|
|
110
|
+
var tasks = env.taskDefs.map(tskutil.create);
|
|
92
111
|
var tasksByName = tskutil.nameTasks(tasks); // map names to working tasks
|
|
93
|
-
var outTask = tskutil.createOutTask(
|
|
112
|
+
var outTask = tskutil.createOutTask(env.outTaskDef, parsedInput.cb, tasks, vCon, env.options, env);
|
|
94
113
|
var handleError = tskutil.createErrorHandler(vCon, outTask);
|
|
95
114
|
|
|
96
115
|
function contExec() {
|
|
97
116
|
if (!outTask.f) { return; } //stop execution, we already hit an error, f was cleared
|
|
98
117
|
if (outTask.isReady()) return outTask.exec(); // all tasks done, exec cb, return
|
|
99
|
-
tskutil.findReadyAndExec(vCon, tasks, tasksByName, handleError, contExec); //exec tasks that ready to run
|
|
118
|
+
tskutil.findReadyAndExec(vCon, tasks, tasksByName, handleError, contExec, env); //exec tasks that ready to run
|
|
100
119
|
}
|
|
101
120
|
|
|
102
121
|
tasks.forEach(function (t) {
|
|
103
122
|
t.id = idGenerator.createUniqueId();
|
|
104
|
-
t.
|
|
123
|
+
t.env = env;
|
|
105
124
|
if (t.prepare) t.prepare(handleError, vCon, contExec, flowEmitter);
|
|
106
125
|
}); // create callbacks
|
|
107
126
|
contExec(); // start things off
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('../'); // require('react');
|
|
4
|
+
react.trackTasks(); // enable task tracking
|
|
5
|
+
|
|
6
|
+
var AST_EVENTS_RE = /^ast\./;
|
|
7
|
+
var TASK_EVENTS_RE = /^task\./;
|
|
8
|
+
var FLOW_EVENTS_RE = /^flow\./;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
Accumulator to make it easy to capture events
|
|
12
|
+
|
|
13
|
+
@example
|
|
14
|
+
var EventCollector = require('react/lib/event-collector');
|
|
15
|
+
var collector = new EventCollector();
|
|
16
|
+
|
|
17
|
+
collector.capture(); // capture all flow and task events for all react flows
|
|
18
|
+
collector.capture('flow.*'); // capture all flow events for all react flows
|
|
19
|
+
collector.capture(flowFn, 'task.*'); // capture task events on a flow
|
|
20
|
+
collector.capture(flowFn, 'flow.*'); // add capture flow events on a flow
|
|
21
|
+
|
|
22
|
+
var events = collector.list(); // retrieve the list of events
|
|
23
|
+
collector.clear(); // clear the list of events;
|
|
24
|
+
*/
|
|
25
|
+
function EventCollector() {
|
|
26
|
+
this.events = [];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
register listener to capture events for a specific flow
|
|
31
|
+
@param flowFn the react flow function or can pass global react
|
|
32
|
+
@param eventId event id or wildcarded id
|
|
33
|
+
*/
|
|
34
|
+
EventCollector.prototype.capture = function (flowFn, eventId) {
|
|
35
|
+
/*jshint validthis: true */
|
|
36
|
+
if (!eventId && typeof(flowFn) === 'string') { // only eventId provided
|
|
37
|
+
eventId = flowFn;
|
|
38
|
+
flowFn = react; // global react
|
|
39
|
+
} else if (!flowFn) flowFn = react; // global react
|
|
40
|
+
if (!eventId) eventId = '*'; // default to all
|
|
41
|
+
var emitter = flowFn.events;
|
|
42
|
+
var self = this;
|
|
43
|
+
function accumEvents(obj) {
|
|
44
|
+
var eventObject = {
|
|
45
|
+
event: this.event,
|
|
46
|
+
time: Date.now()
|
|
47
|
+
};
|
|
48
|
+
if (FLOW_EVENTS_RE.test(this.event)) {
|
|
49
|
+
eventObject.env = obj;
|
|
50
|
+
} else if (TASK_EVENTS_RE.test(this.event)) {
|
|
51
|
+
eventObject.task = obj;
|
|
52
|
+
} else if (AST_EVENTS_RE.test(this.event)) {
|
|
53
|
+
eventObject.ast = obj;
|
|
54
|
+
}
|
|
55
|
+
self.events.push(eventObject);
|
|
56
|
+
}
|
|
57
|
+
emitter.on(eventId, accumEvents);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
EventCollector.prototype.list = function () {
|
|
61
|
+
return this.events;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
EventCollector.prototype.clear = function () {
|
|
65
|
+
this.events = []; // clear
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
module.exports = EventCollector;
|
package/lib/event-manager.js
CHANGED
|
@@ -10,13 +10,24 @@ var EVENT_EMITTER2_CONFIG = {
|
|
|
10
10
|
|
|
11
11
|
var TYPES = {
|
|
12
12
|
// Flow monitoring events and their params
|
|
13
|
+
AST_DEFINED: 'ast.defined', // ast
|
|
14
|
+
FLOW_BEGIN: 'flow.begin', // env
|
|
13
15
|
TASK_BEGIN: 'task.begin', // task
|
|
14
16
|
TASK_COMPLETE: 'task.complete', // task
|
|
17
|
+
TASK_ERRORED: 'task.errored', // task
|
|
18
|
+
FLOW_COMPLETE: 'flow.complete', // env
|
|
19
|
+
FLOW_ERRORED: 'flow.errored', // env
|
|
15
20
|
|
|
16
21
|
// Internal Hooks
|
|
22
|
+
EXEC_FLOW_START: 'exec.flow.start', // env
|
|
17
23
|
EXEC_INPUT_PREPROCESS: 'exec.input.preprocess', // parsedInput
|
|
18
|
-
EXEC_TASKS_PRECREATE: 'exec.tasks.precreate',
|
|
19
|
-
EXEC_OUTTASK_CREATE: 'exec.outTask.create' // outTaskOptions
|
|
24
|
+
EXEC_TASKS_PRECREATE: 'exec.tasks.precreate', // env
|
|
25
|
+
EXEC_OUTTASK_CREATE: 'exec.outTask.create', // outTaskOptions
|
|
26
|
+
EXEC_TASK_START: 'exec.task.start', // task
|
|
27
|
+
EXEC_TASK_COMPLETE: 'exec.task.complete', // task
|
|
28
|
+
EXEC_TASK_ERRORED: 'exec.task.errored', // task
|
|
29
|
+
EXEC_FLOW_COMPLETE: 'exec.flow.complete', // env
|
|
30
|
+
EXEC_FLOW_ERRORED: 'exec.flow.errored' // env
|
|
20
31
|
};
|
|
21
32
|
|
|
22
33
|
/**
|
|
@@ -52,18 +63,10 @@ EventManager.prototype.emit = function (event, arg1, arg2, argN) {
|
|
|
52
63
|
if (this.parent && this.parent.isEnabled()) this.parent.emit.apply(this.parent, arguments);
|
|
53
64
|
};
|
|
54
65
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
Copies object and adds standard fields:
|
|
58
|
-
event: event type
|
|
59
|
-
time: current time
|
|
60
|
-
*/
|
|
61
|
-
EventManager.prototype.emitObject = function (event, object) {
|
|
62
|
-
var evObj = Object.create(object); // create inherited copy version so origin is untouched
|
|
63
|
-
evObj.event = event; // augment with the event type
|
|
64
|
-
evObj.time = Date.now(); // augument with the time of the event
|
|
65
|
-
this.emit(event, evObj);
|
|
66
|
+
EventManager.prototype.removeListener = function (event, listener) {
|
|
67
|
+
if (this.emitter) this.emitter.removeListener.apply(this.emitter, arguments);
|
|
66
68
|
};
|
|
67
69
|
|
|
70
|
+
|
|
68
71
|
module.exports = EventManager;
|
|
69
72
|
module.exports.global = EventManager.create(); // create one top level emitter
|
|
@@ -5,23 +5,22 @@ var util = require('util');
|
|
|
5
5
|
|
|
6
6
|
var STATUS = require('./status.js');
|
|
7
7
|
var VContext = require('./vcon.js');
|
|
8
|
+
var EventManager = require('./event-manager.js');
|
|
8
9
|
|
|
9
10
|
var OUTTASK_A_REQ = 'ast.outTask.a should be an array of string param names';
|
|
10
11
|
|
|
11
12
|
function FinalCbFirstSuccTask(outTaskOptions) {
|
|
12
13
|
var taskDef = outTaskOptions.taskDef;
|
|
13
|
-
|
|
14
|
-
var tasks = outTaskOptions.tasks;
|
|
15
|
-
var vCon = outTaskOptions.vCon;
|
|
16
|
-
var execOptions = outTaskOptions.execOptions;
|
|
17
|
-
var retValue = outTaskOptions.retValue;
|
|
18
|
-
if (typeof(cbFunc) !== 'function') throw new Error('callback is not a function');
|
|
14
|
+
if (typeof(outTaskOptions.cbFunc) !== 'function') throw new Error('callback is not a function');
|
|
19
15
|
var self = this;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
this.
|
|
24
|
-
this.
|
|
16
|
+
for (var k in taskDef) {
|
|
17
|
+
if (true) self[k] = taskDef[k]; // if to make jshint happy
|
|
18
|
+
}
|
|
19
|
+
this.f = outTaskOptions.cbFunc;
|
|
20
|
+
this.tasks = outTaskOptions.tasks;
|
|
21
|
+
this.vCon = outTaskOptions.vCon;
|
|
22
|
+
this.retValue = outTaskOptions.retValue;
|
|
23
|
+
this.env = outTaskOptions.env;
|
|
25
24
|
}
|
|
26
25
|
|
|
27
26
|
function format_error(errmsg, obj) {
|
|
@@ -49,11 +48,15 @@ FinalCbFirstSuccTask.prototype.isReady = function () {
|
|
|
49
48
|
FinalCbFirstSuccTask.prototype.exec = function (err) {
|
|
50
49
|
if (!this.f) return; //must have already been called
|
|
51
50
|
if (err) {
|
|
51
|
+
this.env.error = err;
|
|
52
|
+
this.env.flowEmitter.emit(EventManager.TYPES.EXEC_FLOW_ERRORED, this.env);
|
|
52
53
|
this.f.call(null, err); //call the final callback with the first error hit
|
|
53
54
|
} else { // no error, call with args
|
|
54
55
|
var vCon = this.vCon;
|
|
55
56
|
var finalArgs = this.a.map(function (k) { return vCon.getVar(k); });
|
|
56
57
|
finalArgs.unshift(null); //unshift err=null to front
|
|
58
|
+
this.env.results = finalArgs;
|
|
59
|
+
this.env.flowEmitter.emit(EventManager.TYPES.EXEC_FLOW_COMPLETE, this.env);
|
|
57
60
|
this.f.apply(null, finalArgs);
|
|
58
61
|
}
|
|
59
62
|
this.f = null; // prevent multiple calls
|