@atomist/rugs
Version:
Helper functions for Rugs
233 lines (232 loc) • 9.24 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var Handlers_1 = require("@atomist/rug/operations/Handlers");
var Decorators_1 = require("@atomist/rug/operations/Decorators");
/**
* Builder Pattern implementation to generate the
* HandlerChainDescriptor datastructure
*/
var HandlerChain = (function () {
function HandlerChain(handle) {
this.handle = handle;
}
HandlerChain.prototype.onAny = function (builder) {
this.any = builder;
return this;
};
HandlerChain.prototype.onSuccess = function (builder) {
this.success = builder;
return this;
};
HandlerChain.prototype.onError = function (builder) {
this.error = builder;
return this;
};
HandlerChain.prototype.build = function () {
var chain = { handle: this.handle };
if (this.any !== undefined) {
chain.onAny = this.any.build();
}
if (this.success !== undefined) {
chain.onSuccess = this.success.build();
}
if (this.error !== undefined) {
chain.onError = this.error.build();
}
return chain;
};
return HandlerChain;
}());
exports.HandlerChain = HandlerChain;
/**
* Wrapper around a normal Handler Instruction and any parameters to be passed
* downstream any Response Handlers (if any)
*/
var ChainedInstruction = (function () {
function ChainedInstruction(instruction, params) {
this.instruction = instruction;
this.params = params;
}
return ChainedInstruction;
}());
exports.ChainedInstruction = ChainedInstruction;
/**
* Extend this class to have Instructions and Response Handlers automatically
* generated from a HandlerChainDescriptor that describes your workflow.
*
* Currently only Instructions can be added to the CommandPlan, and only Response
* Handlers can be used to respond to their success or failure. Message sending
* is currently not supported.
*/
var ResponseChainingCommandHandler = (function () {
/**
* In general, onSuccess or onAny should be passed in to make this Handler
* useful.
*
* @param onSuccess handler chain to run if the root Instruction is successful
* @param onError handler chain to run if the root Instruction fails
* @param onAny handler chain to run onSuccess and on Error
*/
function ResponseChainingCommandHandler(onSuccess, onError, onAny) {
this.onSuccess = onSuccess;
this.onError = onError;
this.onAny = onAny;
this.rootSuccessName = "RootSuccessHandler";
this.rootErrorName = "RootErrorHandler";
this.defaultErrorHandlerName = "DefaultErrorHandler";
this.handlers = [];
}
/**
* Configure a default onError Response Handler to use if none already
* set for that node in the workflow
* @param defaultErrorHandler a ChainedResponseHandler to use onError
*/
ResponseChainingCommandHandler.prototype.withDefaultErrorHandler = function (defaultErrorHandler) {
this.defaultErrorHandler = defaultErrorHandler;
var handler = new GeneratedCommandResponseHandler(this.defaultErrorHandler, undefined, undefined);
// tslint:disable-next-line:max-line-length
var decorated = Decorators_1.declareResponseHandler(handler, "Generated Default Error Handler", this.defaultErrorHandlerName);
// hide from the CLI/Bot
Decorators_1.setScope(decorated, "archive");
this.handlers.push(decorated);
return this;
};
/**
* Called by Rug to handle a command. It delegates to `init`
* so that sub-classes can configure an initial Instruction to run
* to kick of the workflow
* @param ctx same context passed to all Command Handlers
*/
ResponseChainingCommandHandler.prototype.handle = function (ctx) {
var plan = new Handlers_1.CommandPlan();
var root = this.init(ctx);
var respondable = {
instruction: root.instruction,
};
if (this.onSuccess !== undefined || this.onAny !== undefined) {
respondable.onSuccess = {
kind: "respond",
name: this.rootSuccessName,
parameters: root.params,
};
}
if (this.onError !== undefined || this.onAny !== undefined) {
respondable.onError = {
kind: "respond",
name: this.rootErrorName,
parameters: root.params,
};
}
if (respondable.onError === undefined && this.onAny !== undefined && this.defaultErrorHandler !== undefined) {
respondable.onError = {
kind: "respond",
name: this.defaultErrorHandlerName,
parameters: root.params,
};
}
plan.add(respondable);
return plan;
};
/**
* Walks the HandlerChainDescriptor and generates an array of handlers
* that can be exported and picked up by the Rug.
*/
ResponseChainingCommandHandler.prototype.buildHandlerChain = function () {
if (this.onAny !== undefined && (this.onSuccess !== undefined || this.onError !== undefined)) {
throw new Error("onAny and an onSuccess/onError handler have been defined");
}
// walk the three trees
this.walk(this.onAny, this.rootSuccessName, this.rootErrorName);
this.walk(this.onError, undefined, this.rootErrorName);
this.walk(this.onSuccess, this.rootSuccessName, undefined);
// make sure this handler itself is registered
this.handlers.push(this);
return this.handlers;
};
/**
* Guts of the tree walking.
* Currently we do _not_ use a cache to ensure
* we don't generate duplicate response handlers.
*/
ResponseChainingCommandHandler.prototype.walk = function (chain, onSuccess, onError) {
var nextOnSuccess;
var nextOnError;
if (chain === undefined) {
return;
}
if (chain.onSuccess !== undefined || chain.onAny !== undefined) {
nextOnSuccess = "GeneratedSuccessResponseHandler-" + this.handlers.length;
}
if (chain.onError !== undefined || chain.onAny !== undefined) {
nextOnError = "GeneratedErrorResponseHandler-" + this.handlers.length;
}
else if (this.defaultErrorHandler !== undefined) {
nextOnError = this.defaultErrorHandlerName;
}
if (onSuccess !== undefined) {
var handler = new GeneratedCommandResponseHandler(chain.handle, nextOnSuccess, nextOnError);
var decorated = Decorators_1.declareResponseHandler(handler, "Generated Command Response Handler", onSuccess);
Decorators_1.setScope(decorated, "archive");
this.handlers.push(decorated);
}
if (onError !== undefined) {
var handler = new GeneratedCommandResponseHandler(chain.handle, nextOnSuccess, nextOnError);
var decorated = Decorators_1.declareResponseHandler(handler, "Generated Command Response Handler", onError);
Decorators_1.setScope(decorated, "archive");
this.handlers.push(decorated);
}
this.walk(chain.onSuccess, nextOnSuccess, undefined);
this.walk(chain.onError, undefined, nextOnError);
this.walk(chain.onAny, nextOnSuccess, nextOnError);
};
return ResponseChainingCommandHandler;
}());
exports.ResponseChainingCommandHandler = ResponseChainingCommandHandler;
/**
* Instances of this class are created by ResponseChainingCommandHandler
* and wired up with the appropriate Instructions.
*
* In general, they are named in an automated way and are hidden from
* the CLI/Bot
*/
var GeneratedCommandResponseHandler = (function () {
function GeneratedCommandResponseHandler(impl, onSuccess, onError) {
this.impl = impl;
this.onSuccess = onSuccess;
this.onError = onError;
}
GeneratedCommandResponseHandler.prototype.handle = function (response) {
var plan = new Handlers_1.CommandPlan();
// filter out stuff from this that aren't parameters
var params = {};
var that = this;
// tslint:disable-next-line:forin
for (var k in this) {
if (that.hasOwnProperty(k)) {
params[k] = that[k];
}
}
var chainedInstruction = this.impl.call(this, response, params);
var respondable = {
instruction: chainedInstruction.instruction,
};
if (this.onSuccess !== undefined) {
respondable.onSuccess = {
kind: "respond",
name: this.onSuccess,
parameters: chainedInstruction.params,
};
}
if (this.onError !== undefined) {
respondable.onError = {
kind: "respond",
name: this.onError,
parameters: chainedInstruction.params,
};
}
plan.add(respondable);
return plan;
};
return GeneratedCommandResponseHandler;
}());
exports.GeneratedCommandResponseHandler = GeneratedCommandResponseHandler;