react 0.2.4 → 0.3.4

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 (65) hide show
  1. package/README.md +146 -94
  2. package/doc/alternate-dsls.md +103 -0
  3. package/{lib → dsl}/chain.js +5 -3
  4. package/{lib → dsl}/fstr.js +17 -6
  5. package/{lib → dsl}/pcode.js +19 -8
  6. package/examples/chain-events1.js +28 -7
  7. package/examples/chain1.js +2 -2
  8. package/examples/default-events1.js +33 -6
  9. package/examples/default-log-events.js +43 -0
  10. package/examples/fstr-events1.js +4 -17
  11. package/examples/fstr1.js +3 -2
  12. package/examples/pcode1.js +2 -2
  13. package/lib/base-task.js +8 -6
  14. package/lib/cb-task.js +14 -1
  15. package/lib/core.js +46 -15
  16. package/lib/dsl.js +14 -6
  17. package/lib/event-manager.js +29 -15
  18. package/lib/finalcb-first-task.js +16 -10
  19. package/lib/finalcb-task.js +17 -10
  20. package/lib/input-parser.js +7 -3
  21. package/lib/log-events.js +71 -0
  22. package/lib/parse.js +6 -3
  23. package/lib/promise-task.js +89 -0
  24. package/lib/ret-task.js +1 -1
  25. package/lib/task.js +32 -23
  26. package/lib/track-tasks.js +117 -0
  27. package/lib/validate.js +14 -5
  28. package/lib/vcon.js +8 -3
  29. package/lib/when-task.js +81 -0
  30. package/package.json +4 -2
  31. package/promise-resolve.js +35 -0
  32. package/react.js +0 -4
  33. package/test/core-deferred.test.js +134 -0
  34. package/test/core-promised.test.js +132 -0
  35. package/test/core-when.test.js +84 -0
  36. package/test/core.test.js +108 -60
  37. package/test/dsl.test.js +58 -6
  38. package/test/{chain.test.js → dsl/chain.test.js} +85 -1
  39. package/test/{fstr.test.js → dsl/fstr.test.js} +13 -1
  40. package/test/{pcode.test.js → dsl/pcode.test.js} +128 -1
  41. package/test/exec-options.test.js +2 -1
  42. package/test/finalcb-task.test.js +6 -5
  43. package/test/input-parser.test.js +10 -6
  44. package/test/module-use.test.js +13 -199
  45. package/test/promise-auto-resolve.test.js +51 -0
  46. package/test/validate.test.js +30 -1
  47. package/test/vcon.test.js +13 -0
  48. package/oldExamples/analyze.js +0 -29
  49. package/oldExamples/analyze2.js +0 -29
  50. package/oldExamples/example10-dsl.js +0 -63
  51. package/oldExamples/example11.js +0 -62
  52. package/oldExamples/example12.js +0 -63
  53. package/oldExamples/example13.js +0 -63
  54. package/oldExamples/example14.js +0 -63
  55. package/oldExamples/example15.js +0 -75
  56. package/oldExamples/example6-ast.js +0 -47
  57. package/oldExamples/example6-dsl.js +0 -49
  58. package/oldExamples/example8-ast.js +0 -55
  59. package/oldExamples/example8-dsl.js +0 -53
  60. package/oldExamples/example9-ast.js +0 -58
  61. package/oldExamples/example9-dsl.js +0 -57
  62. package/oldExamples/function-str-ex1.js +0 -33
  63. package/oldExamples/function-str-ex2.js +0 -67
  64. package/oldExamples/trait1.js +0 -41
  65. package/oldExamples/trait2.js +0 -44
@@ -1,15 +1,24 @@
1
1
  'use strict';
2
+ /*jshint regexp: false */
2
3
 
3
4
  var sprintf = require('sprintf').sprintf;
4
- var core = require('./core.js');
5
- var parse = require('./parse.js');
6
- var tutil = require('./task.js');
5
+ var core = require('../lib/core.js');
6
+ var parse = require('../lib/parse.js');
7
+ var tutil = require('../lib/task.js');
7
8
 
8
9
  var INPARAMS_NO_MATCH = 'input params in wrong format, wanted "foo, bar, cb" - found: %s';
9
10
  var OUTPARAMS_NO_MATCH = 'output params in wrong format, wanted "cb(err, foo)" - found: %s';
10
11
  var INOUT_PARAMS_NO_MATCH = 'task params in wrong format, wanted "foo, bar := func(baz, cat, cb) " - found: %s';
