react 0.0.1 → 0.2.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.
Files changed (69) hide show
  1. package/.npmignore +6 -0
  2. package/Jakefile.js +8 -0
  3. package/README.md +233 -83
  4. package/examples/ast1.js +26 -0
  5. package/examples/chain-events1.js +34 -0
  6. package/examples/chain1.js +19 -0
  7. package/examples/default1.js +40 -0
  8. package/examples/fstr-events1.js +51 -0
  9. package/examples/fstr1.js +36 -0
  10. package/examples/pcode1.js +22 -0
  11. package/jake-tasks/jake-test.js +64 -0
  12. package/lib/base-task.js +115 -0
  13. package/lib/cb-task.js +67 -0
  14. package/lib/chain.js +148 -0
  15. package/lib/core.js +96 -0
  16. package/lib/dsl.js +122 -0
  17. package/lib/error.js +37 -0
  18. package/lib/event-manager.js +57 -0
  19. package/lib/finalcb-first-task.js +59 -0
  20. package/lib/finalcb-task.js +54 -0
  21. package/lib/fstr.js +110 -0
  22. package/lib/id.js +10 -0
  23. package/lib/input-parser.js +44 -0
  24. package/lib/parse.js +29 -0
  25. package/lib/pcode.js +164 -0
  26. package/lib/ret-task.js +67 -0
  27. package/lib/status.js +5 -0
  28. package/lib/task.js +234 -0
  29. package/lib/validate.js +102 -0
  30. package/lib/vcon.js +76 -0
  31. package/oldExamples/analyze.js +29 -0
  32. package/oldExamples/analyze2.js +29 -0
  33. package/oldExamples/example10-dsl.js +63 -0
  34. package/oldExamples/example11.js +62 -0
  35. package/oldExamples/example12.js +63 -0
  36. package/oldExamples/example13.js +63 -0
  37. package/oldExamples/example14.js +63 -0
  38. package/oldExamples/example15.js +75 -0
  39. package/{test → oldExamples}/example6-ast.js +4 -4
  40. package/{test → oldExamples}/example6-dsl.js +3 -2
  41. package/{test → oldExamples}/example8-ast.js +3 -2
  42. package/{test → oldExamples}/example8-dsl.js +3 -2
  43. package/oldExamples/example9-ast.js +58 -0
  44. package/oldExamples/example9-dsl.js +57 -0
  45. package/oldExamples/function-str-ex1.js +33 -0
  46. package/oldExamples/function-str-ex2.js +67 -0
  47. package/oldExamples/trait1.js +41 -0
  48. package/oldExamples/trait2.js +44 -0
  49. package/package.json +16 -6
  50. package/react.js +11 -1
  51. package/test/ast.test.js +69 -0
  52. package/test/cb-task.test.js +197 -0
  53. package/test/chain.test.js +239 -0
  54. package/test/core.test.js +519 -0
  55. package/test/dsl.test.js +237 -0
  56. package/test/event-manager.test.js +102 -0
  57. package/test/exec-options.test.js +32 -0
  58. package/test/finalcb-task.test.js +37 -0
  59. package/test/fstr.test.js +288 -0
  60. package/test/input-parser.test.js +62 -0
  61. package/test/module-use.test.js +317 -0
  62. package/test/pcode.test.js +321 -0
  63. package/test/ret-task.test.js +199 -0
  64. package/test/task.test.js +21 -0
  65. package/test/validate-cb-task.test.js +74 -0
  66. package/test/validate-ret-task.test.js +83 -0
  67. package/test/validate.test.js +218 -0
  68. package/test/vcon.test.js +160 -0
  69. package/lib/react.js +0 -228
