UNPKG

symfony-style-console

Version:

Use the style and utilities of the Symfony Console in Node.js

198 lines (197 loc) 7.54 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var Helper_1 = require("../Helper/Helper"); var readline; /** * Provides simple Q&A with text input, password input, choice and confirmation * * @author Florian Reuschel <florian@loilo.de> */ var Questionnaire = /** @class */ (function () { /** * Creates a new Questionnaire instance. * * @param output The output to use for the questions. */ function Questionnaire(output) { Questionnaire.initReadline(); this.output = output; } /** * Initializes the Node.js `readline` module. */ Questionnaire.initReadline = function () { if (!readline) { readline = require('readline'); } }; /** * Checks if a string does contain anything but whitespace. * * @param value The string to check */ Questionnaire.isFilled = function (value) { return !!value.trim().length; }; /** * Disables the printing of `stdin` data to `stdout`. * * @param char The character that's currently going into `stdin` */ Questionnaire.suppressStdinOutput = function (char) { switch (String(char)) { case '\n': case '\r': case '\u0004': process.stdin.pause(); process.stdin.removeListener('data', Questionnaire.suppressStdinOutput); break; default: setImmediate(function () { process.stdout.write("\u001B[2K\u001B[200D > "); }); break; } }; /** * Performs the actual interaction between user and terminal via `readline`. * * @param _ Question options */ Questionnaire.prototype.doAsk = function (_a) { var _this = this; var question = _a.question, _b = _a.validator, validator = _b === void 0 ? null : _b, _c = _a.hideInput, hideInput = _c === void 0 ? false : _c, _d = _a.errorMsg, errorMsg = _d === void 0 ? 'Invalid value.' : _d; this.output.writeln(question); if (hideInput) { process.stdin.resume(); process.stdin.on('data', Questionnaire.suppressStdinOutput); } var rl = readline.createInterface(process.stdin, process.stdout); rl.setPrompt(' > '); rl.prompt(); return new Promise(function (resolve) { rl.on('line', function (value) { rl.history.shift(); rl.close(); _this.output.newLine(); if (!validator || validator(value)) { resolve(value); } else { _this.output.error(typeof errorMsg === 'function' ? errorMsg(value) : errorMsg); resolve(_this.doAsk({ question: question, hideInput: hideInput, validator: validator, errorMsg: errorMsg })); } }); }); }; /** * Ask for a string answer. * * @param question The (formatted) question to put * @param defaultValue A default value to provide * @param validator A validator callback */ Questionnaire.prototype.ask = function (question, defaultValue, validator) { if (defaultValue === void 0) { defaultValue = null; } if (validator === void 0) { validator = null; } var hasDefaultValue = defaultValue != null; var formattedQuestion = " <fg=green>" + question + "</>"; if (hasDefaultValue) { formattedQuestion += " [<fg=yellow>" + defaultValue + "</>]"; } formattedQuestion += ':'; return (this.doAsk({ question: formattedQuestion, validator: validator || (hasDefaultValue ? null : Questionnaire.isFilled), errorMsg: 'A value is required.' }) // Return default value if exists and input is empty .then(function (value) { return !hasDefaultValue || Questionnaire.isFilled(value) ? value : defaultValue; })); }; /** * Ask for a string answer, hide input chars. * * @param question The (formatted) question to put * @param validator A validator callback */ Questionnaire.prototype.askHidden = function (question, validator) { if (validator === void 0) { validator = null; } var formattedQuestion = " <fg=green>" + question + "</>:"; return this.doAsk({ question: formattedQuestion, hideInput: true, validator: validator || Questionnaire.isFilled, errorMsg: 'A value is required.' }); }; /** * Ask for picking an option. * * @param question The (formatted) question to put * @param choices A value-label map of options * @param defaultValue A default value to provide */ Questionnaire.prototype.choice = function (question, choices, defaultValue) { if (defaultValue === void 0) { defaultValue = null; } var hasDefaultValue = defaultValue != null; var flippedChoices = Helper_1.flipObject(choices); var choiceValues = Object.keys(choices); var choiceLabels = Object.keys(flippedChoices); if (hasDefaultValue && !Helper_1.arrContains(choiceLabels, defaultValue)) { throw new RangeError("Invalid default value \"" + defaultValue + "\"," + ("must be one of: " + choiceLabels .map(function (label) { return "\"" + label + "\""; }) .join(', '))); } var formattedQuestion = " <fg=green>" + question + "</>"; if (hasDefaultValue) { formattedQuestion += " [<fg=yellow>" + defaultValue + "</>]"; } formattedQuestion += ':\n'; for (var option in choices) { formattedQuestion += " [<fg=yellow>" + option + "</>] " + choices[option] + "\n"; } formattedQuestion = formattedQuestion.slice(0, -1); return (this.doAsk({ question: formattedQuestion, validator: function (value) { return Questionnaire.isFilled(value) ? Helper_1.arrContains(choiceValues, value) : hasDefaultValue; }, errorMsg: function (value) { return "Value \"" + value + "\" is invalid."; } }) // Return default value if exists and input is empty .then(function (value) { return !hasDefaultValue || Questionnaire.isFilled(value) ? value : flippedChoices[defaultValue]; })); }; /** * Ask a yes/no question. * * @param question The (formatted) question to put * @param defaultValue If the answer should default to "yes" */ Questionnaire.prototype.confirm = function (question, defaultValue) { if (defaultValue === void 0) { defaultValue = true; } var formattedQuestion = " <fg=green>" + question + " (yes/no)</> [<fg=yellow>" + (defaultValue ? 'yes' : 'no') + "</>]"; var truthyRegex = /^y/i; return this.doAsk({ question: formattedQuestion }).then(function (value) { return Questionnaire.isFilled(value) ? truthyRegex.test(value.trim()) : defaultValue; }); }; return Questionnaire; }()); exports.default = Questionnaire;