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,160 @@
1
+ 'use strict';
2
+
3
+ var test = require('tap').test;
4
+
5
+ var VContext = require('../lib/vcon.js');
6
+
7
+ test('VContext.create with empty args returns empty vCon', function (t) {
8
+ t.deepEqual(VContext.create([], []).values, {}, 'should be empty object');
9
+ t.deepEqual(VContext.create([], ['a']).values, {}, 'should be empty object');
10
+ t.end();
11
+ });
12
+
13
+ test('VContext.create with more args than params, ignore extra args', function (t) {
14
+ t.deepEqual(VContext.create([1], []).values, {}, 'should be empty object');
15
+ t.deepEqual(VContext.create([1, 2], ['a']).values, { a: 1 },
16
+ 'should be object with one value');
17
+ t.end();
18
+ });
19
+
20
+ test('VContext.create sets vCon[paramName] to arg value', function (t) {
21
+ t.deepEqual(VContext.create([1, 2], ['a', 'b']).values, { a: 1, b: 2 },
22
+ 'should have all values');
23
+ t.end();
24
+ });
25
+
26
+ test('create with locals is merged with args taking precedence', function (t) {
27
+ var locals = { a: 11, c: 30 };
28
+ t.deepEqual(VContext.create([1, 2], ['a', 'b'], locals).values,
29
+ { a: 1, c: 30, b: 2 }, 'should have merge of values');
30
+ t.end();
31
+ });
32
+
33
+ test('create with locals should not modify original locals', function (t) {
34
+ var locals = { a: 11, c: 30 };
35
+ t.deepEqual(VContext.create([1, 2], ['a', 'b'], locals).values,
36
+ { a: 1, c: 30, b: 2 }, 'should have merge of values');
37
+ t.deepEqual(locals, { a: 11, c: 30 }, 'should not modify original locals object');
38
+ t.end();
39
+ });
40
+
41
+ test('getVar on null returns null', function (t) {
42
+ t.equal(VContext.create([null], ['a']).getVar('a'), null);
43
+ t.equal(VContext.create([{ b: null }], ['a']).getVar('a.b'), null);
44
+ t.end();
45
+ });
46
+
47
+ test('getVar on undefined or null parent returns undefined', function (t) {
48
+ t.equal(VContext.create([], []).getVar('a'), undefined);
49
+ t.equal(VContext.create([], ['a']).getVar('a'), undefined);
50
+ t.equal(VContext.create([], ['a']).getVar('a.b'), undefined);
51
+ t.equal(VContext.create([], ['a']).getVar('a.b.c'), undefined);
52
+ t.equal(VContext.create([null], ['a']).getVar('a.b'), undefined);
53
+ t.equal(VContext.create([null], ['a']).getVar('a.b.c'), undefined);
54
+ t.equal(VContext.create([1], ['a']).getVar('a.b'), undefined);
55
+ t.equal(VContext.create([1], ['a']).getVar('a.b.c'), undefined);
56
+ t.end();
57
+ });
58
+
59
+ test('simple getVar returns existing value', function (t) {
60
+ t.equal(VContext.create([null], ['a']).getVar('a'), null);
61
+ t.equal(VContext.create([1], ['a']).getVar('a'), 1);
62
+ t.equal(VContext.create([true], ['a']).getVar('a'), true);
63
+ t.equal(VContext.create(['banana'], ['a']).getVar('a'), 'banana');
64
+ t.end();
65
+ });
66
+
67
+ test('getVar on literals returns the literal', function (t) {
68
+ t.equal(VContext.create([], []).getVar(true), true);
69
+ t.equal(VContext.create([], []).getVar(false), false);
70
+ t.equal(VContext.create([], []).getVar(-100), -100);
71
+ t.equal(VContext.create([], []).getVar(100), 100);
72
+ t.equal(VContext.create([], []).getVar(123.4), 123.4);
73
+ t.equal(VContext.create([], []).getVar(-987.6), -987.6);
74
+ t.equal(VContext.create([], []).getVar('"foo"'), 'foo');
75
+ t.equal(VContext.create([], []).getVar("'foo'"), 'foo');
76
+ t.end();
77
+ });
78
+
79
+ test('getVar for property returns the property', function (t) {
80
+ var o = { b: 100};
81
+ t.equal(VContext.create([o], ['a']).getVar('a.b'), 100);
82
+ o = { b: { c: 200 }};
83
+ t.equal(VContext.create([o], ['a']).getVar('a.b.c'), 200);
84
+ t.end();
85
+ });
86
+
87
+ test('setVar will create objects if needed', function (t) {
88
+ var v = VContext.create([], []);
89
+ v.setVar('foo.bar.baz', 100);
90
+ t.deepEqual(v.values, { foo: { bar: { baz: 100}}});
91
+ t.end();
92
+ });
93
+
94
+ test('simple setVar', function (t) {
95
+ var v = VContext.create([], []);
96
+ v.setVar('foo', 100);
97
+ t.deepEqual(v.values, { foo: 100});
98
+ t.end();
99
+ });
100
+
101
+ test('setVar will not affect other vars', function (t) {
102
+ var v = VContext.create([{ bar: 1}], ['foo']);
103
+ v.setVar('foo.baz', 2);
104
+ t.deepEqual(v.values, { foo: { bar: 1, baz: 2 }});
105
+ t.end();
106
+ });
107
+
108
+ test('setVar with null key, will not set anything', function (t) {
109
+ var v = VContext.create([{ bar: 1}], ['foo']);
110
+ v.setVar(null, 2);
111
+ t.deepEqual(v.values, { foo: { bar: 1 }});
112
+ t.end();
113
+ });
114
+
115
+ test('setVar with undefined key, will not set anything', function (t) {
116
+ var v = VContext.create([{ bar: 1}], ['foo']);
117
+ v.setVar(undefined, 2);
118
+ t.deepEqual(v.values, { foo: { bar: 1 }});
119
+ t.end();
120
+ });
121
+
122
+ test('saveResults will set values for params and :LAST_RESULTS', function (t) {
123
+ var v = VContext.create([], []);
124
+ v.saveResults(['foo', 'bar', 'cat'], [1, 'hello', null]);
125
+ t.deepEqual(v.values, { foo: 1, bar: 'hello', cat: null ,
126
+ ':LAST_RESULTS': [1, 'hello', null] });
127
+ t.end();
128
+ });
129
+
130
+ test('saveResults set :LAST_RESULT w/all even params is short', function (t) {
131
+ var v = VContext.create([], []);
132
+ v.saveResults(['foo'], [1, 'hello', null]);
133
+ t.deepEqual(v.values, { foo: 1,
134
+ ':LAST_RESULTS': [1, 'hello', null] });
135
+ t.end();
136
+ });
137
+
138
+ test('saveResults will set values for params and :LAST_RESULTS', function (t) {
139
+ var v = VContext.create([], []);
140
+ v.saveResults(['foo', 'bar', 'cat'], [1, 'hello', null]);
141
+ t.deepEqual(v.values, { foo: 1, bar: 'hello', cat: null ,
142
+ ':LAST_RESULTS': [1, 'hello', null] });
143
+ t.end();
144
+ });
145
+
146
+ test('saveResults upgrades undefined to null, but :LAST_RESULT is exact', function (t) {
147
+ var v = VContext.create([], []);
148
+ v.saveResults(['foo', 'bar', 'baz'], [1, undefined]);
149
+ t.deepEqual(v.values, { foo: 1, bar: null, baz: null,
150
+ ':LAST_RESULTS': [1, undefined] });
151
+ t.end();
152
+ });
153
+
154
+ test('saveResults null params skips saving, :LAST_RESULT is exact', function (t) {
155
+ var v = VContext.create([], []);
156
+ v.saveResults(['foo', null], [1, 20]); //skip second param
157
+ t.deepEqual(v.values, { foo: 1, ':LAST_RESULTS': [1, 20] });
158
+ t.end();
159
+ });
160
+
package/lib/react.js DELETED
@@ -1,228 +0,0 @@
1
- 'use strict';
2
-
3
- var util = require('util');
4
-
5
- var reactOptions = {
6
- debugOutput: false
7
- };
8
-
9
- /**
10
- @example
11
- var r = react('filename, uid, cb').define(
12
- loadUser, 'uid -> err, user',
13
- loadFile, 'filename -> err, filedata',
14
- markdown, 'filedata -> returns html',
15
- prepareDirectory, 'outDirname -> err, dircreated',
16
- sendOutput, 'html, user -> err, html, bytesWritten', {after:prepareDirectory}
17
- ).callbackDef('err, html, user, bytesWritten');
18
-
19
- r.exec(filename, uid, function(err, html, user, bytesWritten){
20
- //use html
21
- });
22
-
23
- */
24
-
25
- function fName(fn){
26
- return (typeof(fn) === 'string') ? fn : fn.name;
27
- }
28
-
29
- function formatErrorMeta(err){
30
- if (!err.meta) return;
31
- var vcon = err.meta.vcon;
32
- var task = err.meta.task;
33
- return '\n\n' +
34
- 'Error occurs in Task function: ' + fName(task.f) + '(' + task.a.join(',') + ')\n\n' +
35
- 'Variable Context: \n' +
36
- util.inspect(vcon) + '\n\n' +
37
- 'Task Source:\n\n' +
38
- task.f.toString() + '\n\n'; //TODO need to pretty print function, gets collapsed
39
- }
40
-
41
- function augmentError(err, meta){
42
- if (typeof(err) === 'string' ) { err = new Error(err); } //props will be lost on non-objects
43
- var origMsg = err.toString();
44
- err.meta = meta;
45
- err.toString = function() { return origMsg + formatErrorMeta(err); };
46
- return err;
47
- }
48
-
49
- function splitTrimFilterArgs(commaSepArgs){ //parse 'one, two' into ['one', 'two']
50
- return commaSepArgs.split( ',' ) //split on commas
51
- .map(function(s){ return s.trim(); }) //trim
52
- .filter(function(s){ return (s); }); //filter out empty strings
53
- }
54
-
55
- function parseInOutDef(inOutDef){ //'a, b -> err, c, d' into { inDef: ['a','b'], outDef: ['c', 'd'] }
56
- var match = /^([^-]*)(->)?\s*(er{0,2}\s*,)?(.*)$/.exec(inOutDef);
57
- if (match) {
58
- return { inDef: splitTrimFilterArgs(match[1]),
59
- outDef: splitTrimFilterArgs(match[4]) };
60
- }
61
- throw "error parsing in/out def: "+inOutDef;
62
- }
63
-
64
- function nameTasks(tasks){ //name tasks that are not already named, validation done elsewhere, ret map
65
- var namesMap = tasks.reduce(function(map, t){
66
- if (t.name) { map[t.name] = t; }
67
- return map; }, {});
68
- tasks.forEach(function(t, idx){
69
- if (!t.name) { //not already named
70
- var name = fName(t.f);
71
- if (!name || namesMap[name]) name = ''+name+'_'+idx; //if empty or already used, postfix with _idx
72
- t.name = name;
73
- namesMap[name] = t;
74
- }
75
- });
76
- return namesMap;
77
- }
78
-
79
- function parseTaskDefs(arrArgs){ // [fun, strArgsCbArgs, optObj]
80
- var taskDefs = [];
81
- var CHECK_RETURNS_RE = /^returns?\s+(\w+)\s*;?$/;
82
- while(arrArgs.length){
83
- var fn = arrArgs.shift();
84
- var strArgsCbArgs = arrArgs.shift();
85
- var optObj = (typeof(arrArgs[0]) === 'object') ? arrArgs.shift() : { };
86
- if (typeof(strArgsCbArgs) !== 'string') throw "eror parsing taskdef, expected str, got:"+strArgsCbArgs;
87
- var inOutDef = parseInOutDef(strArgsCbArgs);
88
- var taskDef = { f:fn, a:inOutDef.inDef, cb:inOutDef.outDef };
89
- Object.keys(optObj).forEach(function(k){ taskDef[k] = optObj[k]; })
90
- if (taskDef.after) {
91
- if (!Array.isArray(taskDef.after)) { taskDef.after = [taskDef.after]; } //ensure arr
92
- taskDef.after = taskDef.after.map(function(a){ return fName(a); });
93
- }
94
- var matchReturn = CHECK_RETURNS_RE.exec(taskDef.cb[0]);
95
- if (matchReturn) { // found return(s) varname, so change this to return type fn
96
- delete taskDef.cb; taskDef.ret = matchReturn[1]; } // del cb, add ret:varname
97
- taskDefs.push( taskDef );
98
- }
99
- return taskDefs;
100
- }
101
-
102
-
103
- function react(inputDef){
104
- inputDef = Array.prototype.slice.call(arguments).join(', '); //convert 'a', 'b', 'c' into 'a, b, c'
105
- var reactObj;
106
- var inOutDef = parseInOutDef(inputDef);
107
- var ast = { inputNames: inOutDef.inDef,
108
- finalOutputNames: inOutDef.outDef, //this might be set later
109
- taskDefs: [] }; //set in define()
110
- var STATUS = { READY: 'ready', RUNNING: 'running', ERRORED: 'errored', COMPLETE: 'complete' };
111
-
112
- function define(arg1, arg2, argN){
113
- ast.taskDefs = ast.taskDefs.concat(parseTaskDefs(Array.prototype.slice.call(arguments)));
114
- nameTasks(ast.taskDefs); //set names in ast.taskDefs so that ast can be inspected before exec
115
- return reactObj;
116
- }
117
-
118
- function callbackDef(argDef){ //define the callback output names
119
- argDef = Array.prototype.slice.call(arguments).join(', '); //convert 'a', 'b', 'c' into 'a, b, c'
120
- argDef = ( argDef && /^\s*->/.test(argDef)) ? argDef : '-> '+argDef; //prefix with -> before parse
121
- var inOutDef = parseInOutDef(argDef); //should be '-> a,b,c'
122
- ast.finalOutputNames = inOutDef.outDef;
123
- return reactObj;
124
- }
125
-
126
- function exec(arg1, arg2, argN){
127
- var args = Array.prototype.slice.call(arguments);
128
- var cbFinal = args.pop(); //pop off final callback from end
129
- var vCon = { }; //create variable context
130
- args.forEach(function(x, idx){ vCon[ast.inputNames[idx]] = x; });
131
- var firstError; //will be set to the err of first task that errors
132
- var contExec; //function defined later
133
- var tasksByName = {}; //set later, by calling nameTasks
134
-
135
- function handleTaskError(task, err){
136
- task.status = STATUS.ERRORED;
137
- if (!firstError) { //no prev error, only calling final callback with error once
138
- var errWithMeta = augmentError(err, {task:task, vcon:vCon});
139
- firstError = errWithMeta; //save this, stop other tasks from being launched
140
- cbFinal.call(null, errWithMeta); //call the final callback with the first error hit
141
- }
142
- }
143
-
144
- function createCallback(task) {
145
- return function(err, arg0, arg1, argn){
146
- var args = Array.prototype.slice.call(arguments,1);
147
- if(err){ handleTaskError(task, err); return; } //handle error and return, we are done
148
-
149
- //no error, save callback args to vCon context, then continue execution
150
- task.cb.forEach(function(k, idx){ //save cb args to v context
151
- vCon[k] = (args[idx] !== undefined) ? args[idx] : null; //upgrade any undefined to null
152
- });
153
- task.status = STATUS.COMPLETE;
154
- if (reactOptions.debugOutput) console.log('in callback: %s cb:', fName(task.f), args, vCon);
155
- contExec();
156
- };
157
- }
158
-
159
- var tasks = ast.taskDefs.map(function(ot){ //create working task copies
160
- var t = Object.create(ot);
161
- if(t.cb) t.cbFun = createCallback(t); //if is callback type fn, create callback
162
- return t;
163
- });
164
- tasksByName = nameTasks(tasks); //remap names to exec task copies instead of taskDefs
165
-
166
-
167
- function execTask(t){
168
- t.status = STATUS.RUNNING;
169
- var args = t.a.map(function(k){ return vCon[k]; }); //get args from vCon
170
- if (t.cbFun) args.push(t.cbFun); //push custom callback to back if fn uses cb
171
- if (reactOptions.debugOutput) console.log('starting task: %s', fName(t.f), args);
172
- try {
173
- var func;
174
- var bindObj = null; //start as global object
175
- if (typeof(t.f) === 'string') { //object method call
176
- var match = /(\w+)\.(\w+)/.exec(t.f);
177
- if (match) {
178
- var objName = match[1];
179
- var methName = match[2];
180
- bindObj = vCon[objName];
181
- func = bindObj[methName];
182
- }
183
- if (!func) throw new Error('Object or method not found: '+t.f);
184
- } else { //function call
185
- func = t.f;
186
- }
187
- var ret = func.apply(bindObj, args);
188
- if (t.ret) { //if non-cb fn/method,
189
- vCon[t.ret] = ret; // save retval
190
- t.status = STATUS.COMPLETE; // mark complete
191
- contExec(); // continue since no callback to run this
192
- }
193
- } catch (e) { handleTaskError(t, e); } //catch and handle the task error, calling final cb
194
- }
195
-
196
- contExec = function contExec(){
197
- if (firstError) { return; } //stop execution, we already hit an error
198
- if (tasks.every(function(t){ return (t.status === STATUS.COMPLETE); })) { //all completed
199
- //we are done, call final callback
200
- var finalArgs = ast.finalOutputNames.map(function(k){ return vCon[k]; });
201
- finalArgs.unshift(null); //unshift err=null to front
202
- cbFinal.apply(null, finalArgs);
203
- return;
204
- }
205
- var tasksReady = tasks.filter(function(t, idx, arr){ //if we are here then we stil have tasks to run
206
- return !t.status && // filter for not started AND
207
- t.a.every(function(k){ return (vCon[k] !== undefined); }) && // all dep vars defined AND
208
- (!t.after || // (no dep tasks OR
209
- t.after.every( function(n){ return tasksByName[n].status === STATUS.COMPLETE; })); //alldone
210
- });
211
- tasksReady.forEach(function(t){ t.status = STATUS.READY; }); //set ready before call, no double exec
212
- tasksReady.forEach(function(t){ execTask(t); });
213
- };
214
- contExec(); //now kick off the execution for exec()
215
- }
216
-
217
- reactObj = {
218
- define: define,
219
- callbackDef: callbackDef,
220
- exec: exec,
221
- ast: ast,
222
- };
223
-
224
- return reactObj;
225
- }
226
-
227
- module.exports.react = react;
228
- module.exports.reactOptions = reactOptions;