Require Node.js 12 and move to ESM

This commit is contained in:
Sindre Sorhus 2021-04-07 00:38:12 +07:00
parent 4f86930f75
commit 458618efa4
8 changed files with 127 additions and 150 deletions

3
.github/funding.yml vendored
View File

@ -1,3 +0,0 @@
github: sindresorhus
open_collective: sindresorhus
custom: https://sindresorhus.com/donate

View File

@ -12,7 +12,6 @@ jobs:
node-version: node-version:
- 14 - 14
- 12 - 12
- 10
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions/setup-node@v1 - uses: actions/setup-node@v1

114
index.d.ts vendored
View File

@ -1,12 +1,18 @@
declare class TimeoutErrorClass extends Error { /* eslint-disable import/export */
export class TimeoutError extends Error {
readonly name: 'TimeoutError'; readonly name: 'TimeoutError';
constructor(message?: string); constructor(message?: string);
} }
declare namespace pTimeout { export interface ClearablePromise<T> extends Promise<T>{
type TimeoutError = TimeoutErrorClass; /**
Clear the timeout.
*/
clear: () => void;
}
type Options = { export type Options = {
/** /**
Custom implementations for the `setTimeout` and `clearTimeout` functions. Custom implementations for the `setTimeout` and `clearTimeout` functions.
@ -14,10 +20,9 @@ declare namespace pTimeout {
@example @example
``` ```
import pTimeout = require('p-timeout'); import pTimeout from 'p-timeout';
import sinon = require('sinon'); import sinon from 'sinon';
(async () => {
const originalSetTimeout = setTimeout; const originalSetTimeout = setTimeout;
const originalClearTimeout = clearTimeout; const originalClearTimeout = clearTimeout;
@ -30,84 +35,67 @@ declare namespace pTimeout {
clearTimeout: originalClearTimeout clearTimeout: originalClearTimeout
} }
}); });
})();
``` ```
*/ */
readonly customTimers?: { readonly customTimers?: {
setTimeout: typeof global.setTimeout; setTimeout: typeof global.setTimeout;
clearTimeout: typeof global.clearTimeout; clearTimeout: typeof global.clearTimeout;
}; };
}; };
}
interface ClearablePromise<T> extends Promise<T>{ /**
/** Timeout a promise after a specified amount of time.
Clear the timeout.
*/
clear: () => void;
}
declare const pTimeout: { If you pass in a cancelable promise, specifically a promise with a `.cancel()` method, that method will be called when the `pTimeout` promise times out.
TimeoutError: typeof TimeoutErrorClass;
default: typeof pTimeout; @param input - Promise to decorate.
@param milliseconds - Milliseconds before timing out.
@param message - Specify a custom error message or error. If you do a custom error, it's recommended to sub-class `pTimeout.TimeoutError`. Default: `'Promise timed out after 50 milliseconds'`.
@returns A decorated `input` that times out after `milliseconds` time. It has a `.clear()` method that clears the timeout.
/** @example
Timeout a promise after a specified amount of time. ```
import {setTimeout} from 'timers/promises';
import pTimeout from 'p-timeout';
If you pass in a cancelable promise, specifically a promise with a `.cancel()` method, that method will be called when the `pTimeout` promise times out. const delayedPromise = setTimeout(200);
@param input - Promise to decorate. await pTimeout(delayedPromise, 50);
@param milliseconds - Milliseconds before timing out. //=> [TimeoutError: Promise timed out after 50 milliseconds]
@param message - Specify a custom error message or error. If you do a custom error, it's recommended to sub-class `pTimeout.TimeoutError`. Default: `'Promise timed out after 50 milliseconds'`. ```
@returns A decorated `input` that times out after `milliseconds` time. It has a `.clear()` method that clears the timeout. */
export default function pTimeout<ValueType>(
@example
```
import delay = require('delay');
import pTimeout = require('p-timeout');
const delayedPromise = delay(200);
pTimeout(delayedPromise, 50).then(() => 'foo');
//=> [TimeoutError: Promise timed out after 50 milliseconds]
```
*/
<ValueType>(
input: PromiseLike<ValueType>, input: PromiseLike<ValueType>,
milliseconds: number, milliseconds: number,
message?: string | Error, message?: string | Error,
options?: pTimeout.Options options?: Options
): ClearablePromise<ValueType>; ): ClearablePromise<ValueType>;
/** /**
Timeout a promise after a specified amount of time. Timeout a promise after a specified amount of time.
If you pass in a cancelable promise, specifically a promise with a `.cancel()` method, that method will be called when the `pTimeout` promise times out. If you pass in a cancelable promise, specifically a promise with a `.cancel()` method, that method will be called when the `pTimeout` promise times out.
@param input - Promise to decorate. @param input - Promise to decorate.
@param milliseconds - Milliseconds before timing out. Passing `Infinity` will cause it to never time out. @param milliseconds - Milliseconds before timing out. Passing `Infinity` will cause it to never time out.
@param fallback - Do something other than rejecting with an error on timeout. You could for example retry. @param fallback - Do something other than rejecting with an error on timeout. You could for example retry.
@returns A decorated `input` that times out after `milliseconds` time. It has a `.clear()` method that clears the timeout. @returns A decorated `input` that times out after `milliseconds` time. It has a `.clear()` method that clears the timeout.
@example @example
``` ```
import delay = require('delay'); import {setTimeout} from 'timers/promises';
import pTimeout = require('p-timeout'); import pTimeout from 'p-timeout';
const delayedPromise = () => delay(200); const delayedPromise = () => setTimeout(200);
pTimeout(delayedPromise(), 50, () => { await pTimeout(delayedPromise(), 50, () => {
return pTimeout(delayedPromise(), 300); return pTimeout(delayedPromise(), 300);
}); });
``` ```
*/ */
<ValueType, ReturnType>( export default function pTimeout<ValueType, ReturnType>(
input: PromiseLike<ValueType>, input: PromiseLike<ValueType>,
milliseconds: number, milliseconds: number,
fallback: () => ReturnType | Promise<ReturnType>, fallback: () => ReturnType | Promise<ReturnType>,
options?: pTimeout.Options options?: Options
): ClearablePromise<ValueType | ReturnType>; ): ClearablePromise<ValueType | ReturnType>;
};
export = pTimeout;

