Defining flow directly using the AST. Additional DSL interfaces can be built by simply having them build the proper AST.
var autoflow = require('autoflow');
function load(res, cb) { setTimeout(cb, 100, null, res + '-loaded'); }
function prefix(prefstr, str, cb) { setTimeout(cb, 100, null, prefstr + str); }
function postfix(str, poststr, cb) { setTimeout(cb, 100, null, str + poststr); }
function upper(str) { return str.toUpperCase(); }
var fn = autoflow();
var errors = fn.setAndValidateAST({
inParams: ['res', 'prefstr', 'poststr'],
tasks: [
{ f: load, a: ['res'], out: ['lres'] },
{ f: upper, a: ['lres'], out: ['ulres'], type: 'ret' },
{ f: prefix, a: ['prefstr', 'ulres'], out: ['plres'] },
{ f: postfix, a: ['plres', 'poststr'], out: ['plresp'] }
],
outTask: { a: ['plresp'] }
});
console.error('errors:', errors); // []
fn('foo', 'pre-', '-post', function cb(err, lres) {
console.error('err:', err); // null
console.error('lres:', lres); // pre-FOO-LOADED-post
});
The abstract syntax tree or AST provided by autoflow represents the data necessary to define the flow. By abstracting this from the DSL, it allows new skins or interfaces to be developed without need to change the core engine.
The AST is normally created at parse time when the autoflow main function is called (or one of the alternate DSL's is called). This can be done a module load time such that after loading the autoflow defined flow function's AST is generated and ready to process eliminating parsing and validation overhead when it is invoked in the future. This has the added advantage that since validation has also been performed that additional syntax issues or incomplete flow defintion errors can be caught quickly.
After the flow function has been created, you can review the generated AST for a function by accessing the ast.
var autoflow = require('autoflow');
var fn = autoflow('my-flow-name', 'paramName1, paramName2, cb -> err, outParamName1, outParamName2',
functionRefOrMethodStr, 'paramName1, cb -> err, outParamName2', // async cb task
functionRefOrMethodStr2, 'paramName2, paramName1 -> outParamName1' // sync task
);
console.error(fn.ast); // output the generated AST
The AST contains the following pieces:
var ast = {
name: flowName,
inParams: [],
tasks: [],
outTask: {},
locals: {}
};
- name - string - represents the name of the flow or function that will be created. autoflow will use the name when generating events so you can monitor progress and performance and also when errors occur.
- InParams - array of strings - the flow input parameter names (excluding the callback param)
- tasks - array of task defintion objects - each containing:
- f - function reference or method string - async or sync function to be used for this task
- a - array of input parameter names (excluding the callback param)
- out - array of output parameter names (excluding the err parame)
- type - type of function determining how function is invoked and its output style - one of: ('cb', 'ret', 'promise', 'when')
- name - string - unique name for each task provided or generated by autoflow
- OutTask - task definition object specifying the flow's output style and parameters containing:
- f - will contain reference to the callback function at runtime
- a - parameters being passed as output from the flow
- locals - object provided which contains additional values that will become part of the autoflow variable space like input parameters but can be defined in advance at flow definition. This can be used to provide functions and objects to autoflow enabling string based DSL's. The global variables are already built-in, but any locals that are needed would be specified here.
Additional functionality which is not enabled by default but available by requiring additional modules.
### LogEvents - log autoflow progress to stderrFor convenience in debugging or in monitoring flow and performance, autoflow has a built-in plugin for easily logging progress to stderr which is loaded and activated calling the autoflow method logEvents
. It can be specified to log globally for all autoflow functions or only for particular autoflow functions. You also may optionally listen to select events rather than all flow and task events.
var autoflow = require('autoflow');
autoflow.logEvents(); // turn on flow and task logging for all autoflow functions
// OR
autoflow.logEvents(myautoflowFn); // turn on flow and task logging for a specific function, repeat as needed
autoflow.LogEvents(myautoflowFn).logEvents(myautoflowFn2); // can also chain
// Both methods can also take an optional event wildcard to specify what you want to listen to
autoflow.logEvents('flow.*'); // turn on flow logging for all autoflow functions
autoflow.logEvents(myautoflowFn, 'task.*'); // turn on task logging for myautoflowFn
To turn off logging
autoflow.logEvents(false); // turn off logging
Available Events that can be logged:
- flow.begin - flow execution has started (receives a flow env)
- flow.complete - flow execution has successfully completed (receives a flow env)
- flow.errored - flow execution has errored (receives a flow env)
- task.begin - task has started (receives task)
- task.complete - task has successfully complted (receives task)
- task.errored - task has errored (receives task)
If you want to automatically resolve promises in autoflow without having to manually call when
or then
, autoflow provides a plugin which will detect the existence of a then
method (indicating a promise) at runtime from any inputs to the flow and will internally create when
tasks to resolve them before passing the values to other tasks. This built-in plugin is not loaded normally but is loaded by invoking the autoflow method resolvePromises
. External plugins like autoflow-deferred
and autoflow-q
also enable this but also provide additional promise integration. See https://github.com/jeffbski/autoflow-deferred and https://github.com/jeffbski/autoflow-q
var autoflow = require('autoflow');
autoflow.resolvePromises(); // turn on automatic promise detection and resolution
Instead of only logging events to stderr (like LogEvents), this built-in plugin fires events that can be directly monitored. The LogEvent plugin uses this internally to get access to the metrics.
Enable this like the other built-in plugins using the method trackTasks
var autoflow = require('autoflow');
autoflow.trackTasks(); // turn on flow and task tracking events
Available Events that can be consumed
- ast.defined - ast was defined (receives the ast)
- flow.begin - flow execution has started (receives a flow env)
- flow.complete - flow execution has successfully completed (receives a flow env)
- flow.errored - flow execution has errored (receives a flow env)
- task.begin - task has started (receives task)
- task.complete - task has successfully complted (receives task)
- task.errored - task has errored (receives task)
When developing or debugging it is often useful to accumulate events and then interrogate them to verify operation, especially in testing.
To make this easier to accomplish, this plugin provides a simple event accumulator for development use. Note that this accumulator is designed for short term debug use, as it will continue to accumulate events and does not have any size restrictions, it should not be used in production since it will just continue to grow in size unless manually cleared.
var autoflow = require('autoflow');
var collector = autoflow.createEventCollector();
collector.capture(); // capture all flow and task events for all autoflow flows
collector.capture('flow.*'); // capture all flow events for all autoflow flows
collector.capture(flowFn, 'task.*'); // capture task events on a flow
collector.capture(flowFn, 'flow.*'); // add capture flow events on a flow
var events = collector.list(); // retrieve the list of events
collector.clear(); // clear the list of events;
- https://github.com/jeffbski/autoflow-deferred - integrates jQuery style Deferred/Promises with autoflow, providing automatic promise resolution and optional usage for autoflow functions where by calling without a callback returns a promise.
- https://github.com/jeffbski/autoflow-q - integrates Q-style Deferred/Promises with autoflow, providing automatic promise resolution and optional usage for autoflow functions where by calling without a callback returns a promise.