@@ -0,0 +1,40 @@
1
+ 'use strict';
2
+ /*jshint white: false */
3
+
4
+ var react = require('../'); // require('react');
5
+
6
+ function loadUser(uid, cb){ setTimeout(cb, 100, null, "User"+uid); }
7
+ function loadFile(filename, cb){ setTimeout(cb, 100, null, 'Filedata'+filename); }
8
+ function markdown(filedata) { return 'html'+filedata; }
9
+ function prepareDirectory(outDirname, cb){ setTimeout(cb, 200, null, 'dircreated-'+outDirname); }
10
+ function writeOutput(html, user, cb){ setTimeout(cb, 300, null, html+'_bytesWritten'); }
11
+ function loadEmailTemplate(cb) { setTimeout(cb, 50, null, 'emailmd'); }
12
+ function customizeEmail(user, emailHtml, cb) { return 'cust-'+user+emailHtml; }
13
+ function deliverEmail(custEmailHtml, cb) { setTimeout(cb, 100, null, 'delivered-'+custEmailHtml); }
14
+
15
+ function useHtml(err, html, user, bytesWritten) {
16
+ if (err) {
17
+ console.log('***Error: %s', err);
18
+ return;
19
+ }
20
+ console.log('final result: %s, user: %s, written:%s', html, user, bytesWritten);
21
+ }
22
+
23
+ // define fn, glue together with react, it will parallelize
24
+ // starts with name and in/out params, then the tasks
25
+ var loadAndSave = react('loadAndSave', 'fName, uid, outDir, cb -> err, html, user, bytes',
26
+ loadUser, 'uid -> err, user', // calling async loadUser with uid, cb called with err and user
27
+ loadFile, 'filename -> err, filedata',
28
+ markdown, 'filedata -> returns html', // using a sync function
29
+ prepareDirectory, 'outDirname -> err, dircreated',
30
+ writeOutput, 'html, user -> err, bytesWritten', { after: prepareDirectory }, // only after prepareDirectory done
31
+ loadEmailTemplate, ' -> err, emailmd',
32
+ markdown, 'emailmd -> returns emailHtml', // using a sync function
33
+ customizeEmail, 'user, emailHtml -> returns custEmailHtml',
34
+ deliverEmail, 'custEmailHtml -> err, deliveredEmail', { after: writeOutput } // only after writeOutput is done
35
+ ); // callback output params
36
+
37
+ //in another module you can use this as any other exported fn
38
+ loadAndSave('file.md', 100, '/tmp/foo', useHtml); // executing the flow
39
+
40
+
@@ -0,0 +1,51 @@
1
+ 'use strict';
2
+
3
+ var react = require('../'); // require('react');
4
+
5
+ //output events as tasks start and complete
6
+ react.events.on('*', function (obj) {
7
+ var time = new Date();
8
+ time.setTime(obj.time);
9
+ var eventTimeStr = time.toISOString();
10
+ var argsNoCb = obj.args.filter(function (a) { return (typeof(a) !== 'function'); });
11
+ if (obj.event === 'task.complete') {
12
+ console.error('%s: %s \tmsecs:(%s) \n\targs:(%s) \n\tresults:(%s)\n',
13
+ obj.event, obj.name, obj.elapsedTime, argsNoCb, obj.results);
14
+ } else {
15
+ console.error('%s: %s \n\targs:(%s)\n', obj.event, obj.name, argsNoCb);
16
+ }
17
+ });
18
+
19
+
20
+ function loadUser(uid, cb){ setTimeout(cb, 100, null, "User"+uid); }
21
+ function loadFile(filename, cb){ setTimeout(cb, 100, null, 'Filedata'+filename); }
22
+ function markdown(filedata) { return 'html'+filedata; }
23
+ function prepareDirectory(outDirname, cb){ setTimeout(cb, 200, null, 'dircreated-'+outDirname); }
24
+ function writeOutput(html, user, cb){ setTimeout(cb, 300, null, html+'_bytesWritten'); }
25
+ function loadEmailTemplate(cb) { setTimeout(cb, 50, null, 'emailmd'); }
26
+ function customizeEmail(user, emailHtml, cb) { return 'cust-'+user+emailHtml; }
27
+ function deliverEmail(custEmailHtml, cb) { setTimeout(cb, 100, null, 'delivered-'+custEmailHtml); }
28
+
29
+ function useHtml(err, html, user, bytesWritten) {
30
+ if(err) {
31
+ console.log('***Error: %s', err);
32
+ return;
33
+ }
34
+ console.log('final result: %s, user: %s, written:%s', html, user, bytesWritten);
35
+ }
36
+
37
+ var loadAndSave = react.fstrDefine('filename, uid, outDirname, cb', [ // input params
38
+ loadUser, 'uid -> err, user', // calling async fn loadUser with uid, callback is called with err and user
39
+ loadFile, 'filename -> err, filedata',
40
+ markdown, 'filedata -> returns html', // using a sync function
41
+ prepareDirectory, 'outDirname -> err, dircreated',
42
+ writeOutput, 'html, user -> err, bytesWritten', { after: prepareDirectory }, // only after prepareDirectory done
43
+ loadEmailTemplate, ' -> err, emailmd',
44
+ markdown, 'emailmd -> returns emailHtml', // using a sync function
45
+ customizeEmail, 'user, emailHtml -> returns custEmailHtml',
46
+ deliverEmail, 'custEmailHtml -> err, deliveredEmail', { after: writeOutput } // only after writeOutput is done
47
+ ], 'err, html, user, bytesWritten'); // callback output params
48
+
49
+ loadAndSave('file.md', 100, '/tmp/foo', useHtml); // executing the flow
50
+
51
+
@@ -0,0 +1,36 @@
1
+ 'use strict';
2
+
3
+ var react = require('../'); // require('react');
4
+
5
+ function loadUser(uid, cb){ setTimeout(cb, 100, null, "User"+uid); }
6
+ function loadFile(filename, cb){ setTimeout(cb, 100, null, 'Filedata'+filename); }
7
+ function markdown(filedata) { return 'html'+filedata; }
8
+ function prepareDirectory(outDirname, cb){ setTimeout(cb, 200, null, 'dircreated-'+outDirname); }
9
+ function writeOutput(html, user, cb){ setTimeout(cb, 300, null, html+'_bytesWritten'); }
10
+ function loadEmailTemplate(cb) { setTimeout(cb, 50, null, 'emailmd'); }
11
+ function customizeEmail(user, emailHtml, cb) { return 'cust-'+user+emailHtml; }
12
+ function deliverEmail(custEmailHtml, cb) { setTimeout(cb, 100, null, 'delivered-'+custEmailHtml); }
13
+
14
+ function useHtml(err, html, user, bytesWritten) {
15
+ if(err) {
16
+ console.log('***Error: %s', err);
17
+ return;
18
+ }
19
+ console.log('final result: %s, user: %s, written:%s', html, user, bytesWritten);
20
+ }
21
+
22
+ var loadAndSave = react.fstrDefine('filename, uid, outDirname, cb', [ // input params
23
+ loadUser, 'uid -> err, user', // calling async fn loadUser with uid, callback is called with err and user
24
+ loadFile, 'filename -> err, filedata',
25
+ markdown, 'filedata -> returns html', // using a sync function
26
+ prepareDirectory, 'outDirname -> err, dircreated',
27
+ writeOutput, 'html, user -> err, bytesWritten', { after: prepareDirectory }, // only after prepareDirectory done
28
+ loadEmailTemplate, ' -> err, emailmd',
29
+ markdown, 'emailmd -> returns emailHtml', // using a sync function
30
+ customizeEmail, 'user, emailHtml -> returns custEmailHtml',
31
+ deliverEmail, 'custEmailHtml -> err, deliveredEmail', { after: writeOutput } // only after writeOutput is done
32
+ ], 'err, html, user, bytesWritten'); // callback output params
33
+
34
+ loadAndSave('file.md', 100, '/tmp/foo', useHtml); // executing the flow
35
+
36
+
@@ -0,0 +1,22 @@
1
+ 'use strict';
2
+
3
+ var react = require('../'); // require('react');
4
+
5
+ function multiply(a, b, cb) { cb(null, a * b); }
6
+ function add(a, b) { return a + b; }
7
+ var locals = { // since pcodeDefine uses strings, need references to functions passed into react
8
+ multiply: multiply,
9
+ add: add
10
+ };
11
+
12
+ var fn = react.pcodeDefine('a, b, cb', [ // input params
13
+ 'm := multiply(a, b)', // using a callback function, use :=
14
+ 's = add(m, a)', // using a sync function, use =
15
+ 'cb(err, m, s)' // output params for final callback
16
+ ], locals); // hash of functions that will be used
17
+
18
+ fn(2, 3, function (err, m, s) {
19
+ console.error('err:', err); // null
20
+ console.error('m:', m); // 2 * 3 = 6
21
+ console.error('s:', s); // 6 + 2 = 8
22
+ });
@@ -0,0 +1,64 @@
1
+
2
+ var watch = require('watch');
3
+ var cp = require('child_process');
4
+
5
+ namespace('test', function () {
6
+
7
+ var watchdir = '.';
8
+ var cmd = 'tapper ./test';
9
+
10
+ var alreadyExecuting = false;
11
+
12
+ function execAndOutput(cmd){
13
+ if(!alreadyExecuting){
14
+ alreadyExecuting = true;
15
+ console.log("Executing cmd:", cmd);
16
+ cp.exec(cmd, function(err, stdout, stderr){
17
+ if(err && err.message) console.log(err.message);
18
+ console.log(stdout);
19
+ console.error(stderr);
20
+ alreadyExecuting = false;
21
+ });
22
+ }
23
+ }
24
+
25
+ function filterWatch(f){
26
+ if(/flymake/.test(f)) return false; //ignore flymake files
27
+ if(/^\.|\/\./.test(f)) return false; //ignore hidden files or dirs
28
+ console.log(f);
29
+ return true;
30
+ }
31
+
32
+ desc('watch and run tests');
33
+ task('watch', ['test:run'], function () {
34
+ // watch the watchdir and if anything changes, rerun the command
35
+ watch.createMonitor(watchdir, { ignoreDotFiles: true }, function(monitor) {
36
+ monitor.on("created", function(f, stat){ if(filterWatch(f)) execAndOutput(cmd); });
37
+ monitor.on("changed", function(f, curr, prev){
38
+ if(filterWatch(f) && curr.mtime > prev.mtime) {
39
+ //console.log(prev.mtime);
40
+ console.log(curr.mtime);
41
+ execAndOutput(cmd);
42
+ }
43
+ });
44
+ monitor.on("removed", function(f, stat){ if(filterWatch(f)) execAndOutput(cmd); });
45
+ });
46
+ });
47
+
48
+
49
+ desc('run tests');
50
+ task('run', [], function (cmdarg1, cmdarg2, cmdargN) {
51
+ execAndOutput(cmd);
52
+ });
53
+
54
+ });
55
+
56
+
57
+
58
+
59
+
60
+
61
+
62
+
63
+
64
+
@@ -0,0 +1,115 @@
1
+ 'use strict';
2
+
3
+ var array = require('ensure-array');
4
+ var STATUS = require('./status.js');
5
+ var EventManager = require('./event-manager.js');
6
+
7
+ function BaseTask() {
8
+ }
9
+
10
+ /**
11
+ Getter Fn to retrieveAn array of the output param names for this task.
12
+ */
13
+ BaseTask.prototype.getOutParams = function () {
14
+ return array(this.out); // ensure array
15
+ };
16
+
17
+ BaseTask.prototype.isComplete = function () {
18
+ return (this.status === STATUS.COMPLETE);
19
+ };
20
+
21
+ BaseTask.prototype.start = function (args) { // mark task as started with args and note time
22
+ this.args = args;
23
+ this.startTime = Date.now();
24
+ if (this.flowEmitter) this.flowEmitter.emitObject(EventManager.TYPES.TASK_BEGIN, this);
25
+ };
26
+
27
+ BaseTask.prototype.complete = function (args) { //args that were used are available
28
+ this.results = args; // save the results
29
+ this.endTime = Date.now();
30
+ this.elapsedTime = this.endTime - this.startTime;
31
+ if (this.flowEmitter) this.flowEmitter.emitObject(EventManager.TYPES.TASK_COMPLETE, this);
32
+ this.status = STATUS.COMPLETE;
33
+ };
34
+
35
+ BaseTask.prototype.functionExists = function (vCon) {
36
+ var fn = this.f;
37
+ if (!fn) return false;
38
+ if (fn instanceof Function) return true;
39
+ if (typeof(fn) === 'string') {
40
+ var f = vCon.getVar(fn); // fn/method by string
41
+ if (f && f instanceof Function) return true;
42
+ }
43
+ return false;
44
+ };
45
+
46
+ BaseTask.prototype.areAllDepArgsDefined = function (vCon) {
47
+ return this.a.every(function (k) { return (vCon.getVar(k) !== undefined); });
48
+ };
49
+
50
+ BaseTask.prototype.depTasksAreDone = function (tasksByName) {
51
+ return (!this.after || !this.after.length || // no dep tasks OR
52
+ this.after.every(function (n) { return tasksByName[n].isComplete(); })); //all done
53
+ };
54
+
55
+ function isObjProperty(str) { return (str.indexOf('.') !== -1); }
56
+
57
+ /**
58
+ check that obj parent is def and not null so writing to obj.prop
59
+ will not fail. ex: 'b.c' checks that b is def and not null.
60
+ Also returns true if not obj.prop but simple var ex: 'b'.
61
+ Tasks will implement outParentsExist() passing each out str
62
+ to this if they want to do this check.
63
+ */
64
+ BaseTask.prototype.parentExists = function (objPropStr, vCon) {
65
+ if (!isObjProperty(objPropStr)) return true; // NOT obj prop, just simple arg, ret true
66
+ var nameAndProps = objPropStr.split('.');
67
+ nameAndProps.pop(); // pop off final prop
68
+ var parent = nameAndProps.reduce(function (accObj, prop) {
69
+ if (accObj === undefined || accObj === null) return undefined; // prevent exception
70
+ return accObj[prop];
71
+ }, vCon.values); // vCon['foo']['bar']
72
+ return (parent !== undefined && parent !== null);
73
+ };
74
+
75
+ /**
76
+ If params are obj property writes make sure the dst objects
77
+ are defined and not null. cb: ['b.c'] -> b is def and not null.
78
+ If null is specified then param is valid and will be ignored.
79
+ @returns true if all obj prop parents are def and non null
80
+ */
81
+ BaseTask.prototype.outParentsExist = function (vCon) {
82
+ var self = this;
83
+ return this.getOutParams().every(function (x) {
84
+ if (x === null) return true;
85
+ return self.parentExists(x, vCon);
86
+ });
87
+ };
88
+
89
+ BaseTask.prototype.isReady = function (vCon, tasksByName) {
90
+ return !this.status && // not started AND
91
+ this.functionExists(vCon) && // function/method exists AND
92
+ this.areAllDepArgsDefined(vCon) && // all dep vars defined AND
93
+ this.depTasksAreDone(tasksByName) && // all dep tasks are done AND
94
+ (!this.outParentsExist || // (task does not implement outParentsExist method OR
95
+ this.outParentsExist(vCon)); // output parents exists (for obj property writes)
96
+ };
97
+
98
+ BaseTask.prototype.isMethodCall = function () {
99
+ return (typeof(this.f) === 'string' && /^.*\..*$/.test(this.f)); //str contains .
100
+ };
101
+
102
+ BaseTask.prototype.getMethodObj = function (vCon) { //obj.prop.prop2, returns obj.prop or undefined
103
+ var name = this.f;
104
+ if (!name) return undefined;
105
+ var nameAndProps = name.split('.');
106
+ nameAndProps.pop(); // pop off last one
107
+ if (!nameAndProps.length) return undefined;
108
+ var result = nameAndProps.reduce(function (accObj, prop) {
109
+ if (accObj === undefined || accObj === null) return undefined; // prevent exception
110
+ return accObj[prop];
111
+ }, vCon.values); // vCon['foo']['bar']
112
+ return result;
113
+ };
114
+
115
+ module.exports = BaseTask;
package/lib/cb-task.js ADDED
@@ -0,0 +1,67 @@
1
+ 'use strict';
2
+
3
+ var util = require('util');
4
+ var sprintf = require('sprintf').sprintf;
5
+
6
+ var BaseTask = require('./base-task.js');
7
+
8
+ function format_error(errmsg, obj) {
9
+ return sprintf('%s - %s', errmsg, util.inspect(obj));
10
+ }
11
+
12
+ var REQ = 'cbTask requires f, a, out';
13
+ var FN_REQ = 'cbTask requires f to be a function or string';
14
+ var A_REQ = 'cbTask requires a to be an array of string param names';
15
+ var CB_REQ = 'cbTask requires out to be an array of string param names';
16
+
17
+ function CbTask(taskDef) {
18
+ var self = this;
19
+ Object.keys(taskDef).forEach(function (k) { self[k] = taskDef[k]; });
20
+ }
21
+
22
+ CbTask.prototype = new BaseTask();
23
+ CbTask.prototype.constructor = CbTask;
24
+
25
+ CbTask.validate = function (taskDef) {
26
+ var errors = [];
27
+ if (!taskDef.f || !taskDef.a || !taskDef.out) {
28
+ errors.push(format_error(REQ, taskDef));
29
+ } else {
30
+ var ftype = typeof(taskDef.f);
31
+ if (! ((taskDef.f instanceof Function) || (ftype === 'string'))) {
32
+ errors.push(format_error(FN_REQ, taskDef));
33
+ }
34
+ if (! (Array.isArray(taskDef.a) &&
35
+ taskDef.a.every(function (x) { return (typeof(x) === 'string'); }))) {
36
+ errors.push(format_error(A_REQ, taskDef));
37
+ }
38
+ if (! (Array.isArray(taskDef.out) &&
39
+ taskDef.out.every(function (x) { return (typeof(x) === 'string'); }))) {
40
+ errors.push(format_error(CB_REQ, taskDef));
41
+ }
42
+ }
43
+ return errors;
44
+ };
45
+
46
+ CbTask.prototype.exec = function exec(vCon, handleError, contExec) {
47
+ try {
48
+ var args = this.a.map(function (k) { return vCon.getVar(k); }); //get args from vCon
49
+ //console.error('CbTask.exec.args=', args);
50
+ //console.error('CbTask.exec.vCon=', vCon);
51
+ this.start(args); //note the start time, args
52
+ args.push(this.cbFun); // push callback fn on end
53
+ var func = this.f;
54
+ var bindObj = null; //global space
55
+ if (this.isMethodCall()) { //if method call then reset func and bindObj
56
+ func = vCon.getVar(this.f);
57
+ bindObj = this.getMethodObj(vCon);
58
+ } else if (typeof(func) === 'string') {
59
+ func = vCon.getVar(func); // we want the actual fn from this string
60
+ }
61
+ func.apply(bindObj, args);
62
+ } catch (err) { //catch and handle the task error, calling final cb
63
+ handleError(this, err);
64
+ }
65
+ };
66
+
67
+ module.exports = CbTask;
package/lib/chain.js ADDED
@@ -0,0 +1,148 @@
1
+ 'use strict';
2
+
3
+ var sprintf = require('sprintf').sprintf;
4
+ var core = require('./core.js');
5
+ var tutil = require('./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;