diff --git a/packages/events/defaultSubscribers/migrate/Messages.js b/packages/events/defaultSubscribers/migrate/Messages.js index 064f6503e1a..831821cf8c0 100644 --- a/packages/events/defaultSubscribers/migrate/Messages.js +++ b/packages/events/defaultSubscribers/migrate/Messages.js @@ -220,7 +220,7 @@ class Messages { deployed: () => { let stopText; if (reporter.blockSpinner) { - reporter.blockSpinner.stop(); + reporter.blockSpinner.remove(); stopText = ` > ${reporter.currentBlockWait}`; } @@ -277,7 +277,7 @@ class Messages { // Transactions endTransaction: () => { if (reporter.blockSpinner) { - reporter.blockSpinner.stop(); + reporter.blockSpinner.remove(); } return ` > ${data.message}`; }, diff --git a/packages/events/defaultSubscribers/migrate/Reporter.js b/packages/events/defaultSubscribers/migrate/Reporter.js index a273fe42861..5867edcdcdc 100644 --- a/packages/events/defaultSubscribers/migrate/Reporter.js +++ b/packages/events/defaultSubscribers/migrate/Reporter.js @@ -267,12 +267,10 @@ class Reporter { async deployFailed(data) { if (this.blockSpinner) { this.blockSpinner.fail(); - this.blockSpinner.remove(); } if (this.transactionSpinner) { this.transactionSpinner.fail(); - this.transactionSpinner.remove(); } return await this.processDeploymentError(data); } @@ -304,7 +302,6 @@ class Reporter { data.message = data.message || "Ending unknown transaction...."; const message = this.messages.steps("endTransaction", data); this.transactionSpinner.succeed(); - this.transactionSpinner.remove(); return message; } diff --git a/packages/spinners/lib/spinner.ts b/packages/spinners/lib/spinner.ts index 94e57d4ed3a..961a3068bdd 100644 --- a/packages/spinners/lib/spinner.ts +++ b/packages/spinners/lib/spinner.ts @@ -5,9 +5,9 @@ const spinnies = new Spinnies(); export class Spinner { name: string; - constructor(name: string, options: SpinnerOptions); + constructor(name: string, options: Partial); constructor(name: string, text: string); - constructor(name: string, optionsOrText: SpinnerOptions | string) { + constructor(name: string, optionsOrText: Partial | string) { this.name = name; const options = @@ -45,12 +45,13 @@ export class Spinner { return; } spinnies.remove(this.name); + spinnies.checkIfActiveSpinners(); } /** * Stops the spinner without a failed or succeeded status */ - stop(options?: SpinnerOptions) { + stop(options?: Partial) { const currentOptions = spinnies.pick(this.name); if (!currentOptions) { return; @@ -220,6 +221,6 @@ export class Spinner { options[key] = value; - spinnies.update(this.name, options as SpinnerOptions); + spinnies.update(this.name, options); } } diff --git a/packages/spinners/typings/spinnies/index.d.ts b/packages/spinners/typings/spinnies/index.d.ts index 292aa98eaf1..321d75e6f2f 100644 --- a/packages/spinners/typings/spinnies/index.d.ts +++ b/packages/spinners/typings/spinnies/index.d.ts @@ -1,4 +1,25 @@ declare module "spinnies" { + const dots: Spinner; + const dashes: Spinner; + + type Color = + | "black" + | "red" + | "green" + | "yellow" + | "blue" + | "magenta" + | "cyan" + | "white" + | "gray" + | "redBright" + | "greenBright" + | "yellowBright" + | "blueBright" + | "magentaBright" + | "cyanBright" + | "whiteBright"; + type StopAllStatus = "succeed" | "fail" | "stopped"; type SpinnerStatus = StopAllStatus | "spinning" | "non-spinnable"; @@ -7,129 +28,184 @@ declare module "spinnies" { frames: string[]; } + /** + * The configuration for a given spinner + */ interface SpinnerOptions { /** - * Optional text to show in the spinner. If none is provided, the name field will be shown. + * Text to show in the spinner. If none is provided, the name field will be shown. */ - text?: string; + text: string; /** - * Optional, indent the spinner with the given number of spaces. - * */ - indent?: number; + * Indent the spinner with the given number of spaces. + */ + indent: number; /** - * Initial status of the spinner. Valid statuses are: succeed, fail, spinning, non-spinnable and stopped. + * Initial status of the spinner. */ - status?: SpinnerStatus; + status: SpinnerStatus; /** - * Any valid chalk color. + * The color of the text that accompanies the spinner. If not specified, the console's default foreground color is used. */ - color?: string; + color?: Color; /** - * Any valid chalk color. + * The color for the text on success. Default value is `"green"` */ - succeedColor?: string; + succeedColor: Color; /** - * Any valid chalk color. + * The color for the text on failure. Default value is `"red"`. */ - failColor?: string; + failColor: Color; /** - * Any valid chalk color. The default value is greenBright. + * The color of the spinner, when active. The default value is `"greenBright"` */ - spinnerColor?: string; + spinnerColor: Color; } + /** + * Contains top-level configuration for the Spinnies class. Also allows the + * caller to override default values used in `SpinnerOptions`. + */ interface Options { /** - * Any valid chalk color. The default value is white. + * The color of the text that accompanies the spinner. If not specified, the console's default foreground color is used. */ - color?: string; + color?: Color; /** - * Any valid chalk color. The default value is green. + * The color for the text on success. Default value is `"green"` */ - succeedColor?: string; + succeedColor: Color; /** - * Any valid chalk color. The default value is red. + * The color for the text on failure. Default value is `"red"`. */ - failColor?: string; + failColor: Color; /** - * Any valid chalk color. The default value is greenBright. + * The color of the spinner, when active. The default value is `"greenBright"` */ - spinnerColor?: string; + spinnerColor: Color; /** - * The default value is ✓. + * The symbol to be used in place of the spinner on success. The default value is ✓. */ - succeedPrefix?: string; + succeedPrefix: string; /** - * The default value is ✖. + * The symbol to be used in place of the spinner on failure. The default value is ✖. */ - failPrefix?: string; + failPrefix: string; /** - * Disable spins (will still print raw messages). + * Disable spinner animations (will still print raw messages if `true`). The default value is `false`. */ - disableSpins?: boolean; + disableSpins: boolean; /** - * Spinner configuration + * Defines the animated spinner to be used while each spinner is active/spinning. */ - spinner?: Spinner; + spinner: Spinner; } + /** + * A class that manages multiple CLI spinners. + */ export default class Spinnies { - static dots: Spinner; - static dashes: Spinner; - options: Options; - constructor(options?: Options); + /** + * The current configuration of this Spinnies object. + */ + options: Spinnies.Options; + + constructor(options?: Partial); /** * Add a new spinner with the given name. + * + * @returns full `SpinnerOptions` object for the given spinner, with + * defaults applied */ - add: (name: string, options?: SpinnerOptions) => SpinnerOptions; + add: ( + name: string, + options?: Partial + ) => Spinnies.SpinnerOptions; /** * Get spinner by name. + * + * @returns full `SpinnerOptions` object for the given spinner, with + * defaults applied */ - pick: (name: string) => SpinnerOptions; + pick: (name: string) => Spinnies.SpinnerOptions; /** * Remove spinner with name. + * + * @returns full `SpinnerOptions` object for the given spinner, with + * defaults applied */ - remove: (name: string) => SpinnerOptions; + remove: (name: string) => Spinnies.SpinnerOptions; /** - * Updates the spinner with name name with the provided options. + * Updates the spinner with name name with the provided options. Retains + * the value of options that aren't specified. + * + * @returns full `SpinnerOptions` object for the given spinner, with + * defaults applied */ - update: (name: string, options?: SpinnerOptions) => SpinnerOptions; + update: ( + name: string, + options?: Partial + ) => Spinnies.SpinnerOptions; /** * Sets the specified spinner status as succeed. + * + * @returns full `SpinnerOptions` object for the given spinner, with + * defaults applied */ - succeed: (name: string, options?: SpinnerOptions) => SpinnerOptions; + succeed: ( + name: string, + options?: Partial + ) => Spinnies.SpinnerOptions; /** * Sets the specified spinner status as fail. + * + * @returns full `SpinnerOptions` object for the given spinner, with + * defaults applied */ - fail: (name: string, options?: SpinnerOptions) => SpinnerOptions; + fail: ( + name: string, + options?: Partial + ) => Spinnies.SpinnerOptions; /** * Stops the spinners and sets the non-succeeded and non-failed ones to the provided status. + * + * @returns an object that maps spinner names to final `SpinnerOptions` objects for each spinner, with + * defaults applied */ - stopAll: (status?: StopAllStatus) => { [name: string]: SpinnerOptions }; + stopAll: (status?: Spinnies.StopAllStatus) => { + [name: string]: Spinnies.SpinnerOptions; + }; /** * @returns false if all spinners have succeeded, failed or have been stopped */ hasActiveSpinners: () => boolean; + + /** + * Disables the spinner loop after all spinners have deactivated. Must be + * called after calling `remove` on the final spinner, otherwise the + * spinner loop will prevent the process from exiting. + */ + checkIfActiveSpinners: () => void; } }