11
12
  var EXTRA_TASKARG = 'extra unmatched task arg: %s';
12
13
 
14
+ var ERR_NAMES_RE = /^err$/i; // err, ERR, Err, ...
15
+
16
+ function filterOutLeadingErrParam(args) { // if leading err param, filter it out
17
+ if (args.length && args[0].match(ERR_NAMES_RE)) args.shift();
18
+ return args;
19
+ }
20
+
21
+
13
22
  /**
14
23
  Examples:
15
24
  var react = require('react');
@@ -54,7 +63,7 @@ var inParse = {
54
63
  };
55
64
 
56
65
  var cbParse = {
57
- regex: /^\s*(var\s+)?([^:]*)\s*:=\s*([a-zA-Z0-9_\.-]+)\s*\(\s*([^)]*)\)\s*(when\s+([^;]+))?;?\s*$/,
66
+ regex: /^\s*(var\s+)?([^:]*)\s*:=\s*([a-zA-Z0-9_\.\-]+)\s*\(\s*([^)]*)\)\s*(when\s+([^;]+))?;?\s*$/,
58
67
  fn: function (m) {
59
68
  var taskDef = {
60
69
  type: 'cb',
@@ -68,7 +77,7 @@ var cbParse = {
68
77
  };
69
78
 
70
79
  var retParse = {
71
- regex: /^\s*(var\s+)?([^:]*)\s*=\s*([a-zA-Z0-9_\.-]+)\s*\(\s*([^)]*)\)\s*(when\s+([^;]+))?;?\s*$/,
80
+ regex: /^\s*(var\s+)?([^:]*)\s*=\s*([a-zA-Z0-9_\.\-]+)\s*\(\s*([^)]*)\)\s*(when\s+([^;]+))?;?\s*$/,
72
81
  fn: function (m) {
73
82
  var taskDef = {
74
83
  type: 'ret',
@@ -82,10 +91,10 @@ var retParse = {
82
91
  };
83
92
 
84
93
  var finalCbParse = {
85
- regex: /^\s*(cb|callback)\s*\((er{0,2}\s*,\s*)?([^)]*)\)\s*;?$/i,
94
+ regex: /^\s*(cb|callback)\s*\(([^)]*)\)\s*;?$/i,
86
95
  fn: function (m) {
87
96
  return {
88
- outDef: (m[3]) ? parse.splitTrimFilterArgs(m[3]) : []
97
+ outDef: (m[2]) ? filterOutLeadingErrParam(parse.splitTrimFilterArgs(m[2])) : []
89
98
  };
90
99
  }
91
100
  };
@@ -161,4 +170,6 @@ function selectFirst(inParamStr, taskStrArr, locals, options) {
161
170
  }
162
171
 
163
172
  module.exports = pcodeDefine;
164
- module.exports.selectFirst = selectFirst;
173
+ module.exports.selectFirst = selectFirst;
174
+ module.exports.options = core.options;
175
+ module.exports.events = core.events;
@@ -1,26 +1,47 @@
1
1
  'use strict';
2
2
 
3
- var react = require('../'); // require('react');
3
+ var chainDefine = require('../dsl/chain'); // require('react/dsl/chain');
4
+ require('../lib/track-tasks'); // require('react/lib/track-tasks'); // turn on tracking
4
5
 
5
6
  //output events as tasks start and complete
6
- react.events.on('*', function (obj) {
7
+ chainDefine.events.on('flow.*', function (obj) {
8
+ /*jshint validthis: true */
7
9
  var time = new Date();
8
10
  time.setTime(obj.time);
9
- var eventTimeStr = time.toISOString();
10
11
  var argsNoCb = obj.args.filter(function (a) { return (typeof(a) !== 'function'); });
11
- if (obj.event === 'task.complete') {
12
+ var eventTimeStr = time.toISOString();
13
+ if (this.event === 'flow.complete') {
14
+ var env = obj;
12
15
  console.error('%s: %s \tmsecs:(%s) \n\targs:(%s) \n\tresults:(%s)\n',
13
- obj.event, obj.name, obj.elapsedTime, argsNoCb, obj.results);
16
+ this.event, env.name, env.elapsedTime, argsNoCb, env.results);
14
17
  } else {
15
- console.error('%s: %s \n\targs:(%s)\n', obj.event, obj.name, argsNoCb);
18
+ var name = obj.name;
19
+ var args = obj.args;
20
+ console.error('%s: %s \n\targs:(%s)\n', this.event, name, argsNoCb);
16
21
  }
