react 0.0.2 → 0.2.1
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 +6 -0
- package/Jakefile.js +8 -0
- package/README.md +226 -86
- package/examples/ast1.js +26 -0
- package/examples/chain-events1.js +34 -0
- package/examples/chain1.js +19 -0
- package/examples/default-events1.js +52 -0
- package/examples/default1.js +40 -0
- package/examples/fstr-events1.js +51 -0
- package/examples/fstr1.js +36 -0
- package/examples/pcode1.js +22 -0
- package/jake-tasks/jake-test.js +64 -0
- package/lib/base-task.js +115 -0
- package/lib/cb-task.js +67 -0
- package/lib/chain.js +148 -0
- package/lib/core.js +96 -0
- package/lib/dsl.js +122 -0
- package/lib/error.js +37 -0
- package/lib/event-manager.js +57 -0
- package/lib/finalcb-first-task.js +59 -0
- package/lib/finalcb-task.js +54 -0
- package/lib/fstr.js +110 -0
- package/lib/id.js +10 -0
- package/lib/input-parser.js +44 -0
- package/lib/parse.js +29 -0
- package/lib/pcode.js +164 -0
- package/lib/ret-task.js +67 -0
- package/lib/status.js +5 -0
- package/lib/task.js +234 -0
- package/lib/validate.js +102 -0
- package/lib/vcon.js +76 -0
- package/oldExamples/analyze.js +29 -0
- package/oldExamples/analyze2.js +29 -0
- package/oldExamples/example10-dsl.js +63 -0
- package/oldExamples/example11.js +62 -0
- package/oldExamples/example12.js +63 -0
- package/oldExamples/example13.js +63 -0
- package/oldExamples/example14.js +63 -0
- package/oldExamples/example15.js +75 -0
- package/{test → oldExamples}/example6-ast.js +4 -4
- package/{test → oldExamples}/example6-dsl.js +3 -2
- package/{test → oldExamples}/example8-ast.js +3 -2
- package/{test → oldExamples}/example8-dsl.js +3 -2
- package/{test → oldExamples}/example9-ast.js +3 -2
- package/{test → oldExamples}/example9-dsl.js +3 -2
- package/oldExamples/function-str-ex1.js +33 -0
- package/oldExamples/function-str-ex2.js +67 -0
- package/oldExamples/trait1.js +41 -0
- package/oldExamples/trait2.js +44 -0
- package/package.json +16 -6
- package/react.js +11 -1
- package/test/ast.test.js +69 -0
- package/test/cb-task.test.js +197 -0
- package/test/chain.test.js +239 -0
- package/test/core.test.js +519 -0
- package/test/dsl.test.js +237 -0
- package/test/event-manager.test.js +102 -0
- package/test/exec-options.test.js +32 -0
- package/test/finalcb-task.test.js +37 -0
- package/test/fstr.test.js +288 -0
- package/test/input-parser.test.js +62 -0
- package/test/module-use.test.js +317 -0
- package/test/pcode.test.js +321 -0
- package/test/ret-task.test.js +199 -0
- package/test/task.test.js +21 -0
- package/test/validate-cb-task.test.js +74 -0
- package/test/validate-ret-task.test.js +83 -0
- package/test/validate.test.js +218 -0
- package/test/vcon.test.js +160 -0
- package/lib/react.js +0 -239
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/*jshint white: false */
|
|
3
|
+
|
|
4
|
+
var react = require('../'); // require('react');
|
|
5
|
+
|
|
6
|
+
//output events as tasks start and complete
|
|
7
|
+
react.events.on('*', function (obj) {
|
|
8
|
+
var time = new Date();
|
|
9
|
+
time.setTime(obj.time);
|
|
10
|
+
var eventTimeStr = time.toISOString();
|
|
11
|
+
var argsNoCb = obj.args.filter(function (a) { return (typeof(a) !== 'function'); });
|
|
12
|
+
if (obj.event === 'task.complete') {
|
|
13
|
+
console.error('%s: %s \tmsecs:(%s) \n\targs:(%s) \n\tresults:(%s)\n',
|
|
14
|
+
obj.event, obj.name, obj.elapsedTime, argsNoCb, obj.results);
|
|
15
|
+
} else {
|
|
16
|
+
console.error('%s: %s \n\targs:(%s)\n', obj.event, obj.name, argsNoCb);
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
function loadUser(uid, cb){ setTimeout(cb, 100, null, "User"+uid); }
|
|
22
|
+
function loadFile(filename, cb){ setTimeout(cb, 100, null, 'Filedata'+filename); }
|
|
23
|
+
function markdown(filedata) { return 'html'+filedata; }
|
|
24
|
+
function prepareDirectory(outDirname, cb){ setTimeout(cb, 200, null, 'dircreated-'+outDirname); }
|
|
25
|
+
function writeOutput(html, user, cb){ setTimeout(cb, 300, null, html+'_bytesWritten'); }
|
|
26
|
+
function loadEmailTemplate(cb) { setTimeout(cb, 50, null, 'emailmd'); }
|
|
27
|
+
function customizeEmail(user, emailHtml, cb) { return 'cust-'+user+emailHtml; }
|
|
28
|
+
function deliverEmail(custEmailHtml, cb) { setTimeout(cb, 100, null, 'delivered-'+custEmailHtml); }
|
|
29
|
+
|
|
30
|
+
function useHtml(err, html, user, bytesWritten) {
|
|
31
|
+
if (err) {
|
|
32
|
+
console.log('***Error: %s', err);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
console.log('final result: %s, user: %s, written:%s', html, user, bytesWritten);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
var loadAndSave = react('loadAndSave', 'filename, uid, outDirname, cb -> err, html, user, bytesWritten', // name, in/out params
|
|
39
|
+
loadUser, 'uid, cb -> err, user', // calling async fn loadUser with uid, callback is called with err and user
|
|
40
|
+
loadFile, 'filename, cb -> err, filedata',
|
|
41
|
+
markdown, 'filedata -> html', // using a sync function
|
|
42
|
+
prepareDirectory, 'outDirname, cb -> err, dircreated',
|
|
43
|
+
writeOutput, 'html, user, cb -> err, bytesWritten', { after: prepareDirectory }, // only after prepareDirectory done
|
|
44
|
+
loadEmailTemplate, 'cb -> err, emailmd',
|
|
45
|
+
markdown, 'emailmd -> emailHtml', // using a sync function
|
|
46
|
+
customizeEmail, 'user, emailHtml, cb -> err, custEmailHtml',
|
|
47
|
+
deliverEmail, 'custEmailHtml, cb -> err, deliveredEmail', { after: writeOutput } // only after writeOutput is done
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
loadAndSave('file.md', 100, '/tmp/foo', useHtml); // executing the flow
|
|
51
|
+
|
|
52
|
+
|
|
@@ -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, cb -> err, user', // calling async loadUser with uid, cb called with err and user
|
|
27
|
+
loadFile, 'filename, cb -> err, filedata',
|
|
28
|
+
markdown, 'filedata -> html', // using a sync function
|
|
29
|
+
prepareDirectory, 'outDirname, cb -> err, dircreated',
|
|
30
|
+
writeOutput, 'html, user, cb -> err, bytesWritten', { after: prepareDirectory }, // only after prepareDirectory done
|
|
31
|
+
loadEmailTemplate, 'cb -> err, emailmd',
|
|
32
|
+
markdown, 'emailmd -> emailHtml', // using a sync function
|
|
33
|
+
customizeEmail, 'user, emailHtml, cb -> custEmailHtml',
|
|
34
|
+
deliverEmail, 'custEmailHtml, cb -> err, deliveredEmail', { after: writeOutput } // only after writeOutput is done
|
|
35
|
+
);
|
|
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
|
+
|
package/lib/base-task.js
ADDED
|
@@ -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;
|