Skip to content

Commit

Permalink
Require Node.js 14
Browse files Browse the repository at this point in the history
Fixes #27
  • Loading branch information
sindresorhus committed Jul 25, 2022
1 parent d7920ca commit eb1730b
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 50 deletions.
7 changes: 4 additions & 3 deletions .github/workflows/main.yml
Expand Up @@ -10,11 +10,12 @@ jobs:
fail-fast: false
matrix:
node-version:
- 18
- 16
- 14
- 12
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- run: npm install
Expand Down
4 changes: 2 additions & 2 deletions index.d.ts
Expand Up @@ -25,7 +25,7 @@ export type Options<ReturnType> = {
@example
```
import {setTimeout} from 'timers/promises';
import {setTimeout} from 'node:timers/promises';
import pTimeout from 'p-timeout';
const delayedPromise = () => setTimeout(200);
Expand Down Expand Up @@ -116,7 +116,7 @@ If you pass in a cancelable promise, specifically a promise with a `.cancel()` m
@example
```
import {setTimeout} from 'timers/promises';
import {setTimeout} from 'node:timers/promises';
import pTimeout from 'p-timeout';
const delayedPromise = () => setTimeout(200);
Expand Down
32 changes: 16 additions & 16 deletions index.js
Expand Up @@ -20,27 +20,32 @@ export class AbortError extends Error {
/**
TODO: Remove AbortError and just throw DOMException when targeting Node 18.
*/
const getDOMException = errorMessage => globalThis.DOMException === undefined ?
new AbortError(errorMessage) :
new DOMException(errorMessage);
const getDOMException = errorMessage => globalThis.DOMException === undefined
? new AbortError(errorMessage)
: new DOMException(errorMessage);

/**
TODO: Remove below function and just 'reject(signal.reason)' when targeting Node 18.
*/
const getAbortedReason = signal => {
const reason = signal.reason === undefined ?
getDOMException('This operation was aborted.') :
signal.reason;
const reason = signal.reason === undefined
? getDOMException('This operation was aborted.')
: signal.reason;

return reason instanceof Error ? reason : getDOMException(reason);
};

export default function pTimeout(promise, options) {
const {
milliseconds,
fallback,
message,
customTimers = {setTimeout, clearTimeout},
} = options;

let timer;

const cancelablePromise = new Promise((resolve, reject) => {
const {milliseconds, fallback, message} = options;

if (typeof milliseconds !== 'number' || Math.sign(milliseconds) !== 1) {
throw new TypeError(`Expected \`milliseconds\` to be a positive number, got \`${milliseconds}\``);
}
Expand All @@ -50,11 +55,6 @@ export default function pTimeout(promise, options) {
return;
}

options = {
customTimers: {setTimeout, clearTimeout},
...options
};

if (options.signal) {
const {signal} = options;
if (signal.aborted) {
Expand All @@ -66,7 +66,7 @@ export default function pTimeout(promise, options) {
});
}

timer = options.customTimers.setTimeout.call(undefined, () => {
timer = customTimers.setTimeout.call(undefined, () => {
if (fallback) {
try {
resolve(fallback());
Expand All @@ -93,13 +93,13 @@ export default function pTimeout(promise, options) {
} catch (error) {
reject(error);
} finally {
options.customTimers.clearTimeout.call(undefined, timer);
customTimers.clearTimeout.call(undefined, timer);
}
})();
});

cancelablePromise.clear = () => {
clearTimeout(timer);
customTimers.clearTimeout.call(undefined, timer);
timer = undefined;
};

Expand Down
24 changes: 13 additions & 11 deletions index.test-d.ts
Expand Up @@ -10,13 +10,15 @@ const delayedPromise: () => Promise<string> = async () => new Promise(resolve =>

pTimeout(delayedPromise(), {milliseconds: 50}).then(() => 'foo');
pTimeout(delayedPromise(), {milliseconds: 50, fallback: async () => pTimeout(delayedPromise(), {milliseconds: 300})});
pTimeout(delayedPromise(), {milliseconds: 50}).then(value => expectType<string>(value));
pTimeout(delayedPromise(), {milliseconds: 50, message: 'error'}).then(value =>
expectType<string>(value)
);
pTimeout(delayedPromise(), {milliseconds: 50, message: new Error('error')}).then(value =>
expectType<string>(value)
);
pTimeout(delayedPromise(), {milliseconds: 50}).then(value => {
expectType<string>(value);
});
pTimeout(delayedPromise(), {milliseconds: 50, message: 'error'}).then(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 => {
expectType<string | number>(value);
});
Expand All @@ -34,17 +36,17 @@ expectError(pTimeout(delayedPromise(), {
milliseconds: 50,
fallback: () => 10,
customTimers: {
setTimeout
}
setTimeout,
},
}));

expectError(pTimeout(delayedPromise(), {
milliseconds: 50,
fallback: () => 10,
customTimers: {
setTimeout: () => 42, // Invalid `setTimeout` implementation
clearTimeout
}
clearTimeout,
},
}));

expectError(pTimeout(delayedPromise(), {})); // `milliseconds` is required
Expand Down
13 changes: 7 additions & 6 deletions package.json
Expand Up @@ -12,8 +12,9 @@
},
"type": "module",
"exports": "./index.js",
"types": "./index.d.ts",
"engines": {
"node": ">=12"
"node": ">=14.16"
},
"scripts": {
"test": "xo && ava && tsd"
Expand All @@ -36,12 +37,12 @@
"bluebird"
],
"devDependencies": {
"ava": "^3.15.0",
"ava": "^4.3.1",
"delay": "^5.0.0",
"in-range": "^3.0.0",
"p-cancelable": "^2.1.0",
"time-span": "^4.0.0",
"tsd": "^0.14.0",
"xo": "^0.38.2"
"p-cancelable": "^4.0.1",
"time-span": "^5.1.0",
"tsd": "^0.22.0",
"xo": "^0.51.0"
}
}
10 changes: 5 additions & 5 deletions readme.md
Expand Up @@ -4,14 +4,14 @@
## Install

```
$ npm install p-timeout
```sh
npm install p-timeout
```

## Usage

```js
import {setTimeout} from 'timers/promises';
import {setTimeout} from 'node:timers/promises';
import pTimeout from 'p-timeout';

const delayedPromise = setTimeout(200);
Expand Down Expand Up @@ -66,7 +66,7 @@ Do something other than rejecting with an error on timeout.
You could for example retry:

```js
import {setTimeout} from 'timers/promises';
import {setTimeout} from 'node:timers/promises';
import pTimeout from 'p-timeout';

const delayedPromise = () => setTimeout(200);
Expand All @@ -90,7 +90,7 @@ Useful for testing purposes, in particular to work around [`sinon.useFakeTimers(
Example:

```js
import {setTimeout} from 'timers/promises';
import {setTimeout} from 'node:timers/promises';
import pTimeout from 'p-timeout';

const originalSetTimeout = setTimeout;
Expand Down
14 changes: 7 additions & 7 deletions test.js
Expand Up @@ -27,7 +27,7 @@ test('throws when milliseconds is NaN', async t => {
test('handles milliseconds being `Infinity`', async t => {
t.is(
await pTimeout(delay(50, {value: fixture}), {milliseconds: Number.POSITIVE_INFINITY}),
fixture
fixture,
);
});

Expand Down Expand Up @@ -77,8 +77,8 @@ test('accepts `customTimers` option', async t => {
clearTimeout(timeoutId) {
t.pass();
return clearTimeout(timeoutId);
}
}
},
},
});
});

Expand All @@ -101,13 +101,13 @@ if (globalThis.AbortController !== undefined) {

const promise = pTimeout(delay(3000), {
milliseconds: 2000,
signal: abortController.signal
signal: abortController.signal,
});

abortController.abort();

await t.throwsAsync(promise, {
name: 'AbortError'
name: 'AbortError',
});
});

Expand All @@ -118,9 +118,9 @@ if (globalThis.AbortController !== undefined) {

await t.throwsAsync(pTimeout(delay(3000), {
milliseconds: 2000,
signal: abortController.signal
signal: abortController.signal,
}), {
name: 'AbortError'
name: 'AbortError',
});
});
}

0 comments on commit eb1730b

Please sign in to comment.