1 | ;
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | const kit_1 = require("@salesforce/kit");
|
4 | const ts_types_1 = require("@salesforce/ts-types");
|
5 | /*
|
6 | * Copyright (c) 2018, salesforce.com, inc.
|
7 | * All rights reserved.
|
8 | * SPDX-License-Identifier: BSD-3-Clause
|
9 | * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
10 | */
|
11 | /**
|
12 | * A table option configuration type that can be the TableOptions as defined by
|
13 | * [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
|
14 | * for simple tables.
|
15 | * @typedef {object} SfdxTableOptions
|
16 | * @property {TableOptions | string[]} options
|
17 | */
|
18 | /**
|
19 | * A prompt option configuration as defined by
|
20 | * [oclif/cli-ux](https://github.com/oclif/cli-ux/blob/master/src/prompt.ts).
|
21 | * @typedef {object} IPromptOptions
|
22 | * @property {string} prompt The prompt string displayed to the user.
|
23 | * @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.
|
24 | */
|
25 | const core_1 = require("@salesforce/core");
|
26 | const ts_types_2 = require("@salesforce/ts-types");
|
27 | const chalk_1 = require("chalk");
|
28 | const cli_ux_1 = require("cli-ux");
|
29 | /**
|
30 | * Utilities for interacting with terminal I/O.
|
31 | */
|
32 | class UX {
|
33 | /**
|
34 | * Do not directly construct instances of this class -- use {@link UX.create} instead.
|
35 | */
|
36 | constructor(logger, isOutputEnabled, ux) {
|
37 | this.logger = logger;
|
38 | this.cli = ux || cli_ux_1.cli;
|
39 | if (ts_types_2.isBoolean(isOutputEnabled)) {
|
40 | this.isOutputEnabled = isOutputEnabled;
|
41 | }
|
42 | else {
|
43 | // Respect the --json flag and SFDX_CONTENT_TYPE for consumers who don't explicitly check
|
44 | const isContentTypeJSON = kit_1.env.getString('SFDX_CONTENT_TYPE', '').toUpperCase() === 'JSON';
|
45 | this.isOutputEnabled = !(process.argv.find(arg => arg === '--json') || isContentTypeJSON);
|
46 | }
|
47 | }
|
48 | /**
|
49 | * Formats a deprecation warning for display to `stderr`, `stdout`, and/or logs.
|
50 | *
|
51 | * @param {DeprecationDefinition} def The definition for the deprecated object.
|
52 | * @returns {string} The formatted deprecation message.
|
53 | */
|
54 | static formatDeprecationWarning(def) {
|
55 | let msg;
|
56 | if (ts_types_2.has(def, 'version')) {
|
57 | const version = ts_types_2.isString(def.version) ? parseInt(def.version, 10) : def.version || 0;
|
58 | const type = ts_types_1.ensure(def.type);
|
59 | const name = ts_types_1.ensure(def.name);
|
60 | msg = `The ${type} "${name}" has been deprecated and will be removed in v${version + 1}.0 or later.`;
|
61 | }
|
62 | else {
|
63 | msg = def.messageOverride;
|
64 | }
|
65 | if (def.to) {
|
66 | msg += ` Use "${def.to}" instead.`;
|
67 | }
|
68 | if (def.message) {
|
69 | msg += ` ${def.message}`;
|
70 | }
|
71 | return msg;
|
72 | }
|
73 | /**
|
74 | * Create a `UX` instance.
|
75 | *
|
76 | * @returns {Promise<UX>} A `Promise` of the created `UX` instance.
|
77 | */
|
78 | static async create() {
|
79 | return new UX(await core_1.Logger.child('UX'));
|
80 | }
|
81 | /**
|
82 | * Logs at `INFO` level and conditionally writes to `stdout` if stream output is enabled.
|
83 | *
|
84 | * @param {...any[]} args The messages or objects to log.
|
85 | * @returns {UX}
|
86 | */
|
87 | log(...args) {
|
88 | if (this.isOutputEnabled) {
|
89 | this.cli.log(...args);
|
90 | }
|
91 | // log to sfdx.log after the console as log filtering mutates the args.
|
92 | this.logger.info(...args);
|
93 | return this;
|
94 | }
|
95 | /**
|
96 | * Log JSON to stdout and to the log file with log level info.
|
97 | *
|
98 | * @param {object} obj The object to log -- must be serializable as JSON.
|
99 | * @returns {UX}
|
100 | * @throws {TypeError} If the object is not JSON-serializable.
|
101 | */
|
102 | logJson(obj) {
|
103 | this.cli.styledJSON(obj);
|
104 | // log to sfdx.log after the console as log filtering mutates the args.
|
105 | this.logger.info(obj);
|
106 | return this;
|
107 | }
|
108 | /**
|
109 | * Prompt the user for input.
|
110 | * @param {string} name The string that the user sees when prompted for information.
|
111 | * @param {IPromptOptions} options A prompt option configuration.
|
112 | * @returns {Promise<string>} The user input to the prompt.
|
113 | */
|
114 | async prompt(name, options = {}) {
|
115 | return this.cli.prompt(name, options);
|
116 | }
|
117 | /**
|
118 | * Prompt the user for confirmation.
|
119 | * @param {string} message The message displayed to the user.
|
120 | * @returns {Promise<boolean>} Returns `true` if the user inputs 'y' or 'yes', and `false` if the user inputs 'n' or 'no'.
|
121 | */
|
122 | async confirm(message) {
|
123 | return this.cli.confirm(message);
|
124 | }
|
125 | /**
|
126 | * Start a spinner action after displaying the given message.
|
127 | * @param {string} message The message displayed to the user.
|
128 | */
|
129 | startSpinner(message) {
|
130 | if (this.isOutputEnabled) {
|
131 | this.cli.action.start(message);
|
132 | }
|
133 | }
|
134 | /**
|
135 | * Pause the spinner and call the given function.
|
136 | * @param {function} fn The function to be called in the pause.
|
137 | * @param {string} icon The string displayed to the user.
|
138 | * @returns {T} The result returned by the passed in function.
|
139 | */
|
140 | pauseSpinner(fn, icon) {
|
141 | if (this.isOutputEnabled) {
|
142 | return this.cli.action.pause(fn, icon);
|
143 | }
|
144 | }
|
145 | /**
|
146 | * Update the spinner status.
|
147 | * @param {string} status The message displayed to the user.
|
148 | */
|
149 | setSpinnerStatus(status) {
|
150 | if (this.isOutputEnabled) {
|
151 | this.cli.action.status = status;
|
152 | }
|
153 | }
|
154 | /**
|
155 | * Get the spinner status.
|
156 | * @returns {Optional<string>}
|
157 | */
|
158 | getSpinnerStatus() {
|
159 | if (this.isOutputEnabled) {
|
160 | return this.cli.action.status;
|
161 | }
|
162 | }
|
163 | /**
|
164 | * Stop the spinner action.
|
165 | * @param {string} message The message displayed to the user.
|
166 | */
|
167 | stopSpinner(message) {
|
168 | if (this.isOutputEnabled) {
|
169 | this.cli.action.stop(message);
|
170 | }
|
171 | }
|
172 | /**
|
173 | * Logs a warning as `WARN` level and conditionally writes to `stderr` if the log
|
174 | * level is `WARN` or above and stream output is enabled. The message is added
|
175 | * to the static {@link UX.warnings} set if stream output is _not_ enabled, for later
|
176 | * consumption and manipulation.
|
177 | *
|
178 | * @param {string} message The warning message to output.
|
179 | * @returns {UX}
|
180 | * @see UX.warnings
|
181 | */
|
182 | warn(message) {
|
183 | const warning = chalk_1.default.yellow('WARNING:');
|
184 | // Necessarily log to sfdx.log.
|
185 | this.logger.warn(warning, message);
|
186 | if (this.logger.shouldLog(core_1.LoggerLevel.WARN)) {
|
187 | if (!this.isOutputEnabled) {
|
188 | UX.warnings.add(message);
|
189 | }
|
190 | else {
|
191 | console.warn(`${warning} ${message}`);
|
192 | }
|
193 | }
|
194 | return this;
|
195 | }
|
196 | /**
|
197 | * Logs an error at `ERROR` level and conditionally writes to `stderr` if stream
|
198 | * output is enabled.
|
199 | *
|
200 | * @param {...any[]} args The errors to log.
|
201 | * @returns {UX}
|
202 | */
|
203 | error(...args) {
|
204 | if (this.isOutputEnabled) {
|
205 | console.error(...args);
|
206 | }
|
207 | this.logger.error(...args);
|
208 | return this;
|
209 | }
|
210 | /**
|
211 | * Logs an object as JSON at `ERROR` level and to `stderr`.
|
212 | *
|
213 | * @param {object} obj The error object to log -- must be serializable as JSON.
|
214 | * @returns {UX}
|
215 | * @throws {TypeError} If the object is not JSON-serializable.
|
216 | */
|
217 | errorJson(obj) {
|
218 | const err = JSON.stringify(obj, null, 4);
|
219 | console.error(err);
|
220 | this.logger.error(err);
|
221 | return this;
|
222 | }
|
223 | /**
|
224 | * Logs at `INFO` level and conditionally writes to `stdout` in a table format if
|
225 | * stream output is enabled.
|
226 | *
|
227 | * @param {object[]} rows The rows of data to be output in table format.
|
228 | * @param {SfdxTableOptions} options The {@link SfdxTableOptions} to use for formatting.
|
229 | * @returns {UX}
|
230 | */
|
231 | // tslint:disable-next-line no-any (matches oclif)
|
232 | table(rows, options = {}) {
|
233 | if (this.isOutputEnabled) {
|
234 | // This is either an array of column names or an already built Partial<OclifTableOptions>
|
235 | if (ts_types_2.isArray(options)) {
|
236 | const tableColumns = [];
|
237 | for (const col of options) {
|
238 | tableColumns.push({
|
239 | key: col,
|
240 | label: col
|
241 | .split(/(?=[A-Z])|[-_\s]/)
|
242 | .map(w => w.toUpperCase())
|
243 | .join(' ')
|
244 | });
|
245 | }
|
246 | this.cli.table(rows, { columns: tableColumns });
|
247 | }
|
248 | else {
|
249 | this.cli.table(rows, options);
|
250 | }
|
251 | }
|
252 | // Log after table output as log filtering mutates data.
|
253 | this.logger.info(rows);
|
254 | return this;
|
255 | }
|
256 | /**
|
257 | * Logs at `INFO` level and conditionally writes to `stdout` in a styled object format if
|
258 | * stream output is enabled.
|
259 | *
|
260 | * @param {object} obj The object to be styled for stdout.
|
261 | * @param {string[]} [keys] The object keys to be written to stdout.
|
262 | * @returns {UX}
|
263 | */
|
264 | styledObject(obj, keys) {
|
265 | this.logger.info(obj);
|
266 | if (this.isOutputEnabled) {
|
267 | this.cli.styledObject(obj, keys);
|
268 | }
|
269 | return this;
|
270 | }
|
271 | /**
|
272 | * Log at `INFO` level and conditionally write to `stdout` in styled JSON format if
|
273 | * stream output is enabled.
|
274 | *
|
275 | * @param {object} obj The object to be styled for stdout.
|
276 | * @returns {UX}
|
277 | */
|
278 | styledJSON(obj) {
|
279 | this.logger.info(obj);
|
280 | if (this.isOutputEnabled) {
|
281 | this.cli.styledJSON(obj);
|
282 | }
|
283 | return this;
|
284 | }
|
285 | /**
|
286 | * Logs at `INFO` level and conditionally writes to `stdout` in a styled header format if
|
287 | * stream output is enabled.
|
288 | *
|
289 | * @param {string} header The header to be styled.
|
290 | * @returns {UX}
|
291 | */
|
292 | styledHeader(header) {
|
293 | this.logger.info(header);
|
294 | if (this.isOutputEnabled) {
|
295 | this.cli.styledHeader(header);
|
296 | }
|
297 | return this;
|
298 | }
|
299 | }
|
300 | /**
|
301 | * Collection of warnings that can be accessed and manipulated later.
|
302 | * @type {Set<string>}
|
303 | */
|
304 | UX.warnings = new Set();
|
305 | exports.UX = UX;
|
306 | //# sourceMappingURL=ux.js.map |
\ | No newline at end of file |