react 0.3.4 → 0.5.2
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 +68 -172
- package/doc/advanced.md +166 -0
- package/doc/color-def.graffle +938 -0
- package/doc/color-def.png +0 -0
- package/doc/simple.dot +25 -0
- package/doc/simple.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/{default-events1.js → using-events1.js} +0 -0
- package/examples/{default-log-events.js → using-log-events.js} +1 -1
- package/lib/core.js +13 -1
- package/lib/event-collector.js +68 -0
- package/lib/event-manager.js +4 -0
- package/lib/id.js +1 -0
- package/lib/log-events.js +30 -15
- package/{promise-resolve.js → lib/promise-resolve.js} +1 -1
- package/lib/task.js +8 -3
- package/lib/track-tasks.js +5 -62
- package/lib/vcon.js +1 -1
- package/package.json +2 -2
- package/react.js +33 -1
- package/test/ast.test.js +50 -1
- package/test/core.test.js +27 -2
- package/test/dsl.test.js +2 -2
- package/test/module-use.test.js +5 -2
- package/test/promise-auto-resolve.test.js +2 -1
- package/Jakefile.js +0 -8
- package/doc/alternate-dsls.md +0 -103
- package/dsl/chain.js +0 -150
- package/dsl/fstr.js +0 -121
- package/dsl/pcode.js +0 -175
- package/examples/chain-events1.js +0 -55
- package/examples/chain1.js +0 -19
- package/examples/fstr-events1.js +0 -38
- 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 -324
- package/test/dsl/fstr.test.js +0 -300
- package/test/dsl/pcode.test.js +0 -448
package/lib/vcon.js
CHANGED
|
@@ -71,7 +71,7 @@ VContext.create = function (args, inParams, locals, self) {
|
|
|
71
71
|
var vContext = new VContext();
|
|
72
72
|
vContext.values = args.reduce(function (vcon, x, idx) { // create vCon start with input args
|
|
73
73
|
var param = inParams[idx];
|
|
74
|
-
if (param) vcon[param] = x;
|
|
74
|
+
if (param) vcon[param] = (x !== undefined) ? x : null; // upgrade undefined to null
|
|
75
75
|
return vcon;
|
|
76
76
|
}, initValues);
|
|
77
77
|
return vContext;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react",
|
|
3
|
-
"description": "React is a javascript module to make it easier to work with asynchronous code, by reducing boilerplate code and improving error and exception handling while allowing variable and task dependencies when defining flow.",
|
|
4
|
-
"version": "0.
|
|
3
|
+
"description": "React is a javascript module implementing a lightweight rules engine to make it easier to work with asynchronous code, by reducing boilerplate code and improving error and exception handling while allowing variable and task dependencies when defining flow.",
|
|
4
|
+
"version": "0.5.2",
|
|
5
5
|
"author": "Jeff Barczewski <jeff.barczewski@gmail.com>",
|
|
6
6
|
"repository": { "type": "git", "url": "http://github.com/jeffbski/react.git" },
|
|
7
7
|
"bugs" : { "url": "http://github.com/jeffbski/react/issues" },
|
package/react.js
CHANGED
|
@@ -2,7 +2,39 @@
|
|
|
2
2
|
|
|
3
3
|
var core = require('./lib/core.js');
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
If called, load the built-in plugin for log events and invoke
|
|
7
|
+
|
|
8
|
+
@param flowFn [function] if not provided uses global react
|
|
9
|
+
@param eventWildcard [string] pattern to log events for
|
|
10
|
+
*/
|
|
11
|
+
function logEvents(flowFn, eventWildcard) {
|
|
12
|
+
var logEventsMod = require('./lib/log-events');
|
|
13
|
+
if (!eventWildcard && typeof(flowFn) === 'string') { // only wildcard provided
|
|
14
|
+
eventWildcard = flowFn;
|
|
15
|
+
flowFn = undefined;
|
|
16
|
+
}
|
|
17
|
+
return logEventsMod.logEvents(flowFn, eventWildcard);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
Enable detection of promises and resolution
|
|
22
|
+
*/
|
|
23
|
+
function resolvePromises() {
|
|
24
|
+
require('./lib/promise-resolve');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
Enable tracking of tasks and flow execution, emitting events and
|
|
29
|
+
tracking start, end, elapsed time
|
|
30
|
+
*/
|
|
31
|
+
function trackTasks() {
|
|
32
|
+
require('./lib/track-tasks');
|
|
33
|
+
}
|
|
34
|
+
|
|
5
35
|
module.exports = require('./lib/dsl.js'); // core + default dsl
|
|
6
36
|
module.exports.options = core.options; // global react options
|
|
7
37
|
module.exports.events = core.events; // global react event emitter
|
|
8
|
-
|
|
38
|
+
module.exports.logEvents = logEvents; // enable event logging
|
|
39
|
+
module.exports.resolvePromises = resolvePromises; // enable promise resolution
|
|
40
|
+
module.exports.trackTasks = trackTasks; // enable tracking of tasks
|
package/test/ast.test.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
var test = require('tap').test;
|
|
4
4
|
|
|
5
|
-
var react = require('../react');
|
|
5
|
+
var react = require('../'); // require('react');
|
|
6
|
+
var EventCollector = require('../lib/event-collector');
|
|
6
7
|
|
|
7
8
|
function load(res, cb) { cb(null, res + '-loaded'); }
|
|
8
9
|
function prefix(prefstr, str, cb) { cb(null, prefstr + str); }
|
|
@@ -38,6 +39,54 @@ test('mixed', function (t) {
|
|
|
38
39
|
});
|
|
39
40
|
});
|
|
40
41
|
|
|
42
|
+
test('ast.defined event called when ast is defined', function (t) {
|
|
43
|
+
var fn = react();
|
|
44
|
+
var collector = new EventCollector();
|
|
45
|
+
collector.capture(fn, 'ast.*');
|
|
46
|
+
|
|
47
|
+
var errors = fn.setAndValidateAST({
|
|
48
|
+
inParams: ['res', 'prefstr', 'poststr'],
|
|
49
|
+
tasks: [
|
|
50
|
+
{ f: load, a: ['res'], out: ['lres'] },
|
|
51
|
+
{ f: upper, a: ['lres'], out: ['ulres'], type: 'ret' },
|
|
52
|
+
{ f: prefix, a: ['prefstr', 'ulres'], out: ['plres'] },
|
|
53
|
+
{ f: postfix, a: ['plres', 'poststr'], out: ['plresp'] }
|
|
54
|
+
],
|
|
55
|
+
outTask: { a: ['plresp'] }
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
var events = collector.list();
|
|
59
|
+
t.equal(events.length, 1);
|
|
60
|
+
t.type(events[0].ast, 'object');
|
|
61
|
+
t.ok(events[0].ast.inParams);
|
|
62
|
+
t.ok(events[0].ast.tasks);
|
|
63
|
+
t.ok(events[0].ast.outTask);
|
|
64
|
+
t.end();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test('ast.defined event is passed to process', function (t) {
|
|
68
|
+
t.plan(5);
|
|
69
|
+
var fn = react();
|
|
70
|
+
process.once('ast.defined', function (ast) {
|
|
71
|
+
t.type(ast, 'object');
|
|
72
|
+
t.ok(ast.inParams);
|
|
73
|
+
t.ok(ast.tasks);
|
|
74
|
+
t.ok(ast.outTask);
|
|
75
|
+
t.deepEqual(ast.inParams, ['res', 'prefstr', 'poststr']);
|
|
76
|
+
t.end();
|
|
77
|
+
});
|
|
78
|
+
var errors = fn.setAndValidateAST({
|
|
79
|
+
inParams: ['res', 'prefstr', 'poststr'],
|
|
80
|
+
tasks: [
|
|
81
|
+
{ f: load, a: ['res'], out: ['lres'] },
|
|
82
|
+
{ f: upper, a: ['lres'], out: ['ulres'], type: 'ret' },
|
|
83
|
+
{ f: prefix, a: ['prefstr', 'ulres'], out: ['plres'] },
|
|
84
|
+
{ f: postfix, a: ['plres', 'poststr'], out: ['plresp'] }
|
|
85
|
+
],
|
|
86
|
+
outTask: { a: ['plresp'] }
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
41
90
|
test('cb with err', function (t) {
|
|
42
91
|
t.plan(5);
|
|
43
92
|
|
package/test/core.test.js
CHANGED
|
@@ -3,13 +3,14 @@
|
|
|
3
3
|
var test = require('tap').test;
|
|
4
4
|
|
|
5
5
|
var react = require('../react');
|
|
6
|
-
var EventCollector = require('../lib/
|
|
6
|
+
var EventCollector = require('../lib/event-collector'); // require('react/lib/event-collector'); // turn on tracking and get EventCollector
|
|
7
7
|
|
|
8
8
|
function multiply(x, y, cb) { cb(null, x * y); }
|
|
9
9
|
function add(x, y, cb) { cb(null, x + y); }
|
|
10
10
|
function badFunc(a, b, cb) { throw new Error('badFuncThrow'); }
|
|
11
11
|
function badF2(a, b, cb) { cb('my-error'); }
|
|
12
12
|
function fnRetsSum(a, b) { return a + b; }
|
|
13
|
+
var anonFn = function (a, b) { return a + b; };
|
|
13
14
|
|
|
14
15
|
test('set and validate AST', function (t) {
|
|
15
16
|
var fn = react();
|
|
@@ -42,16 +43,19 @@ test('unnamed tasks will be assigned unique names', function (t) {
|
|
|
42
43
|
{ f: multiply, a: ['a', 'b'], out: ['c'] },
|
|
43
44
|
{ f: multiply, a: ['a', 'b'], out: ['d'], name: 'multiply' },
|
|
44
45
|
{ f: multiply, a: ['a', 'b'], out: ['e'], name: 'times' },
|
|
46
|
+
{ f: anonFn, a: ['a', 'b'], out: ['g'], type: 'ret' },
|
|
45
47
|
{ f: multiply, a: ['a', 'b'], out: ['f'] }
|
|
46
48
|
],
|
|
47
49
|
outTask: { a: ['c'] }
|
|
48
50
|
});
|
|
49
51
|
t.deepEqual(errors, [], 'should set and validate as true');
|
|
52
|
+
t.equal(fn.ast.name.slice(0, 'flow_'.length), 'flow_', 'generated flow name should start with flow_');
|
|
50
53
|
t.deepEqual(fn.ast.tasks, [
|
|
51
54
|
{ f: multiply, a: ['a', 'b'], out: ['c'], type: 'cb', name: 'multiply_0' },
|
|
52
55
|
{ f: multiply, a: ['a', 'b'], out: ['d'], name: 'multiply', type: 'cb' },
|
|
53
56
|
{ f: multiply, a: ['a', 'b'], out: ['e'], name: 'times', type: 'cb' },
|
|
54
|
-
{ f:
|
|
57
|
+
{ f: anonFn, a: ['a', 'b'], out: ['g'], type: 'ret', name: 'task_3' },
|
|
58
|
+
{ f: multiply, a: ['a', 'b'], out: ['f'], type: 'cb', name: 'multiply_4' }
|
|
55
59
|
]);
|
|
56
60
|
t.end();
|
|
57
61
|
});
|
|
@@ -431,6 +435,27 @@ test('using "this" in a sync function', function (t) {
|
|
|
431
435
|
}]);
|
|
432
436
|
});
|
|
433
437
|
|
|
438
|
+
test('undefined input arguments will be upgraded from undefined to null', function (t) {
|
|
439
|
+
var fn = react();
|
|
440
|
+
function concat(a, b) {
|
|
441
|
+
return '' + a + b;
|
|
442
|
+
}
|
|
443
|
+
var errors = fn.setAndValidateAST({
|
|
444
|
+
inParams: ['a', 'b'],
|
|
445
|
+
tasks: [
|
|
446
|
+
{ f: concat, a: ['a', 'b'], out: ['c'], type: 'ret' }
|
|
447
|
+
],
|
|
448
|
+
outTask: { a: ['c'] }
|
|
449
|
+
});
|
|
450
|
+
t.deepEqual(errors, [], 'no validation errors');
|
|
451
|
+
fn('first', undefined, function (err, c) { // undefined second param, upgrade to null
|
|
452
|
+
t.equal(err, null);
|
|
453
|
+
t.equal(c, 'firstnull');
|
|
454
|
+
t.end();
|
|
455
|
+
});
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
|
|
434
459
|
|
|
435
460
|
// Select first tests
|
|
436
461
|
|
package/test/dsl.test.js
CHANGED
|
@@ -16,7 +16,7 @@ test('module exports is a fn with properties', function (t) {
|
|
|
16
16
|
|
|
17
17
|
test('no arguments -> empty name, inParams, tasks, outTask', function (t) {
|
|
18
18
|
var r = react();
|
|
19
|
-
t.equal(r.ast.name,
|
|
19
|
+
t.equal(r.ast.name.slice(0, 'flow_'.length), 'flow_', 'generated flow name should start with flow_');
|
|
20
20
|
t.deepEqual(r.ast.inParams, []);
|
|
21
21
|
t.deepEqual(r.ast.tasks, []);
|
|
22
22
|
t.deepEqual(r.ast.outTask, { a: [], type: 'finalcb' });
|
|
@@ -26,7 +26,7 @@ test('no arguments -> empty name, inParams, tasks, outTask', function (t) {
|
|
|
26
26
|
|
|
27
27
|
test('empty first string -> empty name, inParams, tasks, outTask', function (t) {
|
|
28
28
|
var r = react('');
|
|
29
|
-
t.equal(r.ast.name, '');
|
|
29
|
+
t.equal(r.ast.name.slice(0, 'flow_'.length), 'flow_', 'generated flow name should start with flow_');
|
|
30
30
|
t.deepEqual(r.ast.inParams, []);
|
|
31
31
|
t.deepEqual(r.ast.tasks, []);
|
|
32
32
|
t.deepEqual(r.ast.outTask, { a: [], type: 'finalcb' });
|
package/test/module-use.test.js
CHANGED
|
@@ -4,8 +4,8 @@ var test = require('tap').test;
|
|
|
4
4
|
var BaseTask = require('../lib/base-task.js');
|
|
5
5
|
|
|
6
6
|
var react = require('../'); // require('react');
|
|
7
|
-
// turn on tracking,
|
|
8
|
-
var EventCollector = require('../lib/
|
|
7
|
+
// turn on tracking, obtain EventCollector
|
|
8
|
+
var EventCollector = require('../lib/event-collector'); // require('react/lib/event-collector');
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
/**
|
|
@@ -39,6 +39,9 @@ test('module exports an function object with properties', function (t) {
|
|
|
39
39
|
t.type(react, 'function', 'is a core constructor and default dsl function');
|
|
40
40
|
t.type(react.options, 'object', 'has property for global react options');
|
|
41
41
|
t.type(react.events, 'object', 'has global react event manager');
|
|
42
|
+
t.type(react.logEvents, 'function', 'has function to enable event logging');
|
|
43
|
+
t.type(react.trackTasks, 'function', 'has function to enable task and flow tracking');
|
|
44
|
+
t.type(react.resolvePromises, 'function', 'has fn to enable promise detection & resolution');
|
|
42
45
|
t.end();
|
|
43
46
|
});
|
|
44
47
|
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
var test = require('tap').test;
|
|
9
9
|
var Deferred = require('promised-io/promise').Deferred;
|
|
10
10
|
|
|
11
|
-
var react = require('../
|
|
11
|
+
var react = require('../'); // require('react');
|
|
12
|
+
react.resolvePromises(); // enable promise resolving
|
|
12
13
|
|
|
13
14
|
function multiply(x, y, cb) { cb(null, x * y); }
|
|
14
15
|
function add(x, y, cb) { cb(null, x + y); }
|
package/Jakefile.js
DELETED
package/doc/alternate-dsls.md
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
# Alternate DSL's
|
|
2
|
-
|
|
3
|
-
These DSL's are not loaded by default and thus require a separate require if you want to use one.
|
|
4
|
-
|
|
5
|
-
Since React is an AST based rules system, it allows custom DSL's to be created easily, they only need to generate the AST and they are fully functional, allowing many different interfaces for the same system.
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
### Examples using the AST directly or alternate DSL's
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
1. [Using pseudocode DSL](#pcode)
|
|
12
|
-
2. [Using jquery-like chaining DSL](#chain)
|
|
13
|
-
3. [Function String DSL](#fstr) (Deprecated)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
<a name="pcode"/>
|
|
17
|
-
### Example using pseudocode DSL interface
|
|
18
|
-
|
|
19
|
-
```javascript
|
|
20
|
-
var pcodeDefine = require('react/dsl/pcode');
|
|
21
|
-
|
|
22
|
-
function multiply(a, b, cb) { cb(null, a * b); }
|
|
23
|
-
function add(a, b) { return a + b; }
|
|
24
|
-
var locals = { // since pcodeDefine uses strings, need references to functions passed into react
|
|
25
|
-
multiply: multiply,
|
|
26
|
-
add: add
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
var fn = pcodeDefine('a, b, cb', [ // input params
|
|
30
|
-
'm := multiply(a, b)', // using a callback function, use :=
|
|
31
|
-
's = add(m, a)', // using a sync function, use =
|
|
32
|
-
'cb(err, m, s)' // output params for final callback
|
|
33
|
-
], locals); // hash of functions that will be used
|
|
34
|
-
|
|
35
|
-
fn(2, 3, function (err, m, s) {
|
|
36
|
-
console.error('err:', err); // null
|
|
37
|
-
console.error('m:', m); // 2 * 3 = 6
|
|
38
|
-
console.error('s:', s); // 6 + 2 = 8
|
|
39
|
-
});
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
<a name="chain"/>
|
|
43
|
-
### Example using jquery-like chaining DSL interface
|
|
44
|
-
|
|
45
|
-
```javascript
|
|
46
|
-
var chainDefine = require('react/dsl/chain');
|
|
47
|
-
|
|
48
|
-
function multiply(a, b, cb) { cb(null, a * b); }
|
|
49
|
-
function add(a, b) { return a + b; }
|
|
50
|
-
|
|
51
|
-
var fn = chainDefine()
|
|
52
|
-
.in('a', 'b', 'cb') // input params
|
|
53
|
-
.out('err', 'm', 's') // final callback output params
|
|
54
|
-
.async(multiply).in('a', 'b', 'cb').out('err', 'm') // task def - async fn, in params, callback out params
|
|
55
|
-
.sync(add).in('m', 'a').out('s') // task def - sync fn, in params, return value
|
|
56
|
-
.end();
|
|
57
|
-
|
|
58
|
-
fn(2, 3, function (err, m, s) {
|
|
59
|
-
console.error('err:', err); // null
|
|
60
|
-
console.error('m:', m); // 2 * 3 = 6
|
|
61
|
-
console.error('s:', s); // 6 + 2 = 8
|
|
62
|
-
});
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
<a name="fstr"/>
|
|
66
|
-
### Example using Function String DSL interface
|
|
67
|
-
|
|
68
|
-
The Function String DSL interface is deprecated since it morphed into the default DSL which is very similar. It is recommended that you use the default DSL instead.
|
|
69
|
-
|
|
70
|
-
```javascript
|
|
71
|
-
var fstrDefine = require('react/dsl/fstr');
|
|
72
|
-
|
|
73
|
-
function loadUser(uid, cb){ setTimeout(cb, 100, null, "User"+uid); }
|
|
74
|
-
function loadFile(filename, cb){ setTimeout(cb, 100, null, 'Filedata'+filename); }
|
|
75
|
-
function markdown(filedata) { return 'html'+filedata; }
|
|
76
|
-
function prepareDirectory(outDirname, cb){ setTimeout(cb, 200, null, 'dircreated-'+outDirname); }
|
|
77
|
-
function writeOutput(html, user, cb){ setTimeout(cb, 300, null, html+'_bytesWritten'); }
|
|
78
|
-
function loadEmailTemplate(cb) { setTimeout(cb, 50, null, 'emailmd'); }
|
|
79
|
-
function customizeEmail(user, emailHtml, cb) { return 'cust-'+user+emailHtml; }
|
|
80
|
-
function deliverEmail(custEmailHtml, cb) { setTimeout(cb, 100, null, 'delivered-'+custEmailHtml); }
|
|
81
|
-
|
|
82
|
-
function useHtml(err, html, user, bytesWritten) {
|
|
83
|
-
if(err) {
|
|
84
|
-
console.log('***Error: %s', err);
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
console.log('final result: %s, user: %s, written:%s', html, user, bytesWritten);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
var loadAndSave = fstrDefine('filename, uid, outDirname, cb', [ // input params
|
|
91
|
-
loadUser, 'uid -> err, user', // calling async fn loadUser with uid, callback is called with err and user
|
|
92
|
-
loadFile, 'filename -> err, filedata',
|
|
93
|
-
markdown, 'filedata -> returns html', // using a sync function
|
|
94
|
-
prepareDirectory, 'outDirname -> err, dircreated',
|
|
95
|
-
writeOutput, 'html, user -> err, bytesWritten', { after: prepareDirectory }, // only after prepareDirectory done
|
|
96
|
-
loadEmailTemplate, ' -> err, emailmd',
|
|
97
|
-
markdown, 'emailmd -> returns emailHtml', // using a sync function
|
|
98
|
-
customizeEmail, 'user, emailHtml -> returns custEmailHtml',
|
|
99
|
-
deliverEmail, 'custEmailHtml -> err, deliveredEmail', { after: writeOutput } // only after writeOutput is done
|
|
100
|
-
], 'err, html, user, bytesWritten'); // callback output params
|
|
101
|
-
|
|
102
|
-
loadAndSave('file.md', 100, '/tmp/foo', useHtml); // executing the flow
|
|
103
|
-
```
|
package/dsl/chain.js
DELETED
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var sprintf = require('sprintf').sprintf;
|
|
4
|
-
var core = require('../lib/core.js');
|
|
5
|
-
var tutil = require('../lib/task.js');
|
|
6
|
-
|
|
7
|
-
// err for task type cb is implied and thus optional, but allow for clarity.
|
|
8
|
-
var ERROR_NAMES_RE = /^err$/i; // first out param matching this is skipped as being the err object
|
|
9
|
-
|
|
10
|
-
// callback is implied for task type cb is implied and thus optional, but allow for clarity.
|
|
11
|
-
var CALLBACK_NAMES_RE = /^cb$|^callback$/i; // last in param matching this is skipped as being the cb
|
|
12
|
-
|
|
13
|
-
var FlowBuilder;
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
jQuery-like chain interface for defining flow
|
|
17
|
-
|
|
18
|
-
@example
|
|
19
|
-
// normal flow
|
|
20
|
-
var react = require('react');
|
|
21
|
-
var fn = react.chainDefine()
|
|
22
|
-
.in('filename', 'uid', 'outDirname', 'cb')
|
|
23
|
-
.out('err', 'html', 'user', 'bytesWritten')
|
|
24
|
-
.async(loadUser) .in('uid') .out('err', 'user')
|
|
25
|
-
.async(loadFile) .in('filename') .out('err', 'filedata')
|
|
26
|
-
.sync(markdown) .in('filedata') .out('html')
|
|
27
|
-
.async(prepareDirectory) .in('outDirname') .out('err', 'dircreated')
|
|
28
|
-
.async(writeOutput) .in('html', 'user') .out('err', 'bytesWritten') .after('prepareDirectory')
|
|
29
|
-
.async(loadEmailTemplate) .in() .out('err', 'emailmd')
|
|
30
|
-
.sync(markdown) .in('emailmd') .out('emailHtml')
|
|
31
|
-
.sync(customizeEmail) .in('user', 'emailHtml') .out('custEmailHtml')
|
|
32
|
-
.async(deliverEmail) .in('custEmailHtml') .out('err', 'deliveredEmail') .after('writeOutput')
|
|
33
|
-
.end();
|
|
34
|
-
|
|
35
|
-
@example
|
|
36
|
-
// selectFirst flow
|
|
37
|
-
var fn = chainDefine()
|
|
38
|
-
.selectFirst()
|
|
39
|
-
.in('a', 'b', 'cb')
|
|
40
|
-
.out('err', 'c')
|
|
41
|
-
.async(falpha).in('a', 'b', 'cb').out('err', 'c')
|
|
42
|
-
.sync(fbeta).in('a', 'b').out('c')
|
|
43
|
-
.end();
|
|
44
|
-
*/
|
|
45
|
-
function chainDefine() {
|
|
46
|
-
return FlowBuilder.create();
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function FlowBuilder() {
|
|
50
|
-
this.main = {
|
|
51
|
-
name: null,
|
|
52
|
-
options: {}
|
|
53
|
-
};
|
|
54
|
-
this.tasks = [];
|
|
55
|
-
this.focus = this.main;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
FlowBuilder.create = function () { return new FlowBuilder(); };
|
|
59
|
-
|
|
60
|
-
FlowBuilder.prototype.selectFirst = function () {
|
|
61
|
-
this.main.outTaskType = 'finalcbFirst';
|
|
62
|
-
return this;
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
FlowBuilder.prototype.name = function (name) {
|
|
66
|
-
this.focus.name = name;
|
|
67
|
-
return this;
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
FlowBuilder.prototype.in = function (param1, param2, paramN) {
|
|
71
|
-
var args = Array.prototype.slice.call(arguments);
|
|
72
|
-
if (args.length && this.focus.type !== 'ret') { // has args and cb or main
|
|
73
|
-
if (args[args.length - 1].match(CALLBACK_NAMES_RE)) args.pop(); // pop off the cb name if specified
|
|
74
|
-
}
|
|
75
|
-
if (this.focus === this.main) this.focus.in = args;
|
|
76
|
-
else this.focus.a = args; // for tasks
|
|
77
|
-
return this;
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
FlowBuilder.prototype.out = function (param1, param2, paramN) {
|
|
81
|
-
var args = Array.prototype.slice.call(arguments);
|
|
82
|
-
if (args.length && this.focus.type !== 'ret') { // has args and cb or main
|
|
83
|
-
if (args[0].match(ERROR_NAMES_RE)) args.shift(); // shift off err if specified
|
|
84
|
-
}
|
|
85
|
-
this.focus.out = args;
|
|
86
|
-
return this;
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
FlowBuilder.prototype.options = function (options) {
|
|
90
|
-
var self = this;
|
|
91
|
-
if (this.focus === this.main) {
|
|
92
|
-
Object.keys(options).forEach(function (k) { self.focus.options[k] = options[k]; });
|
|
93
|
-
} else { // task so set options right on task
|
|
94
|
-
Object.keys(options).forEach(function (k) { self.focus[k] = options[k]; });
|
|
95
|
-
}
|
|
96
|
-
return this;
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
FlowBuilder.prototype.async = function (funcOrStrMethod) {
|
|
100
|
-
var task = { f: funcOrStrMethod, type: 'cb' };
|
|
101
|
-
this.tasks.push(task);
|
|
102
|
-
this.focus = task;
|
|
103
|
-
return this;
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
FlowBuilder.prototype.sync = function (funcOrStrMethod) {
|
|
107
|
-
var task = { f: funcOrStrMethod, type: 'ret' };
|
|
108
|
-
this.tasks.push(task);
|
|
109
|
-
this.focus = task;
|
|
110
|
-
return this;
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
FlowBuilder.prototype.after = function (name1, name2, nameN) {
|
|
114
|
-
this.focus.after = Array.prototype.slice.call(arguments);
|
|
115
|
-
return this;
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
Complete the building of a flow and perform validation
|
|
120
|
-
which throws error if flow is not valid.
|
|
121
|
-
*/
|
|
122
|
-
FlowBuilder.prototype.end = function end() {
|
|
123
|
-
var reactFn = core();
|
|
124
|
-
|
|
125
|
-
if (this.main.outTaskType === 'finalcbFirst') {
|
|
126
|
-
this.tasks = tutil.serializeTasks(this.tasks);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
var ast = {
|
|
130
|
-
inParams: this.main.in || [],
|
|
131
|
-
tasks: this.tasks,
|
|
132
|
-
outTask: {
|
|
133
|
-
a: this.main.out || [],
|
|
134
|
-
type: this.main.outTaskType || 'finalcb'
|
|
135
|
-
}
|
|
136
|
-
};
|
|
137
|
-
if (this.main.name) ast.name = this.main.name;
|
|
138
|
-
var self = this;
|
|
139
|
-
Object.keys(this.main.options).forEach(function (k) { ast[k] = self.main.options[k]; });
|
|
140
|
-
var errors = reactFn.setAndValidateAST(ast);
|
|
141
|
-
if (errors.length) {
|
|
142
|
-
var errorStr = errors.join('\n');
|
|
143
|
-
throw new Error(errorStr);
|
|
144
|
-
}
|
|
145
|
-
return reactFn;
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
module.exports = chainDefine;
|
|
149
|
-
module.exports.options = core.options;
|
|
150
|
-
module.exports.events = core.events;
|