@boostercloud/cli
Version:
CLI of the Booster Framework, the next level of abstraction for cloud-native applications
102 lines (101 loc) • 4.74 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Script = void 0;
const ReaderTaskEither_1 = require("fp-ts/lib/ReaderTaskEither");
const pipeable_1 = require("fp-ts/lib/pipeable");
const Either_1 = require("fp-ts/lib/Either");
const TaskEither_1 = require("fp-ts/lib/TaskEither");
const function_1 = require("fp-ts/lib/function");
const logger_1 = require("../services/logger");
const brand_1 = require("./brand");
/**
* A Script represents some steps in a booster command, it stores the initial context
* implicitly, and makes it available for all of the steps that define this process.
*/
class Script {
constructor(contextResolver, errorHandlers, action) {
this.contextResolver = contextResolver;
this.errorHandlers = errorHandlers;
this.action = action;
/**
* Method that eases the creation of steps. It accepts a message to be shown in the spinner and a
* function that receives the context and the input from the previous step.
* From this function you must return a Promise that resolves with the value that you want to pass to the next step (if any)
*
* @param message Message to initialize the spinner
* @param action Function that receives the config object and performs an action
*/
this.step = (message, action) => new Script(this.contextResolver, this.errorHandlers, (0, pipeable_1.pipe)(this.action, (0, ReaderTaskEither_1.chain)(() => (0, ReaderTaskEither_1.ask)()), (0, ReaderTaskEither_1.chain)((ctx) => (0, ReaderTaskEither_1.fromTaskEither)((0, TaskEither_1.tryCatch)(async () => {
Script.logger.start(message);
await action(ctx);
Script.logger.succeed(message);
}, (err) => {
Script.logger.fail(message);
return err;
})))));
/**
* Function to determine next action depending on passed boolean condition
* If condition is true, step will be skipped and info action will be called.
* Otherwise, step method will be called as usual.
*
* @param skipCondition When true, the action is skipped
* @param message Message to initialize the spinner
* @param action Function that receives the config object and performs an action
*/
this.optionalStep = (skipCondition, message, action) => {
if (skipCondition)
return this.info(brand_1.default.mellancholize(`Skipping: ${message}`));
return this.step(message, action);
};
/**
* Convenience method to generate a step that just prints a message with a small blue `i` character in front of it.
*
* @param message Message to be shown in the CLI
*/
this.info = (message) => new Script(this.contextResolver, this.errorHandlers, (0, pipeable_1.pipe)(this.action, (0, ReaderTaskEither_1.chain)(() => (0, ReaderTaskEither_1.rightIO)(() => {
Script.logger.info(message);
}))));
/**
* Add a handler to catch a specific type of errors
*
* @param errorType the kind of errors that the handler will catch
* @param handler handler for the errors
*/
this.catch = (errorType, handler) => {
const newHandlers = { ...this.errorHandlers };
newHandlers[errorType] = handler;
return new Script(this.contextResolver, newHandlers, this.action);
};
}
/**
* Function to finish the script,
* it will handle any error in between that might happen in
* some steps.
*/
async done() {
try {
const context = await this.contextResolver;
const result = await (0, ReaderTaskEither_1.run)(this.action, context);
return (0, pipeable_1.pipe)(result, (0, Either_1.fold)((err) => {
throw err;
}, function_1.constVoid));
}
catch (err) {
const error = err;
const defaultHandler = (e) => e.stack || e.message || JSON.stringify(e);
const handler = this.errorHandlers[error.name] || defaultHandler;
throw new Error(handler(error));
}
}
}
exports.Script = Script;
/**
* Convenience function to print a welcome message and initialize the context of the script
*
* @param initialMessage The message to show in the console
* @param contextResolver A promise that fulfills into a valid context object
*/
Script.init = (initialMessage, contextResolver) => new Script(contextResolver, {}, (0, ReaderTaskEither_1.rightIO)(() => {
Script.logger.info(initialMessage);
}));
Script.logger = logger_1.oraLogger;