UNPKG

@salesforce/command

Version:
335 lines 11.7 kB
"use strict"; /* * Copyright (c) 2020, salesforce.com, inc. * All rights reserved. * Licensed under the BSD 3-Clause license. * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ Object.defineProperty(exports, "__esModule", { value: true }); exports.UX = void 0; // would be willing to change this, but don't want to change types on public methods (object => Record<string, undefined>)) /* eslint-disable @typescript-eslint/ban-types */ /* eslint-disable no-console */ const kit_1 = require("@salesforce/kit"); const ts_types_1 = require("@salesforce/ts-types"); /** * A table option configuration type that can be the TableOptions as defined by * [oclif/cli-ux](https://github.com/oclif/cli-ux/blob/master/src/styled/table.ts) or a string array of table keys to be used as table headers * for simple tables. * * @typedef {object} SfdxTableOptions * @property {TableOptions | string[]} options */ /** * A prompt option configuration as defined by * [oclif/cli-ux](https://github.com/oclif/cli-ux/blob/master/src/prompt.ts). * * @typedef {object} IPromptOptions * @property {string} prompt The prompt string displayed to the user. * @property {'normal' | 'mask' | 'hide'} type `Normal` does not hide the user input, `mask` hides the user input after the user presses `ENTER`, and `hide` hides the user input as it is being typed. */ /** * An action option configuration as defined by * [oclif/cli-ux](https://github.com/oclif/cli-ux/blob/master/src/action/base.ts). * * @typedef {object} OclifActionOptions * @property {boolean} stdout The option to display to stdout or not. */ const core_1 = require("@salesforce/core"); const chalk_1 = require("chalk"); const core_2 = require("@oclif/core"); /** * @deprecated Use Ux from `@salesforce/sf-plugins-core` instead * Utilities for interacting with terminal I/O. */ class UX { /** * Do not directly construct instances of this class -- use {@link UX.create} instead. */ constructor(logger, isOutputEnabled, ux) { this.logger = logger; this.cli = ux ?? core_2.CliUx; if ((0, ts_types_1.isBoolean)(isOutputEnabled)) { this.isOutputEnabled = isOutputEnabled; } else { // Respect the --json flag and SFDX_CONTENT_TYPE for consumers who don't explicitly check const isContentTypeJSON = kit_1.env.getString('SFDX_CONTENT_TYPE', '').toUpperCase() === 'JSON'; this.isOutputEnabled = !(process.argv.find((arg) => arg === '--json') ?? isContentTypeJSON); } } /** * Formats a deprecation warning for display to `stderr`, `stdout`, and/or logs. * * @param {DeprecationDefinition} def The definition for the deprecated object. * @returns {string} The formatted deprecation message. */ static formatDeprecationWarning(def) { let msg; if ((0, ts_types_1.has)(def, 'version')) { const version = (0, ts_types_1.isString)(def.version) ? parseInt(def.version, 10) : def.version || 0; // @ts-ignore const type = (0, ts_types_1.ensure)(def.type); // @ts-ignore const name = (0, ts_types_1.ensure)(def.name); // @ts-ignore // eslint-disable-next-line @typescript-eslint/restrict-plus-operands msg = `The ${type} "${name}" has been deprecated and will be removed in v${version + 1}.0 or later.`; } else { msg = def.messageOverride; } if (def.to) { msg += ` Use "${def.to}" instead.`; } if (def.message) { msg += ` ${def.message}`; } return msg; } /** * Create a `UX` instance. * * @returns {Promise<UX>} A `Promise` of the created `UX` instance. */ static async create() { return new UX(await core_1.Logger.child('UX')); } /** * Logs at `INFO` level and conditionally writes to `stdout` if stream output is enabled. * * @param {...any[]} args The messages or objects to log. * @returns {UX} */ log(...args) { if (this.isOutputEnabled) { this.cli.ux.log(...args); } // log to sfdx.log after the console as log filtering mutates the args. this.logger.info(...args); return this; } /** * Log JSON to stdout and to the log file with log level info. * * @param {object} obj The object to log -- must be serializable as JSON. * @returns {UX} * @throws {TypeError} If the object is not JSON-serializable. */ logJson(obj) { this.cli.ux.styledJSON(obj); // log to sfdx.log after the console as log filtering mutates the args. this.logger.info(obj); return this; } /** * Prompt the user for input. * * @param {string} name The string that the user sees when prompted for information. * @param {IPromptOptions} options A prompt option configuration. * @returns {Promise<string>} The user input to the prompt. */ async prompt(name, options = {}) { return this.cli.ux.prompt(name, options); } /** * Prompt the user for confirmation. * * @param {string} message The message displayed to the user. * @returns {Promise<boolean>} Returns `true` if the user inputs 'y' or 'yes', and `false` if the user inputs 'n' or 'no'. */ async confirm(message) { return this.cli.ux.confirm(message); } /** * Start a spinner action after displaying the given message. * * @param {string} message The message displayed to the user. * @param {string} status The status displayed to the user. * @param {OclifActionOptions} opts The options to select whereas spinner will output to stderr or stdout. */ startSpinner(message, status, opts = {}) { if (this.isOutputEnabled) { this.cli.ux.action.start(message, status, opts); } } /** * Pause the spinner and call the given function. * * @param {function} fn The function to be called in the pause. * @param {string} icon The string displayed to the user. * @returns {T} The result returned by the passed in function. */ pauseSpinner(fn, icon) { if (this.isOutputEnabled) { return this.cli.ux.action.pause(fn, icon); } } /** * Update the spinner status. * * @param {string} status The message displayed to the user. */ setSpinnerStatus(status) { if (this.isOutputEnabled) { this.cli.ux.action.status = status; } } /** * Get the spinner status. * * @returns {Optional<string>} */ getSpinnerStatus() { if (this.isOutputEnabled) { return this.cli.ux.action.status; } } /** * Stop the spinner action. * * @param {string} message The message displayed to the user. */ stopSpinner(message) { if (this.isOutputEnabled) { this.cli.ux.action.stop(message); } } /** * Logs a warning as `WARN` level and conditionally writes to `stderr` if the log * level is `WARN` or above and stream output is enabled. The message is added * to the static {@link UX.warnings} set if stream output is _not_ enabled, for later * consumption and manipulation. * * @param {string} message The warning message to output. * @returns {UX} * @see UX.warnings */ warn(message) { const warning = chalk_1.default.yellow('WARNING:'); // Necessarily log to sfdx.log. this.logger.warn(warning, message); if (this.logger.shouldLog(core_1.LoggerLevel.WARN)) { if (!this.isOutputEnabled) { UX.warnings.add(message); } else { console.warn(`${warning} ${message}`); } } return this; } /** * Logs an error at `ERROR` level and conditionally writes to `stderr` if stream * output is enabled. * * @param {...any[]} args The errors to log. * @returns {UX} */ error(...args) { if (this.isOutputEnabled) { console.error(...args); } this.logger.error(...args); return this; } /** * Logs an object as JSON at `ERROR` level and to `stderr`. * * @param {object} obj The error object to log -- must be serializable as JSON. * @returns {UX} * @throws {TypeError} If the object is not JSON-serializable. */ errorJson(obj) { const err = JSON.stringify(obj, null, 4); console.error(err); this.logger.error(err); return this; } /** * Logs at `INFO` level and conditionally writes to `stdout` in a table format if * stream output is enabled. * * @param {object[]} rows The rows of data to be output in table format. * @param columns Table column options * @param {SfdxTableOptions} options The {@link SfdxTableOptions} to use for formatting. * @returns {UX} */ table( // (allow any because matches oclif) // eslint-disable-next-line @typescript-eslint/no-explicit-any rows, columns = {}, options = { 'no-truncate': true }) { if (this.isOutputEnabled) { // This is either an array of column names or an already built Partial<OclifTableOptions> if ((0, ts_types_1.isArray)(columns)) { const tableColumns = {}; for (const col of columns) { tableColumns[col] = { header: col .split(/(?=[A-Z])|[-_\s]/) .map((w) => w.toUpperCase()) .join(' '), }; } this.cli.ux.table(rows, tableColumns, options); } else { this.cli.ux.table(rows, columns, options); } } // Log after table output as log filtering mutates data. this.logger.info(rows); return this; } /** * Logs at `INFO` level and conditionally writes to `stdout` in a styled object format if * stream output is enabled. * * @param {object} obj The object to be styled for stdout. * @param {string[]} [keys] The object keys to be written to stdout. * @returns {UX} */ styledObject(obj, keys) { this.logger.info(obj); if (this.isOutputEnabled) { this.cli.ux.styledObject(obj, keys); } return this; } /** * Log at `INFO` level and conditionally write to `stdout` in styled JSON format if * stream output is enabled. * * @param {object} obj The object to be styled for stdout. * @returns {UX} */ styledJSON(obj) { this.logger.info(obj); if (this.isOutputEnabled) { this.cli.ux.styledJSON(obj); } return this; } /** * Logs at `INFO` level and conditionally writes to `stdout` in a styled header format if * stream output is enabled. * * @param {string} header The header to be styled. * @returns {UX} */ styledHeader(header) { this.logger.info(header); if (this.isOutputEnabled) { this.cli.ux.styledHeader(header); } return this; } } exports.UX = UX; /** * Collection of warnings that can be accessed and manipulated later. * * @type {Set<string>} */ UX.warnings = new Set(); //# sourceMappingURL=ux.js.map