17
22
  });
18
23
 
24
+ chainDefine.events.on('task.*', function (obj) {
25
+ /*jshint validthis: true */
26
+ var time = new Date();
27
+ time.setTime(obj.time);
28
+ var argsNoCb = obj.args.filter(function (a) { return (typeof(a) !== 'function'); });
29
+ var eventTimeStr = time.toISOString();
30
+ if (this.event === 'task.complete') {
31
+ var task = obj;
32
+ console.error('%s: %s \tmsecs:(%s) \n\targs:(%s) \n\tresults:(%s)\n',
33
+ this.event, task.name, task.elapsedTime, argsNoCb, task.results);
34
+ } else {
35
+ var name = obj.name;
36
+ var args = obj.args;
37
+ console.error('%s: %s \n\targs:(%s)\n', this.event, name, argsNoCb);
38
+ }
39
+ });
19
40
 
20
41
  function multiply(a, b, cb) { cb(null, a * b); }
21
42
  function add(a, b) { return a + b; }
22
43
 
23
- var fn = react.chainDefine()
44
+ var fn = chainDefine()
24
45
  .in('a', 'b', 'cb') // input params
25
46
  .out('err', 'm', 's') // final callback output params
26
47
  .async(multiply).in('a', 'b', 'cb').out('err', 'm') // task def - async fn, in params, callback out params
@@ -1,11 +1,11 @@
1
1
  'use strict';
2
2
 
3
- var react = require('../'); // require('react');
3
+ var chainDefine = require('../dsl/chain'); // require('react/dsl/chain');
4
4
 
5
5
  function multiply(a, b, cb) { cb(null, a * b); }
6
6
  function add(a, b) { return a + b; }
7
7
 
8
- var fn = react.chainDefine()
8
+ var fn = chainDefine()
9
9
  .in('a', 'b', 'cb') // input params
10
10
  .out('err', 'm', 's') // final callback output params
11
11
  .async(multiply).in('a', 'b', 'cb').out('err', 'm') // task def - async fn, in params, callback out params
@@ -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('*', function (obj) {
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
- if (obj.event === 'task.complete') {
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
- obj.event, obj.name, obj.elapsedTime, argsNoCb, obj.results);
38
+ this.event, task.name, task.elapsedTime, argsNoCb, task.results);
15
39
  } else {
16
- console.error('%s: %s \n\targs:(%s)\n', obj.event, obj.name, argsNoCb);
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 -> err, custEmailHtml', // sync fn
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
 
@@ -0,0 +1,43 @@
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/log-events').logEvents(react); // require('react/lib/log-events').logEvents(react); // turn on logging
10
+
11
+
12
+ function loadUser(uid, cb){ setTimeout(cb, 100, null, "User"+uid); }
13
+ function loadFile(filename, cb){ setTimeout(cb, 100, null, 'Filedata'+filename); }
14
+ function markdown(filedata) { return 'html'+filedata; }
15
+ function prepareDirectory(outDirname, cb){ setTimeout(cb, 200, null, 'dircreated-'+outDirname); }
16
+ function writeOutput(html, user, cb){ setTimeout(cb, 300, null, html+'_bytesWritten'); }
17
+ function loadEmailTemplate(cb) { setTimeout(cb, 50, null, 'emailmd'); }
18
+ function customizeEmail(user, emailHtml) { return 'cust-'+user+emailHtml; }
19
+ function deliverEmail(custEmailHtml, cb) { setTimeout(cb, 100, null, 'delivered-'+custEmailHtml); }
20
+
21
+ function useHtml(err, html, user, bytesWritten) {
22
+ if (err) {
23
+ console.log('***Error: %s', err);
24
+ return;
25
+ }
26
+ console.log('final result: %s, user: %s, written:%s', html, user, bytesWritten);
27
+ }
28
+
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
+ );
40
+
41
+ loadAndSave('file.md', 100, '/tmp/foo', useHtml); // executing the flow
42
+
43
+
@@ -1,21 +1,8 @@
1
1
  'use strict';
2
+ /*jshint white: false */
2
3
 
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
-
4
+ var fstr = require('../dsl/fstr'); // require('react/dsl/fstr');
5
+ require('../lib/log-events').logEvents(fstr); // require('react/lib/log-events').logEvents(react);
19
6
 
