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