react 0.2.6 → 0.5.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/.npmignore +2 -1
- package/README.md +94 -149
- package/doc/advanced.md +161 -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/default-events1.js +33 -6
- package/examples/{fstr1.js → default-log-events.js} +20 -13
- package/examples/default-simple.js +45 -0
- package/lib/base-task.js +8 -6
- package/lib/cb-task.js +14 -1
- package/lib/core.js +43 -12
- package/lib/dsl.js +14 -6
- package/lib/event-collector.js +65 -0
- package/lib/event-manager.js +29 -16
- package/lib/finalcb-first-task.js +16 -10
- package/lib/finalcb-task.js +17 -10
- package/lib/input-parser.js +7 -3
- package/lib/log-events.js +86 -0
- package/lib/parse.js +6 -3
- package/lib/promise-resolve.js +35 -0
- package/lib/promise-task.js +89 -0
- package/lib/ret-task.js +1 -1
- package/lib/task.js +32 -23
- package/lib/track-tasks.js +60 -0
- package/lib/validate.js +3 -3
- package/lib/vcon.js +6 -3
- package/lib/when-task.js +81 -0
- package/package.json +5 -3
- package/react.js +33 -5
- package/test/core-deferred.test.js +134 -0
- package/test/core-promised.test.js +132 -0
- package/test/core-when.test.js +84 -0
- package/test/core.test.js +108 -60
- package/test/dsl.test.js +58 -6
- package/test/exec-options.test.js +2 -1
- package/test/finalcb-task.test.js +6 -5
- package/test/input-parser.test.js +10 -6
- package/test/module-use.test.js +16 -199
- package/test/promise-auto-resolve.test.js +52 -0
- package/test/validate.test.js +4 -2
- package/test/vcon.test.js +13 -0
- package/Jakefile.js +0 -8
- package/examples/chain-events1.js +0 -34
- package/examples/chain1.js +0 -19
- package/examples/fstr-events1.js +0 -51
- package/examples/pcode1.js +0 -22
- package/jake-tasks/jake-test.js +0 -64
- package/lib/chain.js +0 -148
- package/lib/fstr.js +0 -119
- package/lib/pcode.js +0 -173
- package/oldExamples/analyze.js +0 -29
- package/oldExamples/analyze2.js +0 -29
- package/oldExamples/example10-dsl.js +0 -63
- package/oldExamples/example11.js +0 -62
- package/oldExamples/example12.js +0 -63
- package/oldExamples/example13.js +0 -63
- package/oldExamples/example14.js +0 -63
- package/oldExamples/example15.js +0 -75
- package/oldExamples/example6-ast.js +0 -47
- package/oldExamples/example6-dsl.js +0 -49
- package/oldExamples/example8-ast.js +0 -55
- package/oldExamples/example8-dsl.js +0 -53
- package/oldExamples/example9-ast.js +0 -58
- package/oldExamples/example9-dsl.js +0 -57
- package/oldExamples/function-str-ex1.js +0 -33
- package/oldExamples/function-str-ex2.js +0 -67
- package/oldExamples/trait1.js +0 -41
- package/oldExamples/trait2.js +0 -44
- package/test/chain.test.js +0 -253
- package/test/fstr.test.js +0 -300
- package/test/pcode.test.js +0 -335
|
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
|
|
@@ -1,22 +1,49 @@
|
|
|
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
|
+
require('../lib/track-tasks'); // require('react/lib/track-tasks'); // turn on tracking
|
|
5
10
|
|
|
6
11
|
//output events as tasks start and complete
|
|
7
|
-
react.events.on('
|
|
12
|
+
react.events.on('flow.*', function (obj) {
|
|
13
|
+
/*jshint validthis: true */
|
|
8
14
|
var time = new Date();
|
|
9
15
|
time.setTime(obj.time);
|
|
16
|
+
var argsNoCb = obj.args.filter(function (a) { return (typeof(a) !== 'function'); });
|
|
10
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);
|
|
11
33
|
var argsNoCb = obj.args.filter(function (a) { return (typeof(a) !== 'function'); });
|
|
12
|
-
|
|
34
|
+
var eventTimeStr = time.toISOString();
|
|
35
|
+
if (this.event === 'task.complete') {
|
|
36
|
+
var task = obj;
|
|
13
37
|
console.error('%s: %s \tmsecs:(%s) \n\targs:(%s) \n\tresults:(%s)\n',
|
|
14
|
-
|
|
38
|
+
this.event, task.name, task.elapsedTime, argsNoCb, task.results);
|
|
15
39
|
} else {
|
|
16
|
-
|
|
40
|
+
var name = obj.name;
|
|
41
|
+
var args = obj.args;
|
|
42
|
+
console.error('%s: %s \n\targs:(%s)\n', this.event, name, argsNoCb);
|
|
17
43
|
}
|
|
18
44
|
});
|
|
19
|
-
|
|
45
|
+
|
|
46
|
+
|
|
20
47
|
|
|
21
48
|
function loadUser(uid, cb){ setTimeout(cb, 100, null, "User"+uid); }
|
|
22
49
|
function loadFile(filename, cb){ setTimeout(cb, 100, null, 'Filedata'+filename); }
|
|
@@ -43,7 +70,7 @@ var loadAndSave = react('loadAndSave', 'filename, uid, outDirname, cb -> err, ht
|
|
|
43
70
|
writeOutput, 'html, user, cb -> err, bytesWritten', { after: prepareDirectory }, // only after prepareDirectory done
|
|
44
71
|
loadEmailTemplate, 'cb -> err, emailmd',
|
|
45
72
|
markdown, 'emailmd -> emailHtml', // using a sync function
|
|
46
|
-
customizeEmail, 'user, emailHtml ->
|
|
73
|
+
customizeEmail, 'user, emailHtml -> custEmailHtml', // sync fn
|
|
47
74
|
deliverEmail, 'custEmailHtml, cb -> err, deliveredEmail', { after: writeOutput } // only after writeOutput is done
|
|
48
75
|
);
|
|
49
76
|
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
+
/*jshint white: false */
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
Default DSL, showing use of events
|
|
6
|
+
*/
|
|
2
7
|
|
|
3
8
|
var react = require('../'); // require('react');
|
|
9
|
+
react.logEvents(); // turn on logging of all flow and task events for all react functions
|
|
10
|
+
|
|
4
11
|
|
|
5
12
|
function loadUser(uid, cb){ setTimeout(cb, 100, null, "User"+uid); }
|
|
6
13
|
function loadFile(filename, cb){ setTimeout(cb, 100, null, 'Filedata'+filename); }
|
|
@@ -8,28 +15,28 @@ function markdown(filedata) { return 'html'+filedata; }
|
|
|
8
15
|
function prepareDirectory(outDirname, cb){ setTimeout(cb, 200, null, 'dircreated-'+outDirname); }
|
|
9
16
|
function writeOutput(html, user, cb){ setTimeout(cb, 300, null, html+'_bytesWritten'); }
|
|
10
17
|
function loadEmailTemplate(cb) { setTimeout(cb, 50, null, 'emailmd'); }
|
|
11
|
-
function customizeEmail(user, emailHtml
|
|
18
|
+
function customizeEmail(user, emailHtml) { return 'cust-'+user+emailHtml; }
|
|
12
19
|
function deliverEmail(custEmailHtml, cb) { setTimeout(cb, 100, null, 'delivered-'+custEmailHtml); }
|
|
13
20
|
|
|
14
21
|
function useHtml(err, html, user, bytesWritten) {
|
|
15
|
-
if(err) {
|
|
22
|
+
if (err) {
|
|
16
23
|
console.log('***Error: %s', err);
|
|
17
24
|
return;
|
|
18
25
|
}
|
|
19
26
|
console.log('final result: %s, user: %s, written:%s', html, user, bytesWritten);
|
|
20
27
|
}
|
|
21
28
|
|
|
22
|
-
var loadAndSave = react
|
|
23
|
-
loadUser, 'uid
|
|
24
|
-
loadFile, 'filename
|
|
25
|
-
markdown, 'filedata ->
|
|
26
|
-
prepareDirectory, 'outDirname
|
|
27
|
-
writeOutput, 'html, user
|
|
28
|
-
loadEmailTemplate, '
|
|
29
|
-
markdown, 'emailmd ->
|
|
30
|
-
customizeEmail, 'user, emailHtml ->
|
|
31
|
-
deliverEmail, 'custEmailHtml
|
|
32
|
-
|
|
29
|
+
var loadAndSave = react('loadAndSave', 'filename, uid, outDirname, cb -> err, html, user, bytesWritten', // name, in/out params
|
|
30
|
+
loadUser, 'uid, cb -> err, user', // calling async fn loadUser with uid, callback is called with err and user
|
|
31
|
+
loadFile, 'filename, cb -> err, filedata',
|
|
32
|
+
markdown, 'filedata -> html', // using a sync function
|
|
33
|
+
prepareDirectory, 'outDirname, cb -> err, dircreated',
|
|
34
|
+
writeOutput, 'html, user, cb -> err, bytesWritten', { after: prepareDirectory }, // only after prepareDirectory done
|
|
35
|
+
loadEmailTemplate, 'cb -> err, emailmd',
|
|
36
|
+
markdown, 'emailmd -> emailHtml', // using a sync function
|
|
37
|
+
customizeEmail, 'user, emailHtml -> custEmailHtml', // sync fn
|
|
38
|
+
deliverEmail, 'custEmailHtml, cb -> err, deliveredEmail', { after: writeOutput } // only after writeOutput is done
|
|
39
|
+
);
|
|
33
40
|
|
|
34
41
|
loadAndSave('file.md', 100, '/tmp/foo', useHtml); // executing the flow
|
|
35
42
|
|
|
@@ -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
|
+
});
|
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) {
|
|
@@ -96,6 +97,7 @@ BaseTask.prototype.isReady = function (vCon, tasksByName) {
|
|
|
96
97
|
};
|
|
97
98
|
|
|
98
99
|
BaseTask.prototype.isMethodCall = function () {
|
|
100
|
+
/*jshint regexp: false */
|
|
99
101
|
return (typeof(this.f) === 'string' && /^.*\..*$/.test(this.f)); //str contains .
|
|
100
102
|
};
|
|
101
103
|
|
package/lib/cb-task.js
CHANGED
|
@@ -43,6 +43,19 @@ CbTask.validate = function (taskDef) {
|
|
|
43
43
|
return errors;
|
|
44
44
|
};
|
|
45
45
|
|
|
46
|
+
CbTask.prototype.prepare = function prepare(handleTaskError, vCon, contExec) {
|
|
47
|
+
var self = this;
|
|
48
|
+
this.cbFun = function (err, arg0, arg1, argn) {
|
|
49
|
+
var args = Array.prototype.slice.call(arguments, 1);
|
|
50
|
+
if (err) { handleTaskError(self, err); return; } //handle error and return, we are done
|
|
51
|
+
|
|
52
|
+
//no error, save callback args to vCon context, then continue execution
|
|
53
|
+
vCon.saveResults(self.out, args);
|
|
54
|
+
self.complete(args);
|
|
55
|
+
contExec();
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
|
|
46
59
|
CbTask.prototype.exec = function exec(vCon, handleError, contExec) {
|
|
47
60
|
try {
|
|
48
61
|
var args = this.a.map(function (k) { return vCon.getVar(k); }); //get args from vCon
|
|
@@ -51,7 +64,7 @@ CbTask.prototype.exec = function exec(vCon, handleError, contExec) {
|
|
|
51
64
|
this.start(args); //note the start time, args
|
|
52
65
|
args.push(this.cbFun); // push callback fn on end
|
|
53
66
|
var func = this.f;
|
|
54
|
-
var bindObj =
|
|
67
|
+
var bindObj = vCon.getVar('this'); //global space or the original this
|
|
55
68
|
if (this.isMethodCall()) { //if method call then reset func and bindObj
|
|
56
69
|
func = vCon.getVar(this.f);
|
|
57
70
|
bindObj = this.getMethodObj(vCon);
|
package/lib/core.js
CHANGED
|
@@ -7,7 +7,6 @@ var validate = require('./validate.js');
|
|
|
7
7
|
var tskutil = require('./task.js');
|
|
8
8
|
var STATUS = require('./status.js');
|
|
9
9
|
var VContext = require('./vcon.js');
|
|
10
|
-
var FinalCbTask = require('./finalcb-task.js');
|
|
11
10
|
var EventManager = require('./event-manager.js');
|
|
12
11
|
var inputParser = require('./input-parser.js');
|
|
13
12
|
var idGenerator = require('./id.js');
|
|
@@ -16,7 +15,17 @@ var reactOptions = {
|
|
|
16
15
|
stackTraceLimitMin: 30
|
|
17
16
|
};
|
|
18
17
|
|
|
19
|
-
var reactEmitter = EventManager.
|
|
18
|
+
var reactEmitter = EventManager.global; // the top emitter
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
merge global react options with parsed options
|
|
22
|
+
*/
|
|
23
|
+
function mergeOptions(parsedOptions) {
|
|
24
|
+
return Object.keys(reactOptions).reduce(function (accum, k) {
|
|
25
|
+
if (!accum[k]) accum[k] = reactOptions[k];
|
|
26
|
+
return accum;
|
|
27
|
+
}, parsedOptions);
|
|
28
|
+
}
|
|
20
29
|
|
|
21
30
|
/**
|
|
22
31
|
Creates react function which the AST can be manipulated and then
|
|
@@ -56,32 +65,54 @@ function reactFactory() {
|
|
|
56
65
|
Object.keys(newAST).forEach(function (k) { ast[k] = newAST[k]; }); // copy all properties
|
|
57
66
|
var errors = validate(ast);
|
|
58
67
|
if (!errors.length) tskutil.nameTasks(ast.tasks); //run this so names can be checked in ast
|
|
68
|
+
if (Object.freeze) { //lets freeze the AST so plugin writers don't accidentally manip the ast
|
|
69
|
+
Object.keys(newAST).forEach(function (k) {
|
|
70
|
+
if (typeof(newAST[k]) === 'object') Object.freeze(newAST[k]);
|
|
71
|
+
});
|
|
72
|
+
Object.freeze(newAST);
|
|
73
|
+
}
|
|
59
74
|
return errors;
|
|
60
75
|
}
|
|
61
76
|
|
|
62
77
|
function exec(arg1, arg2, argN, cb) { // called to execute the flow
|
|
63
|
-
|
|
64
|
-
var args =
|
|
65
|
-
var
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
78
|
+
/*jshint validthis: true */
|
|
79
|
+
var args = Array.prototype.slice.call(arguments);
|
|
80
|
+
var env = {
|
|
81
|
+
execId: idGenerator.createUniqueId(),
|
|
82
|
+
args: args,
|
|
83
|
+
ast: ast,
|
|
84
|
+
flowEmitter: flowEmitter
|
|
85
|
+
};
|
|
86
|
+
env.name = ast.name || env.execId;
|
|
87
|
+
flowEmitter.emit(EventManager.TYPES.EXEC_FLOW_START, env); // hook
|
|
88
|
+
var parsedInput = inputParser(args, ast);
|
|
89
|
+
var vCon = VContext.create(parsedInput.args, ast.inParams, ast.locals, this); // create var ctx with in args & locals
|
|
90
|
+
|
|
91
|
+
env.parsedInput = parsedInput;
|
|
92
|
+
env.options = mergeOptions(parsedInput.options);
|
|
93
|
+
env.vCon = vCon;
|
|
94
|
+
env.taskDefs = ast.tasks.slice(); // create copy
|
|
95
|
+
env.outTaskDef = Object.create(ast.outTask); // create copy
|
|
96
|
+
reactEmitter.emit(EventManager.TYPES.EXEC_TASKS_PRECREATE, env); // hook
|
|
97
|
+
|
|
98
|
+
var tasks = env.taskDefs.map(tskutil.create);
|
|
69
99
|
var tasksByName = tskutil.nameTasks(tasks); // map names to working tasks
|
|
70
|
-
var outTask = tskutil.createOutTask(
|
|
100
|
+
var outTask = tskutil.createOutTask(env.outTaskDef, parsedInput.cb, tasks, vCon, env.options, env);
|
|
71
101
|
var handleError = tskutil.createErrorHandler(vCon, outTask);
|
|
72
102
|
|
|
73
103
|
function contExec() {
|
|
74
104
|
if (!outTask.f) { return; } //stop execution, we already hit an error, f was cleared
|
|
75
105
|
if (outTask.isReady()) return outTask.exec(); // all tasks done, exec cb, return
|
|
76
|
-
tskutil.findReadyAndExec(vCon, tasks, tasksByName, handleError, contExec); //exec tasks that ready to run
|
|
106
|
+
tskutil.findReadyAndExec(vCon, tasks, tasksByName, handleError, contExec, env); //exec tasks that ready to run
|
|
77
107
|
}
|
|
78
108
|
|
|
79
109
|
tasks.forEach(function (t) {
|
|
80
110
|
t.id = idGenerator.createUniqueId();
|
|
81
|
-
t.
|
|
82
|
-
if (t.
|
|
111
|
+
t.env = env;
|
|
112
|
+
if (t.prepare) t.prepare(handleError, vCon, contExec, flowEmitter);
|
|
83
113
|
}); // create callbacks
|
|
84
114
|
contExec(); // start things off
|
|
115
|
+
return outTask.retValue; // could return promise
|
|
85
116
|
}
|
|
86
117
|
|
|
87
118
|
var reactFn = exec; // make the exec() the function returned
|
package/lib/dsl.js
CHANGED
|
@@ -6,8 +6,10 @@ var core = require('./core.js');
|
|
|
6
6
|
var parse = require('./parse.js');
|
|
7
7
|
var tutil = require('./task.js');
|
|
8
8
|
|
|
9
|
-
var MISSING_NAME = '
|
|
10
|
-
var INOUT_PARAMS_NO_MATCH = 'params in wrong format, wanted "foo, bar cb -> err, baz" - found: %s';
|
|
9
|
+
var MISSING_NAME = 'first flow parameter should be the flow name, but found in/out def: %s';
|
|
10
|
+
var INOUT_PARAMS_NO_MATCH = 'params in wrong format, wanted "foo, bar, cb -> err, baz" - found: %s';
|
|
11
|
+
var MISSING_ERR = 'callback specified, but first out param was not "err", use for clarity. Found in/out def: %s';
|
|
12
|
+
var MISSING_CB = 'found err param, but cb/callback is not specified, is this cb-style async or sync function? Found in/out def: %s';
|
|
11
13
|
var EXTRA_TASKARG = 'extra unmatched task arg: %s';
|
|
12
14
|
|
|
13
15
|
var INOUT_RE = /\->/; // used to detect missing name, in/out as first arg
|
|
@@ -25,12 +27,18 @@ function filterOutLeadingErrParam(args) { // if leading err param, filter it out
|
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
var inOutDefParse = {
|
|
28
|
-
|
|
29
|
-
fn: function (m) {
|
|
30
|
-
var inParams = parse.splitTrimFilterArgs(m[
|
|
30
|
+
splitStr: '->',
|
|
31
|
+
fn: function (m, origStr) {
|
|
32
|
+
var inParams = parse.splitTrimFilterArgs(m[0]);
|
|
31
33
|
var lastParam = inParams[inParams.length - 1];
|
|
32
34
|
var type = (lastParam && CB_NAMES_RE.test(lastParam)) ? 'cb' : 'ret';
|
|
33
|
-
var outParams = parse.splitTrimFilterArgs(m[
|
|
35
|
+
var outParams = parse.splitTrimFilterArgs(m[1]);
|
|
36
|
+
var firstOutParam = outParams[0];
|
|
37
|
+
if (type === 'cb' && (!firstOutParam || !ERR_NAMES_RE.test(firstOutParam))) {
|
|
38
|
+
throw new Error(sprintf(MISSING_ERR, origStr)); // found cb, but no err param
|
|
39
|
+
} else if (type === 'ret' && firstOutParam && ERR_NAMES_RE.test(firstOutParam)) {
|
|
40
|
+
throw new Error(sprintf(MISSING_CB, origStr)); // found err but not cb param
|
|
41
|
+
}
|
|
34
42
|
return {
|
|
35
43
|
type: type,
|
|
36
44
|
inDef: filterOutTrailingCbParam(inParams),
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('../'); // require('react');
|
|
4
|
+
react.trackTasks(); // enable task tracking
|
|
5
|
+
|
|
6
|
+
var TASK_EVENTS_RE = /^task\./;
|
|
7
|
+
var FLOW_EVENTS_RE = /^flow\./;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
Accumulator to make it easy to capture events
|
|
11
|
+
|
|
12
|
+
@example
|
|
13
|
+
var EventCollector = require('react/lib/event-collector');
|
|
14
|
+
var collector = new EventCollector();
|
|
15
|
+
|
|
16
|
+
collector.capture(); // capture all flow and task events for all react flows
|
|
17
|
+
collector.capture('flow.*'); // capture all flow events for all react flows
|
|
18
|
+
collector.capture(flowFn, 'task.*'); // capture task events on a flow
|
|
19
|
+
collector.capture(flowFn, 'flow.*'); // add capture flow events on a flow
|
|
20
|
+
|
|
21
|
+
var events = collector.list(); // retrieve the list of events
|
|
22
|
+
collector.clear(); // clear the list of events;
|
|
23
|
+
*/
|
|
24
|
+
function EventCollector() {
|
|
25
|
+
this.events = [];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
register listener to capture events for a specific flow
|
|
30
|
+
@param flowFn the react flow function or can pass global react
|
|
31
|
+
@param eventId event id or wildcarded id
|
|
32
|
+
*/
|
|
33
|
+
EventCollector.prototype.capture = function (flowFn, eventId) {
|
|
34
|
+
/*jshint validthis: true */
|
|
35
|
+
if (!eventId && typeof(flowFn) === 'string') { // only eventId provided
|
|
36
|
+
eventId = flowFn;
|
|
37
|
+
flowFn = react; // global react
|
|
38
|
+
} else if (!flowFn) flowFn = react; // global react
|
|
39
|
+
if (!eventId) eventId = '*'; // default to all
|
|
40
|
+
var emitter = flowFn.events;
|
|
41
|
+
var self = this;
|
|
42
|
+
function accumEvents(obj) {
|
|
43
|
+
var eventObject = {
|
|
44
|
+
event: this.event,
|
|
45
|
+
time: Date.now()
|
|
46
|
+
};
|
|
47
|
+
if (FLOW_EVENTS_RE.test(this.event)) {
|
|
48
|
+
eventObject.env = obj;
|
|
49
|
+
} else if (TASK_EVENTS_RE.test(this.event)) {
|
|
50
|
+
eventObject.task = obj;
|
|
51
|
+
}
|
|
52
|
+
self.events.push(eventObject);
|
|
53
|
+
}
|
|
54
|
+
emitter.on(eventId, accumEvents);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
EventCollector.prototype.list = function () {
|
|
58
|
+
return this.events;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
EventCollector.prototype.clear = function () {
|
|
62
|
+
this.events = []; // clear
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
module.exports = EventCollector;
|