Asynchronous CLI Spinner. Allow to create and manage simultaneous/multiple spinners at a time.
npm install @slimio/async-cli-spinnerAsynchronous CLI Spinner. This package has been created to handle simultaneous/multiple spinner at a time. The package has been inspired by Ora but in Asynchronous.
All available spinners are part of cli-spinners package.

This package is available in the Node Package Repository and can be easily installed with npm or yarn.
``bash`
$ npm i @slimio/async-cli-spinneror
$ yarn add @slimio/async-cli-spinner
js
const { promisify } = require("util");
const Spinner = require("@slimio/async-cli-spinner");const sleep = promisify(setTimeout);
async function fnWithSpinner(prefixText, succeed = true) {
const spinner = new Spinner({ prefixText }).start("Start working!");
await sleep(1000);
spinner.text = "Work in progress...";
await sleep(1000);
if (succeed) {
spinner.succeed(
All done in ${spinner.elapsedTime.toFixed(2)}ms !);
}
else {
spinner.failed("Something wrong happened !");
}
}Spinner.startAll([
fnWithSpinner,
Spinner.create(fnWithSpinner),
Spinner.create(fnWithSpinner, "Item 1"),
Spinner.create(fnWithSpinner, "Item 2", false)
])
.then(() => console.log("All spinners finished!"))
.catch(console.error);
`If you want to only achieve one Spinner by one Spinner, use it like Ora (it will work)
`js
const spinner = new Spinner().start("Start working!");await sleep(1000);
spinner.text = "Work in progress...";
await sleep(1000);
spinner.succeed("All done !");
`> 👀 When you are working on a CLI that can be used as an API too, the verbose option allow you to disable the Spinner.
API
Spinner line structure :
${spinner} ${prefixText} - ${text}Properties :
`ts
declare namespace Spinner {
public spinner: cliSpinners.Spinner;
public prefixText: string;
public text: string;
public color: string;
public started: boolean;
public startTime: number;
public stream: TTY.WriteStream;
public readonly elapsedTime: number;
}
`-
spinner: spinner type (default: "dots")
- prefixText: mostly used to differentiate each spinner
- text: you can change text at any moment.
- color: spinner color
- elapsedTime: time elapsed since start() call
constructor(options?: Spinner.options)
Create a new Spinner object. options is described by the following TypeScript interface:
`ts
declare namespace Spinner {
interface spinnerObj {
frames: string[];
interval: number;
} interface options {
spinner: SpinnerObj | Spinner.spinners;
text: string;
prefixText: string;
color: string;
verbose: boolean;
}
}
`> 👀 Look cli-spinners for all kind of available spinners.
Example:
`js
const Spinner = require("@slimio/async-cli-spinner");const spinner = new Spinner();
const dotsSpinner = new Spinner({ spinner: "dots" });
`
static startAll(functions: Spinner.Handler[], options?: Spinner.startOpt): Promise<any[]>
Start all functions with spinners passed in array.
> ⚠️ Only accept functions that return a Promise.
Options is described by the following TypeScript interface:
`ts
declare namespace Spinner {
type RecapSet = "none" | "error" | "always"; interface startOpt {
recap: RecapSet;
rejects: boolean;
}
}
`
> Default recap : always
static create(fn: Spinner.Handler, args?: any): Function|[Function, ...any]
This method allow to pass arguments to our spinner function. This method prevent execute function to earlier.
`js
async function fnWithSpinner(prefixText) {
const spinner = new Spinner({ prefixText }).start("Start working!"); await new Promise((resolve) => setTimeout(resolve, 1000));
spinner.text = "Work in progress...";
await new Promise((resolve) => setTimeout(resolve, 1000));
spinner.succeed("All done !");
}
Spinner.startAll([
fnWithSpinner("Item 1"), // <-- Wrong, it's executed directly, not in startAll
Spinner.create(fnWithSpinner, "Item 2") // <-- What you should do
])
.then(() => console.log("All spinners finished!"))
.catch(console.error);
`
-------------------------------------------------
start(text?: string): Spinner
Start the spinner in the CLI and write the text passed in param.
`js
const Spinner = require("@slimio/async-cli-spinner");async function fnWithSpinner() {
const spinner = new Spinner().start("Start working!");
}
Spinner.startAll([
fnWithSpinner
])
.then(() => console.log("All spinners finished!"))
.catch(console.error);
`
succeed(text?: string): void
Stop the spinner in the CLI, write the text passed in param and mark it as succeed with a symbol.
`js
const Spinner = require("@slimio/async-cli-spinner");async function fnWithSpinner() {
const spinner = new Spinner().start("Start working!");
await new Promise((resolve) => setTimeout(resolve, 1000));
spinner.succeed("All done !");
}
Spinner.startAll([
fnWithSpinner
])
.then(() => console.log("All spinners finished!"))
.catch(console.error);
`
failed(text?: string): void
Stop the spinner in the CLI, write the text passed in param and mark it as failed with a symbol.
`js
const Spinner = require("@slimio/async-cli-spinner");async function fnWithSpinner() {
const spinner = new Spinner().start("Start working!");
await new Promise((resolve) => setTimeout(resolve, 1000));
spinner.failed("Something wrong happened !");
}
Spinner.startAll([
fnWithSpinner
])
.then(() => console.log("All spinners finished!"))
.catch(console.error);
``> ⚠️ Functions start(), succeed() and failed() are supposed to be executed in a function which return a promise and will be called by Spinner.startAll().
|Name|Refactoring|Security Risk|Usage|
|---|---|---|---|
|@slimio/is|Minor|Low|Type checker|
|@slimio/wcwidth|⚠️Major|Low|Get CLI columns for special characters|
|ansi-regex|Minor|Low|Get ANSI code|
|cli-cursor|⚠️Major|High|Show/Hide CLI cursor|
|cli-spinners|Minor|Low|Bunch of spinner|
|kleur|Minor|Low|CLI color|
|strip-ansi|Minor|Low|ANSI escape codes|