UNPKG

@sfdx-falcon/prompt

Version:

Provides a standardized means of user interaction via the console. Part of the SFDX-Falcon Library.

186 lines 11.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); //─────────────────────────────────────────────────────────────────────────────────────────────────┐ /** * @author Vivek M. Chawla <@VivekMChawla> * @copyright 2019, Vivek M. Chawla / Salesforce. All rights reserved. * @license BSD-3-Clause For full license text, see the LICENSE file in the repo root or * `https://opensource.org/licenses/BSD-3-Clause` * @file packages/prompt/src/prompt.ts * @summary Exports `SfdxFalconPrompt` which provides user interaction via the console. * @description Helps developers quickly build Inquirer based interviews. Prompts created this * way can be executed alone or as part of an `SfdxFalconInterview` group. */ //─────────────────────────────────────────────────────────────────────────────────────────────────┘ /** */ // Import External Libraries, Modules, and Types const inquirer = require("inquirer"); // A collection of common interactive command line user interfaces. // Import SFDX-Falcon Classes & Functions const builder_1 = require("@sfdx-falcon/builder"); // Abstract Class. Basis for creating "builder" classes that can create Tasks, Questions, and more. const debug_1 = require("@sfdx-falcon/debug"); // Class. Provides custom "debugging" services (ie. debug-style info to console.log()). const status_1 = require("@sfdx-falcon/status"); // Class. Uses table creation code borrowed from the SFDX-Core UX library to make it easy to build "Key/Value" tables. // Set the File Local Debug Namespace const dbgNs = '@sfdx-falcon:prompt'; debug_1.SfdxFalconDebug.msg(`${dbgNs}:`, `Debugging initialized for ${dbgNs}`); //─────────────────────────────────────────────────────────────────────────────────────────────────┐ /** * @class SfdxFalconPrompt * @summary Collection of one or more Inquirer Questions that can be used to gather user input. * @description Allows easy creation of Inquirer prompts that have a "confirmation" question that * can be used to restart collection of the information. * @public */ //─────────────────────────────────────────────────────────────────────────────────────────────────┘ class SfdxFalconPrompt { //───────────────────────────────────────────────────────────────────────────┐ /** * @constructs SfdxFalconPrompt * @param {PromptOptions<T>} opts Required. Options that define the * questions, default answers, confirmation questions, and * Prompt Engine that should be used by this SfdxFalconPrompt * object. * @description Constructs an SfdxFalconPrompt object. * @public */ //───────────────────────────────────────────────────────────────────────────┘ constructor(opts) { this._questions = opts.questions; this._questionsArgs = opts.questionsArgs || []; this._confirmation = opts.confirmation; this._confirmationArgs = opts.confirmationArgs || []; this._display = opts.display; this._invertConfirmation = opts.invertConfirmation || false; this.defaultAnswers = opts.defaultAnswers; this.confirmationAnswers = {}; this.userAnswers = {}; } // Public Accessors /** Returns the set of Inquirer `Questions` that will be displayed during the 'confirmation' phase of the prompt. */ get confirmation() { if (this._confirmation instanceof builder_1.Builder) { return this._confirmation.build(this); } if (typeof this._confirmation === 'function') { return this._confirmation.call(this, this._confirmationArgs); } else { return this._confirmation; } } /** Returns a union of Default and User Answers, representing the "final" set of answers to this prompt. */ get finalAnswers() { return Object.assign(Object.assign({}, this.defaultAnswers), this.userAnswers); } /** Returns the set of Inquirer `Questions` that will be displayed as the main part of this prompt. */ get questions() { if (this._questions instanceof builder_1.Builder) { return this._questions.build(this); } if (typeof this._questions === 'function') { return this._questions.apply(this, this._questionsArgs); } else { return this._questions; } } //─────────────────────────────────────────────────────────────────────────────┐ /** * @method prompt * @returns {Promise<T>} Returns the answers provided by the user. * @description Uses an Inquirer prompt() function to show the questions defined * in this SfdxFalconPrompt to the user and returns their input. * @public @async */ //─────────────────────────────────────────────────────────────────────────────┘ async prompt() { // Define function-local debug namespace. const funcName = `prompt`; const dbgNsLocal = `${dbgNs}:${funcName}`; // Start the question loop. If a "confirmation" is specified, the loop will // continue until the user indicates that they want to continue. do { // Grab questions first. This lets us debug AND use them without questions being built twice. const questions = this.questions; // DEBUG debug_1.SfdxFalconDebug.obj(`${dbgNsLocal}:questions:`, questions); // Prompt the user and store the answers. this.userAnswers = await inquirer.prompt(questions); // If there is anything to display, displayAnswers() will take care of it. await this.displayAnswers(); } while (await this.confirmRestart()); // Send back the user's answers. return this.userAnswers; } //───────────────────────────────────────────────────────────────────────────┐ /** * @method confirmRestart * @returns {Promise<boolean>} Returns true if the user wants to restart, * false if otherwise. * @description If this.confirmation contains Questions, prompts the user with * those questions and then decides to continue or restart based * on the answers. * @private @async */ //───────────────────────────────────────────────────────────────────────────┘ async confirmRestart() { // Define function-local debug namespace. const funcName = `confirmRestart`; const dbgNsLocal = `${dbgNs}:${funcName}`; // Debug - Keep commented out unless needed for troubleshooting. //SfdxFalconDebug.obj(`${dbgNs}confirmRestart:`, this.confirmation, `this.confirmation: `); //SfdxFalconDebug.obj(`${dbgNs}confirmRestart:`, this.confirmationAnswers, `this.confirmationAnswers: `); // If "confirmation" is undefined then the user should be allowed to proceed. if (typeof this._confirmation === 'undefined') { this.confirmationAnswers.proceed = true; this.confirmationAnswers.restart = false; this.confirmationAnswers.abort = false; return false; } // Tell Yeoman to prompt the user for confirmation of installation. this.confirmationAnswers = await inquirer.prompt(this.confirmation); // DEBUG debug_1.SfdxFalconDebug.obj(`${dbgNsLocal}:this.confirmationAnswers:`, this.confirmationAnswers); // Check if the Confirmation Answer "proceed" was provided. If it's TRUE, do not restart. if (this.confirmationAnswers.proceed === true) { return false; } // Convert the "invert confirmation" and "restart" booleans into numbers. const invertConfirmation = this._invertConfirmation ? 1 : 0; const restart = this.confirmationAnswers.restart ? 1 : 0; // XOR the values of "invert" and "restart" numbers to get the correct boolean. if ((invertConfirmation ^ restart) === 0) { return false; // Do not restart the prompts. } else { console.log(''); // Separate confirmation question from restarted prompts with a blank line. return true; // Restart the prompts. } } //───────────────────────────────────────────────────────────────────────────┐ /** * @method displayAnswers * @returns {Promise<void>} * @description Uses the Display function (if present) to display the User * Answers from the prompt to the user. If the Display function * returns void, it means that it rendered output to the user. * If it returns an Array, it means that we need to manually * render the returned data in a FalconTable. * @private @async */ //───────────────────────────────────────────────────────────────────────────┘ async displayAnswers() { // If there's a Display Function, use that to build/display the output. if (typeof this._display === 'function') { // The display function *might* render something on its own. If it does, it will return void. const displayResults = await this._display(this.userAnswers); // If the display function returned an Array, then we'll show it to the user with a Falcon Table. if (Array.isArray(displayResults)) { const falconTable = new status_1.SfdxFalconKeyValueTable(); console.log(''); falconTable.render(displayResults); console.log(''); } } } } exports.SfdxFalconPrompt = SfdxFalconPrompt; //# sourceMappingURL=prompt.js.map