View File

@ -1,20 +1,18 @@
'use strict'; export class TimeoutError extends Error {
class TimeoutError extends Error {
constructor(message) { constructor(message) {
super(message); super(message);
this.name = 'TimeoutError'; this.name = 'TimeoutError';
} }
} }
const pTimeout = (promise, milliseconds, fallback, options) => { export default function pTimeout(promise, milliseconds, fallback, options) {
let timer; let timer;
const cancelablePromise = new Promise((resolve, reject) => { const cancelablePromise = new Promise((resolve, reject) => {
if (typeof milliseconds !== 'number' || milliseconds < 0) { if (typeof milliseconds !== 'number' || milliseconds < 0) {
throw new TypeError('Expected `milliseconds` to be a positive number'); throw new TypeError('Expected `milliseconds` to be a positive number');
} }
if (milliseconds === Infinity) { if (milliseconds === Number.POSITIVE_INFINITY) {
resolve(promise); resolve(promise);
return; return;
} }
@ -62,10 +60,4 @@ const pTimeout = (promise, milliseconds, fallback, options) => {
}; };
return cancelablePromise; return cancelablePromise;
}; }
module.exports = pTimeout;
// TODO: Remove this for the next major release
module.exports.default = pTimeout;
module.exports.TimeoutError = TimeoutError;

View File

@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-floating-promises */
import {expectType, expectError} from 'tsd'; import {expectType, expectError} from 'tsd';
import pTimeout = require('.'); import pTimeout, {TimeoutError} from './index.js';
import {TimeoutError} from '.';
const delayedPromise: () => Promise<string> = async () => { const delayedPromise: () => Promise<string> = async () => {
return new Promise(resolve => { return new Promise(resolve => {
@ -11,7 +11,7 @@ const delayedPromise: () => Promise<string> = async () => {
}; };
pTimeout(delayedPromise(), 50).then(() => 'foo'); pTimeout(delayedPromise(), 50).then(() => 'foo');
pTimeout(delayedPromise(), 50, () => { pTimeout(delayedPromise(), 50, async () => {
return pTimeout(delayedPromise(), 300); return pTimeout(delayedPromise(), 300);
}); });
pTimeout(delayedPromise(), 50).then(value => expectType<string>(value)); pTimeout(delayedPromise(), 50).then(value => expectType<string>(value));

View File

@ -4,13 +4,16 @@
"description": "Timeout a promise after a specified amount of time", "description": "Timeout a promise after a specified amount of time",
"license": "MIT", "license": "MIT",
"repository": "sindresorhus/p-timeout", "repository": "sindresorhus/p-timeout",
"funding": "https://github.com/sponsors/sindresorhus",
"author": { "author": {
"name": "Sindre Sorhus", "name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com", "email": "sindresorhus@gmail.com",
"url": "https://sindresorhus.com" "url": "https://sindresorhus.com"
}, },
"type": "module",
"exports": "./index.js",
"engines": { "engines": {
"node": ">=10" "node": ">=12"
}, },
"scripts": { "scripts": {
"test": "xo && ava && tsd" "test": "xo && ava && tsd"
@ -33,12 +36,12 @@
"bluebird" "bluebird"
], ],
"devDependencies": { "devDependencies": {
"ava": "^2.4.0", "ava": "^3.15.0",
"delay": "^4.4.0", "delay": "^5.0.0",
"p-cancelable": "^2.0.0", "in-range": "^3.0.0",
"tsd": "^0.13.1", "p-cancelable": "^2.1.0",
"xo": "^0.35.0", "time-span": "^4.0.0",
"in-range": "^2.0.0", "tsd": "^0.14.0",
"time-span": "^4.0.0" "xo": "^0.38.2"
} }
} }

View File

@ -11,12 +11,12 @@ $ npm install p-timeout
## Usage ## Usage
```js ```js
const delay = require('delay'); import {setTimeout} from 'timers/promises';
const pTimeout = require('p-timeout'); import pTimeout from 'p-timeout';
const delayedPromise = delay(200); const delayedPromise = setTimeout(200);
pTimeout(delayedPromise, 50).then(() => 'foo'); await pTimeout(delayedPromise, 50);
//=> [TimeoutError: Promise timed out after 50 milliseconds] //=> [TimeoutError: Promise timed out after 50 milliseconds]
``` ```
@ -61,12 +61,12 @@ Do something other than rejecting with an error on timeout.
You could for example retry: You could for example retry:
```js ```js
const delay = require('delay'); import {setTimeout} from 'timers/promises';
const pTimeout = require('p-timeout'); import pTimeout from 'p-timeout';
const delayedPromise = () => delay(200); const delayedPromise = () => setTimeout(200);
pTimeout(delayedPromise(), 50, () => { await pTimeout(delayedPromise(), 50, () => {
return pTimeout(delayedPromise(), 300); return pTimeout(delayedPromise(), 300);
}); });
``` ```
@ -86,23 +86,21 @@ Useful for testing purposes, in particular to work around [`sinon.useFakeTimers(
Example: Example:
```js ```js
const pTimeout = require('p-timeout'); import {setTimeout} from 'timers/promises';
const sinon = require('sinon'); import pTimeout from 'p-timeout';
(async () => { const originalSetTimeout = setTimeout;
const originalSetTimeout = setTimeout; const originalClearTimeout = clearTimeout;
const originalClearTimeout = clearTimeout;
sinon.useFakeTimers(); sinon.useFakeTimers();
// Use `pTimeout` without being affected by `sinon.useFakeTimers()`: // Use `pTimeout` without being affected by `sinon.useFakeTimers()`:
await pTimeout(doSomething(), 2000, undefined, { await pTimeout(doSomething(), 2000, undefined, {
customTimers: { customTimers: {
setTimeout: originalSetTimeout, setTimeout: originalSetTimeout,
clearTimeout: originalClearTimeout clearTimeout: originalClearTimeout
} }
}); });
})();
``` ```
### pTimeout.TimeoutError ### pTimeout.TimeoutError

22
test.js
View File

@ -3,7 +3,7 @@ import delay from 'delay';
import PCancelable from 'p-cancelable'; import PCancelable from 'p-cancelable';
import inRange from 'in-range'; import inRange from 'in-range';
import timeSpan from 'time-span'; import timeSpan from 'time-span';
import pTimeout from '.'; import pTimeout, {TimeoutError} from './index.js';
const fixture = Symbol('fixture'); const fixture = Symbol('fixture');
const fixtureError = new Error('fixture'); const fixtureError = new Error('fixture');
@ -13,35 +13,35 @@ test('resolves before timeout', async t => {
}); });
test('throws when milliseconds is not number', async t => { test('throws when milliseconds is not number', async t => {
await t.throwsAsync(pTimeout(delay(50), '200'), TypeError); await t.throwsAsync(pTimeout(delay(50), '200'), {instanceOf: TypeError});
}); });
test('throws when milliseconds is negative number', async t => { test('throws when milliseconds is negative number', async t => {
await t.throwsAsync(pTimeout(delay(50), -1), TypeError); await t.throwsAsync(pTimeout(delay(50), -1), {instanceOf: TypeError});
}); });
test('handles milliseconds being `Infinity`', async t => { test('handles milliseconds being `Infinity`', async t => {
t.is( t.is(
await pTimeout(delay(50, {value: fixture}), Infinity), await pTimeout(delay(50, {value: fixture}), Number.POSITIVE_INFINITY),
fixture fixture
); );
}); });
test('rejects after timeout', async t => { test('rejects after timeout', async t => {
await t.throwsAsync(pTimeout(delay(200), 50), pTimeout.TimeoutError); await t.throwsAsync(pTimeout(delay(200), 50), {instanceOf: TimeoutError});
}); });
test('rejects before timeout if specified promise rejects', async t => { test('rejects before timeout if specified promise rejects', async t => {
await t.throwsAsync(pTimeout(delay(50).then(() => Promise.reject(fixtureError)), 200), fixtureError.message); await t.throwsAsync(pTimeout(delay(50).then(() => Promise.reject(fixtureError)), 200), {message: fixtureError.message});
}); });
test('fallback argument', async t => { test('fallback argument', async t => {
await t.throwsAsync(pTimeout(delay(200), 50, 'rainbow'), 'rainbow'); await t.throwsAsync(pTimeout(delay(200), 50, 'rainbow'), {message: 'rainbow'});
await t.throwsAsync(pTimeout(delay(200), 50, new RangeError('cake')), RangeError); await t.throwsAsync(pTimeout(delay(200), 50, new RangeError('cake')), {instanceOf: RangeError});
await t.throwsAsync(pTimeout(delay(200), 50, () => Promise.reject(fixtureError)), fixtureError.message); await t.throwsAsync(pTimeout(delay(200), 50, () => Promise.reject(fixtureError)), {message: fixtureError.message});
await t.throwsAsync(pTimeout(delay(200), 50, () => { await t.throwsAsync(pTimeout(delay(200), 50, () => {
throw new RangeError('cake'); throw new RangeError('cake');
}), RangeError); }), {instanceOf: RangeError});
}); });
test('calls `.cancel()` on promise when it exists', async t => { test('calls `.cancel()` on promise when it exists', async t => {
@ -54,7 +54,7 @@ test('calls `.cancel()` on promise when it exists', async t => {
resolve(); resolve();
}); });
await t.throwsAsync(pTimeout(promise, 50), pTimeout.TimeoutError); await t.throwsAsync(pTimeout(promise, 50), {instanceOf: TimeoutError});
t.true(promise.isCanceled); t.true(promise.isCanceled);
}); });