191 lines
4.9 KiB
JavaScript
191 lines
4.9 KiB
JavaScript
var symbols = require('./symbols'),
|
|
cleanErrorRegex = /((?:\n.*__kgoRunStep__[^]+|\n.*__kgoDeferredCallback__)[^]+?\n[^]+?(?:\n|$))/;
|
|
|
|
function cleanError(stack, error){
|
|
var currentStack = '';
|
|
if(error instanceof Error){
|
|
currentStack = error.stack ? error.stack.replace(cleanErrorRegex, '') : currentStack;
|
|
}else{
|
|
error = new Error(error);
|
|
error.stack = '';
|
|
}
|
|
error.stack = 'Error: ' + error.message + currentStack + stack;
|
|
return error;
|
|
}
|
|
|
|
function Step(task, args, done){
|
|
this._task = task;
|
|
this._args = args;
|
|
this._done = done;
|
|
}
|
|
Step.prototype.run = function __kgoRunStep__(){
|
|
var step = this;
|
|
|
|
function complete(error){
|
|
|
|
if(step._complete){
|
|
throw cleanError(step._task.stack, 'Step callback called more than once for task: ' + step._task.names);
|
|
}
|
|
|
|
step._complete = true;
|
|
|
|
var result = Array.prototype.slice.call(arguments, 1);
|
|
|
|
if(error instanceof Error){
|
|
error = cleanError(step._task.stack, error);
|
|
}
|
|
|
|
step.done(error, result);
|
|
}
|
|
|
|
try{
|
|
var args = this._args.slice();
|
|
if(!this._task.returnless){
|
|
args.push(complete);
|
|
}
|
|
this._task.fn.apply(this, args);
|
|
}catch(error){
|
|
throw cleanError(step._task.stack, error);
|
|
}
|
|
};
|
|
Step.prototype.done = function(error, result){
|
|
|
|
if(error){
|
|
return this._done(error);
|
|
}
|
|
this._done(null, result);
|
|
};
|
|
|
|
function runTask(task, results, errors, aboutToRun, done){
|
|
var names = task.names,
|
|
dependants = task.args,
|
|
args = [],
|
|
error = errors[symbols.errorSymbol],
|
|
numDeps = 0,
|
|
metDeps = 0,
|
|
allDepsMet;
|
|
|
|
if(dependants){
|
|
var useError,
|
|
hasError;
|
|
|
|
for(var i = 0; i < dependants.length; i++) {
|
|
var dependantName = dependants[i],
|
|
isErrorDep = dependantName.match(symbols.errorDependency),
|
|
ignore = dependantName.match(symbols.ignoreDependency);
|
|
|
|
if(isErrorDep){
|
|
useError = true;
|
|
hasError = hasError || dependantName in errors;
|
|
continue;
|
|
}
|
|
|
|
if(ignore){
|
|
dependantName = dependantName.slice(1);
|
|
}
|
|
|
|
numDeps++;
|
|
|
|
if(dependantName in results){
|
|
metDeps++;
|
|
}
|
|
}
|
|
|
|
allDepsMet = numDeps === metDeps;
|
|
|
|
if(!allDepsMet && !hasError || !numDeps && useError && !hasError || !hasError && error){
|
|
return;
|
|
}
|
|
|
|
for(var i = 0; i < dependants.length; i++) {
|
|
var dependantName = dependants[i],
|
|
isErrorDep = dependantName.match(symbols.errorDependency),
|
|
ignore = dependantName.match(symbols.ignoreDependency);
|
|
|
|
if(isErrorDep){
|
|
args.push(errors[dependantName]);
|
|
continue;
|
|
}
|
|
|
|
if(ignore){
|
|
continue;
|
|
}
|
|
|
|
if(hasError){
|
|
args.push(undefined);
|
|
continue;
|
|
}
|
|
|
|
args.push(results[dependantName]);
|
|
}
|
|
}
|
|
|
|
var step = new Step(task, args, function(error, results){
|
|
done(names, error, results);
|
|
});
|
|
|
|
aboutToRun(names);
|
|
step.run();
|
|
}
|
|
|
|
function run(tasks, results, errors, kgo){
|
|
var currentTask,
|
|
noMoreTasks = true;
|
|
|
|
for(var key in tasks){
|
|
noMoreTasks = false;
|
|
currentTask = tasks[key];
|
|
|
|
runTask(
|
|
currentTask,
|
|
results,
|
|
errors,
|
|
function(names){
|
|
names.map(function(name){
|
|
delete tasks[name];
|
|
});
|
|
},
|
|
function(names, taskError, taskResults){
|
|
if(taskError && !errors[symbols.errorSymbol]){
|
|
errors[symbols.errorSymbol] = taskError;
|
|
}
|
|
|
|
for(var i = 0; i < names.length; i++){
|
|
if(taskError){
|
|
errors[symbols.errorSymbol + names[i]] = taskError;
|
|
}else{
|
|
results[names[i]] = taskResults[i];
|
|
}
|
|
}
|
|
|
|
run(tasks, results, errors, kgo);
|
|
}
|
|
);
|
|
}
|
|
}
|
|
|
|
function cloneAndRun(tasks, results, kgo){
|
|
var todo = {},
|
|
errors = {};
|
|
|
|
kgo._taskCount = Object.keys(results).length;
|
|
|
|
function checkDependencyIsDefined(dependencyName){
|
|
var taskName = dependencyName.match(/[!*]?(.*)/)[1];
|
|
|
|
if(dependencyName !== symbols.errorSymbol && !(taskName in tasks) && !(taskName in results)){
|
|
throw cleanError(this.stack, 'No task or result has been defined for dependency: ' + taskName);
|
|
}
|
|
}
|
|
|
|
for(var key in tasks){
|
|
todo[key] = tasks[key];
|
|
kgo._taskCount ++;
|
|
|
|
tasks[key].args.map(checkDependencyIsDefined, tasks[key]);
|
|
}
|
|
|
|
run(todo, results, errors, kgo);
|
|
}
|
|
|
|
module.exports = cloneAndRun; |