Require Node.js 14

Fixes #27
This commit is contained in:
Sindre Sorhus 2022-07-25 18:24:32 +02:00
parent d7920cae0a
commit eb1730ba0c
7 changed files with 54 additions and 50 deletions

View File

@ -10,11 +10,12 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
node-version: node-version:
- 18
- 16
- 14 - 14
- 12
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- uses: actions/setup-node@v1 - uses: actions/setup-node@v3
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
- run: npm install - run: npm install

4
index.d.ts vendored
View File

@ -25,7 +25,7 @@ export type Options<ReturnType> = {
@example @example
``` ```
import {setTimeout} from 'timers/promises'; import {setTimeout} from 'node:timers/promises';
import pTimeout from 'p-timeout'; import pTimeout from 'p-timeout';
const delayedPromise = () => setTimeout(200); const delayedPromise = () => setTimeout(200);
@ -116,7 +116,7 @@ If you pass in a cancelable promise, specifically a promise with a `.cancel()` m
@example @example
``` ```
import {setTimeout} from 'timers/promises'; import {setTimeout} from 'node:timers/promises';
import pTimeout from 'p-timeout'; import pTimeout from 'p-timeout';
const delayedPromise = () => setTimeout(200); const delayedPromise = () => setTimeout(200);

View File

@ -20,27 +20,32 @@ export class AbortError extends Error {
/** /**
TODO: Remove AbortError and just throw DOMException when targeting Node 18. TODO: Remove AbortError and just throw DOMException when targeting Node 18.
*/ */
const getDOMException = errorMessage => globalThis.DOMException === undefined ? const getDOMException = errorMessage => globalThis.DOMException === undefined
new AbortError(errorMessage) : ? new AbortError(errorMessage)
new DOMException(errorMessage); : new DOMException(errorMessage);
/** /**
TODO: Remove below function and just 'reject(signal.reason)' when targeting Node 18. TODO: Remove below function and just 'reject(signal.reason)' when targeting Node 18.
*/ */
const getAbortedReason = signal => { const getAbortedReason = signal => {
const reason = signal.reason === undefined ? const reason = signal.reason === undefined
getDOMException('This operation was aborted.') : ? getDOMException('This operation was aborted.')
signal.reason; : signal.reason;
return reason instanceof Error ? reason : getDOMException(reason); return reason instanceof Error ? reason : getDOMException(reason);
}; };
export default function pTimeout(promise, options) { export default function pTimeout(promise, options) {
const {
milliseconds,
fallback,
message,
customTimers = {setTimeout, clearTimeout},
} = options;
let timer; let timer;
const cancelablePromise = new Promise((resolve, reject) => { const cancelablePromise = new Promise((resolve, reject) => {
const {milliseconds, fallback, message} = options;
if (typeof milliseconds !== 'number' || Math.sign(milliseconds) !== 1) { if (typeof milliseconds !== 'number' || Math.sign(milliseconds) !== 1) {
throw new TypeError(`Expected \`milliseconds\` to be a positive number, got \`${milliseconds}\``); throw new TypeError(`Expected \`milliseconds\` to be a positive number, got \`${milliseconds}\``);
} }
@ -50,11 +55,6 @@ export default function pTimeout(promise, options) {
return; return;
} }
options = {
customTimers: {setTimeout, clearTimeout},
...options
};
if (options.signal) { if (options.signal) {
const {signal} = options; const {signal} = options;
if (signal.aborted) { if (signal.aborted) {
@ -66,7 +66,7 @@ export default function pTimeout(promise, options) {
}); });
} }
timer = options.customTimers.setTimeout.call(undefined, () => { timer = customTimers.setTimeout.call(undefined, () => {
if (fallback) { if (fallback) {
try { try {
resolve(fallback()); resolve(fallback());
@ -93,13 +93,13 @@ export default function pTimeout(promise, options) {
} catch (error) { } catch (error) {
reject(error); reject(error);
} finally { } finally {
options.customTimers.clearTimeout.call(undefined, timer); customTimers.clearTimeout.call(undefined, timer);
} }
})(); })();
}); });
cancelablePromise.clear = () => { cancelablePromise.clear = () => {
clearTimeout(timer); customTimers.clearTimeout.call(undefined, timer);
timer = undefined; timer = undefined;
}; };

View File

@ -10,13 +10,15 @@ const delayedPromise: () => Promise<string> = async () => new Promise(resolve =>
pTimeout(delayedPromise(), {milliseconds: 50}).then(() => 'foo'); pTimeout(delayedPromise(), {milliseconds: 50}).then(() => 'foo');
pTimeout(delayedPromise(), {milliseconds: 50, fallback: async () => pTimeout(delayedPromise(), {milliseconds: 300})}); pTimeout(delayedPromise(), {milliseconds: 50, fallback: async () => pTimeout(delayedPromise(), {milliseconds: 300})});
pTimeout(delayedPromise(), {milliseconds: 50}).then(value => expectType<string>(value)); pTimeout(delayedPromise(), {milliseconds: 50}).then(value => {
pTimeout(delayedPromise(), {milliseconds: 50, message: 'error'}).then(value => expectType<string>(value);
expectType<string>(value) });
); pTimeout(delayedPromise(), {milliseconds: 50, message: 'error'}).then(value => {
pTimeout(delayedPromise(), {milliseconds: 50, message: new Error('error')}).then(value => expectType<string>(value);
expectType<string>(value) });
); pTimeout(delayedPromise(), {milliseconds: 50, message: new Error('error')}).then(value => {
expectType<string>(value);
});
pTimeout(delayedPromise(), {milliseconds: 50, fallback: async () => 10}).then(value => { pTimeout(delayedPromise(), {milliseconds: 50, fallback: async () => 10}).then(value => {
expectType<string | number>(value); expectType<string | number>(value);
}); });
@ -34,8 +36,8 @@ expectError(pTimeout(delayedPromise(), {
milliseconds: 50, milliseconds: 50,
fallback: () => 10, fallback: () => 10,
customTimers: { customTimers: {
setTimeout setTimeout,
} },
})); }));
expectError(pTimeout(delayedPromise(), { expectError(pTimeout(delayedPromise(), {
@ -43,8 +45,8 @@ expectError(pTimeout(delayedPromise(), {
fallback: () => 10, fallback: () => 10,
customTimers: { customTimers: {
setTimeout: () => 42, // Invalid `setTimeout` implementation setTimeout: () => 42, // Invalid `setTimeout` implementation
clearTimeout clearTimeout,
} },
})); }));
expectError(pTimeout(delayedPromise(), {})); // `milliseconds` is required expectError(pTimeout(delayedPromise(), {})); // `milliseconds` is required

View File

@ -12,8 +12,9 @@
}, },
"type": "module", "type": "module",
"exports": "./index.js", "exports": "./index.js",
"types": "./index.d.ts",
"engines": { "engines": {
"node": ">=12" "node": ">=14.16"
}, },
"scripts": { "scripts": {
"test": "xo && ava && tsd" "test": "xo && ava && tsd"
@ -36,12 +37,12 @@
"bluebird" "bluebird"
], ],
"devDependencies": { "devDependencies": {
"ava": "^3.15.0", "ava": "^4.3.1",
"delay": "^5.0.0", "delay": "^5.0.0",
"in-range": "^3.0.0", "in-range": "^3.0.0",
"p-cancelable": "^2.1.0", "p-cancelable": "^4.0.1",
"time-span": "^4.0.0", "time-span": "^5.1.0",
"tsd": "^0.14.0", "tsd": "^0.22.0",
"xo": "^0.38.2" "xo": "^0.51.0"
} }
} }

View File

@ -4,14 +4,14 @@
## Install ## Install
``` ```sh
$ npm install p-timeout npm install p-timeout
``` ```
## Usage ## Usage
```js ```js
import {setTimeout} from 'timers/promises'; import {setTimeout} from 'node:timers/promises';
import pTimeout from 'p-timeout'; import pTimeout from 'p-timeout';
const delayedPromise = setTimeout(200); const delayedPromise = setTimeout(200);
@ -66,7 +66,7 @@ Do something other than rejecting with an error on timeout.
You could for example retry: You could for example retry:
```js ```js
import {setTimeout} from 'timers/promises'; import {setTimeout} from 'node:timers/promises';
import pTimeout from 'p-timeout'; import pTimeout from 'p-timeout';
const delayedPromise = () => setTimeout(200); const delayedPromise = () => setTimeout(200);
@ -90,7 +90,7 @@ Useful for testing purposes, in particular to work around [`sinon.useFakeTimers(
Example: Example:
```js ```js
import {setTimeout} from 'timers/promises'; import {setTimeout} from 'node:timers/promises';
import pTimeout from 'p-timeout'; import pTimeout from 'p-timeout';
const originalSetTimeout = setTimeout; const originalSetTimeout = setTimeout;

14
test.js
View File

@ -27,7 +27,7 @@ test('throws when milliseconds is NaN', async t => {
test('handles milliseconds being `Infinity`', async t => { test('handles milliseconds being `Infinity`', async t => {
t.is( t.is(
await pTimeout(delay(50, {value: fixture}), {milliseconds: Number.POSITIVE_INFINITY}), await pTimeout(delay(50, {value: fixture}), {milliseconds: Number.POSITIVE_INFINITY}),
fixture fixture,
); );
}); });
@ -77,8 +77,8 @@ test('accepts `customTimers` option', async t => {
clearTimeout(timeoutId) { clearTimeout(timeoutId) {
t.pass(); t.pass();
return clearTimeout(timeoutId); return clearTimeout(timeoutId);
} },
} },
}); });
}); });
@ -101,13 +101,13 @@ if (globalThis.AbortController !== undefined) {
const promise = pTimeout(delay(3000), { const promise = pTimeout(delay(3000), {
milliseconds: 2000, milliseconds: 2000,
signal: abortController.signal signal: abortController.signal,
}); });
abortController.abort(); abortController.abort();
await t.throwsAsync(promise, { await t.throwsAsync(promise, {
name: 'AbortError' name: 'AbortError',
}); });
}); });
@ -118,9 +118,9 @@ if (globalThis.AbortController !== undefined) {
await t.throwsAsync(pTimeout(delay(3000), { await t.throwsAsync(pTimeout(delay(3000), {
milliseconds: 2000, milliseconds: 2000,
signal: abortController.signal signal: abortController.signal,
}), { }), {
name: 'AbortError' name: 'AbortError',
}); });
}); });
} }