20
7
  function loadUser(uid, cb){ setTimeout(cb, 100, null, "User"+uid); }
21
8
  function loadFile(filename, cb){ setTimeout(cb, 100, null, 'Filedata'+filename); }
@@ -34,7 +21,7 @@ function useHtml(err, html, user, bytesWritten) {
34
21
  console.log('final result: %s, user: %s, written:%s', html, user, bytesWritten);
35
22
  }
36
23
 
37
- var loadAndSave = react.fstrDefine('filename, uid, outDirname, cb', [ // input params
24
+ var loadAndSave = fstr('filename, uid, outDirname, cb', [ // input params
38
25
  loadUser, 'uid -> err, user', // calling async fn loadUser with uid, callback is called with err and user
39
26
  loadFile, 'filename -> err, filedata',
40
27
  markdown, 'filedata -> returns html', // using a sync function
package/examples/fstr1.js CHANGED
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
+ /*jshint white: false */
2
3
 
3
- var react = require('../'); // require('react');
4
+ var fstr = require('../dsl/fstr'); // require('react/dsl/fstr');
4
5
 
5
6
  function loadUser(uid, cb){ setTimeout(cb, 100, null, "User"+uid); }
6
7
  function loadFile(filename, cb){ setTimeout(cb, 100, null, 'Filedata'+filename); }
@@ -19,7 +20,7 @@ function useHtml(err, html, user, bytesWritten) {
19
20
  console.log('final result: %s, user: %s, written:%s', html, user, bytesWritten);
20
21
  }
21
22
 
22
- var loadAndSave = react.fstrDefine('filename, uid, outDirname, cb', [ // input params
23
+ var loadAndSave = fstr('filename, uid, outDirname, cb', [ // input params
23
24
  loadUser, 'uid -> err, user', // calling async fn loadUser with uid, callback is called with err and user
24
25
  loadFile, 'filename -> err, filedata',
25
26
  markdown, 'filedata -> returns html', // using a sync function
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var react = require('../'); // require('react');
3
+ var pcodeDefine = require('../dsl/pcode'); // require('react/dsl/pcode');
4
4
 
5
5
  function multiply(a, b, cb) { cb(null, a * b); }
6
6
  function add(a, b) { return a + b; }
@@ -9,7 +9,7 @@ var locals = { // since pcodeDefine uses strings, need references to functions
9
9
  add: add
10
10
  };
11
11
 
12
- var fn = react.pcodeDefine('a, b, cb', [ // input params
12
+ var fn = pcodeDefine('a, b, cb', [ // input params
13
13
  'm := multiply(a, b)', // using a callback function, use :=
14
14
  's = add(m, a)', // using a sync function, use =
15
15
  'cb(err, m, s)' // output params for final callback
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.startTime = Date.now();
24
- if (this.flowEmitter) this.flowEmitter.emitObject(EventManager.TYPES.TASK_BEGIN, this);
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
- 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);
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 = null; //global space
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,16 +7,25 @@ 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');
14
13
 
15
14
  var reactOptions = {
16
- stackTraceLimitMin: 30
15
+ stackTraceLimitMin: 30
17
16
  };
18
17
 
19
- var reactEmitter = EventManager.create(); // the top emitter
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
@@ -39,7 +48,7 @@ var reactEmitter = EventManager.create(); // the top emitter
39
48
  */
40
49
  function reactFactory() {
41
50
  if (arguments.length) throw new Error('react() takes no args, check API');
42
-
51
+
43
52
  error.ensureStackTraceLimitSet(reactOptions.stackTraceLimitMin);
44
53
  var flowEmitter = EventManager.create();
45
54
  flowEmitter.parent = reactEmitter;
@@ -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
- var parsedInput = inputParser(Array.prototype.slice.call(arguments), ast);
64
- var args = parsedInput.args;
65
- var cbFinal = parsedInput.cb;
66
- var extraArgs = parsedInput.extraArgs; // we'll have these if we need them
67
- var vCon = VContext.create(args, ast.inParams, ast.locals); // create var ctx with in args & locals
68
- var tasks = ast.tasks.map(tskutil.create);
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(ast.outTask, cbFinal, tasks, vCon);
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.flowEmitter = flowEmitter;
82
- if (t.type === 'cb') t.cbFun = tskutil.createCallback(t, handleError, vCon, contExec, flowEmitter);
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