Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve ora.promise() #181

Merged
merged 11 commits into from
Aug 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
28 changes: 22 additions & 6 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,22 @@ declare namespace ora {
readonly prefixText?: string | PrefixTextGenerator;
}

interface PromiseOptions<T> extends Options {
/**
The new text of the spinner when the promise is resolved.

If undefined, will keep the initial text.
*/
successText?: string | ((result: T) => string);

/**
The new text of the spinner when the promise is rejected.

If undefined, will keep the initial text.
*/
failText?: string | ((error: Error) => string);
}

interface Ora {
/**
A boolean of whether the instance is currently spinning.
Expand Down Expand Up @@ -259,19 +275,19 @@ declare const ora: {
}, 1000);
```
*/
(options?: ora.Options | string): ora.Ora;
(options?: string | ora.Options): ora.Ora;

/**
Starts a spinner for a promise. The spinner is stopped with `.succeed()` if the promise fulfills or with `.fail()` if it rejects.
Starts a spinner for a function or a promise. The spinner is stopped with `.succeed()` if the promise fulfills or with `.fail()` if it rejects. Returns the Promise.

@param action - The promise to start the spinner for.
@param options - If a string is provided, it is treated as a shortcut for `options.text`.
@returns The spinner instance.
*/
promise(
action: PromiseLike<unknown>,
options?: ora.Options | string
): ora.Ora;
promise<T>(
action: PromiseLike<T> | ((spinner: ora.Ora) => PromiseLike<T>),
options?: string | ora.PromiseOptions<T>
): Promise<T>;
};

export = ora;
42 changes: 27 additions & 15 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -385,23 +385,35 @@ const oraFactory = function (options) {

module.exports = oraFactory;

module.exports.promise = (action, options) => {
// https://github.com/sindresorhus/ora/issues/169#issuecomment-873269524
module.exports.promise = async (action, options) => {
const actionIsFunction = typeof action === 'function';
// eslint-disable-next-line promise/prefer-await-to-then
if (typeof action.then !== 'function') {
throw new TypeError('Parameter `action` must be a Promise');
}
const actionIsPromise = typeof action.then === 'function';

const spinner = new Ora(options);
spinner.start();
if (!actionIsFunction && !actionIsPromise) {
throw new TypeError('Parameter `action` must be a Function or a Promise');
}

(async () => {
try {
await action;
spinner.succeed();
} catch {
spinner.fail();
}
})();
const {successText, failText} = typeof options === 'object' ?
options :
{successText: undefined, failText: undefined};

return spinner;
const spinner = new Ora(options); // Set the initial string or ora options.
spinner.start();
try {
const promise = actionIsFunction ? action(spinner) : action;
const result = await promise;
spinner.succeed(successText === undefined ?
undefined :
(typeof successText === 'string' ? successText : successText(result))
);
return result;
} catch (error) {
spinner.fail(failText === undefined ?
undefined :
(typeof failText === 'string' ? failText : failText(error))
);
throw error;
}
};
20 changes: 18 additions & 2 deletions index.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,27 @@ spinner.render();
spinner.frame();

const resolves = Promise.resolve(1);
promise(resolves, 'foo');
promise(resolves, {
void promise(resolves, 'foo');
void promise(resolves, {
stream: new PassThroughStream(),
text: 'foo',
color: 'blue',
isEnabled: true,
isSilent: false
});
void promise(async () => {
await resolves;
}, 'foo');
void promise(async spinner => {
spinner.prefixText = 'foo';
await resolves;
return 7;
}, {
stream: new PassThroughStream(),
text: 'foo',
color: 'blue',
isEnabled: true,
isSilent: false,
successText: result => `Resolved with number ${result}`,
failText: 'bar'
});
21 changes: 19 additions & 2 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,11 +226,28 @@ Change the spinner indent.
### ora.promise(action, text)
### ora.promise(action, options)

Starts a spinner for a promise. The spinner is stopped with `.succeed()` if the promise fulfills or with `.fail()` if it rejects. Returns the spinner instance.
Starts a spinner for a function or a promise. The spinner is stopped with `.succeed()` if the promise fulfills or with `.fail()` if it rejects. Returns the promise.

#### action

Type: `Promise`
Type: `Promise | ((spinner: ora.Ora) => Promise)`

#### options

Type: `object`

All of the [options](#options) plus the following:

##### successText
Type: `string | ((result: T) => string)`
Copy link
Contributor Author

@SrBrahma SrBrahma Jul 25, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the functions, I used this as pattern: https://github.com/sindresorhus/got/blob/main/documentation/5-https.md#checkserveridentity. Please, change it further if wanted to fit your README styling.


The new text of the spinner when the promise is resolved. If undefined, will keep the initial text.

##### failText
Type: `string | ((error: Error) => string)`

The new text of the spinner when the promise is rejected. If undefined, will keep the initial text.


## FAQ

Expand Down
14 changes: 6 additions & 8 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,15 +167,13 @@ test('.promise() - rejects', async t => {
const output = getStream(stream);
const rejects = Promise.reject(new Error()); // eslint-disable-line unicorn/error-message

Ora.promise(rejects, {
stream,
text: 'foo',
color: false,
isEnabled: true
});

try {
await rejects;
await Ora.promise(rejects, {
stream,
text: 'foo',
color: false,
isEnabled: true
})
} catch {}

stream.end();
Expand Down