From 68dfe953e58bbf55332a879aa01669d56bd93ffa Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Thu, 7 Dec 2023 13:39:02 +0100 Subject: [PATCH] Require Node.js 18 --- .github/funding.yml | 2 -- .github/workflows/main.yml | 4 ++-- bench.ts | 8 ++++---- package.json | 38 +++++++++++++++++++++----------------- readme.md | 14 ++++---------- source/index.ts | 29 +++++++++-------------------- source/options.ts | 18 +++++++++--------- source/priority-queue.ts | 8 ++++---- source/queue.ts | 4 ++-- test/test.ts | 6 +++--- 10 files changed, 58 insertions(+), 73 deletions(-) delete mode 100644 .github/funding.yml diff --git a/.github/funding.yml b/.github/funding.yml deleted file mode 100644 index b261ad9..0000000 --- a/.github/funding.yml +++ /dev/null @@ -1,2 +0,0 @@ -github: sindresorhus -tidelift: npm/p-queue diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 441975c..5f816e2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -12,8 +12,8 @@ jobs: node-version: - 16 steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - run: npm install diff --git a/bench.ts b/bench.ts index bcdd2b2..0d1e5f4 100644 --- a/bench.ts +++ b/bench.ts @@ -1,4 +1,4 @@ -import Benchmark, {Deferred, Event} from 'benchmark'; +import Benchmark, {type Deferred, type Event} from 'benchmark'; import PQueue from './source/index.js'; const suite = new Benchmark.Suite(); @@ -10,7 +10,7 @@ suite .add('baseline', { defer: true, - fn: async (deferred: Resolvable) => { + async fn(deferred: Resolvable) { const queue = new PQueue(); for (let i = 0; i < 100; i++) { @@ -25,7 +25,7 @@ suite .add('operation with random priority', { defer: true, - fn: async (deferred: Resolvable) => { + async fn(deferred: Resolvable) { const queue = new PQueue(); for (let i = 0; i < 100; i++) { @@ -42,7 +42,7 @@ suite .add('operation with increasing priority', { defer: true, - fn: async (deferred: Resolvable) => { + async fn(deferred: Resolvable) { const queue = new PQueue(); for (let i = 0; i < 100; i++) { diff --git a/package.json b/package.json index 8367745..32c0e8b 100644 --- a/package.json +++ b/package.json @@ -6,15 +6,18 @@ "repository": "sindresorhus/p-queue", "funding": "https://github.com/sponsors/sindresorhus", "type": "module", - "exports": "./dist/index.js", + "exports": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + }, + "sideEffects": false, "engines": { - "node": ">=12" + "node": ">=18" }, "scripts": { "build": "del-cli dist && tsc", - "//test": "xo && ava && del-cli dist && tsc && tsd", - "test": "ava && del-cli dist && tsc && tsd", - "bench": "node --loader=ts-node/esm bench.ts", + "test": "xo && ava && del-cli dist && tsc && tsd", + "bench": "node --import=tsx/esm bench.ts", "prepublishOnly": "del-cli dist && tsc" }, "files": [ @@ -45,26 +48,27 @@ ], "dependencies": { "eventemitter3": "^5.0.1", - "p-timeout": "^5.0.2" + "p-timeout": "^6.1.2" }, "devDependencies": { - "@sindresorhus/tsconfig": "^2.0.0", - "@types/benchmark": "^2.1.1", - "@types/node": "^17.0.13", + "@sindresorhus/tsconfig": "^5.0.0", + "@types/benchmark": "^2.1.5", + "@types/node": "^20.10.4", "ava": "^5.3.1", "benchmark": "^2.1.4", - "del-cli": "^5.0.0", - "delay": "^5.0.0", + "del-cli": "^5.1.0", + "delay": "^6.0.0", "in-range": "^3.0.0", "p-defer": "^4.0.0", "random-int": "^3.0.0", - "time-span": "^5.0.0", - "ts-node": "^10.9.1", - "tsd": "^0.25.0", - "typescript": "^5.2.2", - "xo": "^0.52.0" + "time-span": "^5.1.0", + "tsd": "^0.29.0", + "tsx": "^4.6.2", + "typescript": "^5.3.3", + "xo": "^0.56.0" }, "ava": { + "workerThreads": false, "files": [ "test/**" ], @@ -72,7 +76,7 @@ "ts": "module" }, "nodeArguments": [ - "--loader=ts-node/esm" + "--import=tsx/esm" ] }, "xo": { diff --git a/readme.md b/readme.md index 46dc970..bf148e1 100644 --- a/readme.md +++ b/readme.md @@ -14,7 +14,7 @@ Note that the project is feature complete. We are happy to review pull requests, npm install p-queue ``` -**Warning:** This package is native [ESM](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) and no longer provides a CommonJS export. If your project uses CommonJS, you'll have to [convert to ESM](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c) or use the [dynamic `import()`](https://v8.dev/features/dynamic-import) function. Please don't open issues for questions regarding CommonJS / ESM. +**Warning:** This package is native [ESM](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) and no longer provides a CommonJS export. If your project uses CommonJS, you'll have to [convert to ESM](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c). Please don't open issues for questions regarding CommonJS / ESM. ## Usage @@ -139,12 +139,10 @@ Priority of operation. Operations with greater priority will be scheduled first. ##### signal -*Requires Node.js 16 or later.* - -[`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) for cancellation of the operation. When aborted, it will be removed from the queue and the `queue.add()` call will reject with an `AbortError`. If the operation is already running, the signal will need to be handled by the operation itself. +[`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) for cancellation of the operation. When aborted, it will be removed from the queue and the `queue.add()` call will reject with an [error](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/reason). If the operation is already running, the signal will need to be handled by the operation itself. ```js -import PQueue, {AbortError} from 'p-queue'; +import PQueue from 'p-queue'; import got, {CancelError} from 'got'; const queue = new PQueue(); @@ -168,7 +166,7 @@ try { } }, {signal: controller.signal}); } catch (error) { - if (!(error instanceof AbortError)) { + if (!(error instanceof DOMException)) { throw error; } } @@ -378,10 +376,6 @@ await queue.add(() => delay(600)); //=> 'Task is completed. Size: 0 Pending: 0' ``` -### AbortError - -The error thrown by `queue.add()` when a job is aborted before it is run. See [`signal`](#signal). - ## Advanced example A more advanced example to help you understand the flow. diff --git a/source/index.ts b/source/index.ts index 48a9455..faf2c9e 100644 --- a/source/index.ts +++ b/source/index.ts @@ -1,24 +1,19 @@ import {EventEmitter} from 'eventemitter3'; import pTimeout, {TimeoutError} from 'p-timeout'; -import {Queue, RunFunction} from './queue.js'; +import {type Queue, type RunFunction} from './queue.js'; import PriorityQueue from './priority-queue.js'; -import {QueueAddOptions, Options, TaskOptions} from './options.js'; +import {type QueueAddOptions, type Options, type TaskOptions} from './options.js'; type Task = | ((options: TaskOptions) => PromiseLike) | ((options: TaskOptions) => TaskResultType); -/** -The error thrown by `queue.add()` when a job is aborted before it is run. See `signal`. -*/ -export class AbortError extends Error {} - type EventName = 'active' | 'idle' | 'empty' | 'add' | 'next' | 'completed' | 'error'; /** Promise queue with concurrency control. */ -export default class PQueue = PriorityQueue, EnqueueOptionsType extends QueueAddOptions = QueueAddOptions> extends EventEmitter { +export default class PQueue = PriorityQueue, EnqueueOptionsType extends QueueAddOptions = QueueAddOptions> extends EventEmitter { // eslint-disable-line @typescript-eslint/naming-convention, unicorn/prefer-event-target readonly #carryoverConcurrencyCount: boolean; readonly #isIntervalIgnored: boolean; @@ -228,9 +223,7 @@ export default class PQueue { return new Promise((_resolve, reject) => { signal.addEventListener('abort', () => { - // TODO: Reject with signal.throwIfAborted() when targeting Node.js 18 - // TODO: Use ABORT_ERR code when targeting Node.js 16 (https://nodejs.org/docs/latest-v16.x/api/errors.html#abort_err) - reject(new AbortError('The task was aborted.')); + reject(signal.reason); }, {once: true}); }); } @@ -253,16 +246,12 @@ export default class PQueue( functions: ReadonlyArray>, options?: {throwOnTimeout: true} & Partial>, - ): Promise + ): Promise; async addAll( functions: ReadonlyArray>, options?: Partial, @@ -430,5 +419,5 @@ export default class PQueue, QueueOptions extends QueueAddOptions> extends TimeoutOptions { +export type Options, QueueOptions extends QueueAddOptions> = { /** Concurrency limit. @@ -60,18 +60,18 @@ export interface Options, Que @default false */ readonly carryoverConcurrencyCount?: boolean; -} +} & TimeoutOptions; -export interface QueueAddOptions extends TaskOptions, TimeoutOptions { +export type QueueAddOptions = { /** Priority of operation. Operations with greater priority will be scheduled first. @default 0 */ readonly priority?: number; -} +} & TaskOptions & TimeoutOptions; -export interface TaskOptions { +export type TaskOptions = { /** [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) for cancellation of the operation. When aborted, it will be removed from the queue and the `queue.add()` call will reject with an `AbortError`. If the operation is already running, the signal will need to be handled by the operation itself. @@ -108,4 +108,4 @@ export interface TaskOptions { ``` */ readonly signal?: AbortSignal; -} +}; diff --git a/source/priority-queue.ts b/source/priority-queue.ts index 45993bc..e161610 100644 --- a/source/priority-queue.ts +++ b/source/priority-queue.ts @@ -1,10 +1,10 @@ -import {Queue, RunFunction} from './queue.js'; +import {type Queue, type RunFunction} from './queue.js'; import lowerBound from './lower-bound.js'; -import {QueueAddOptions} from './options.js'; +import {type QueueAddOptions} from './options.js'; -export interface PriorityQueueOptions extends QueueAddOptions { +export type PriorityQueueOptions = { priority?: number; -} +} & QueueAddOptions; export default class PriorityQueue implements Queue { readonly #queue: Array = []; diff --git a/source/queue.ts b/source/queue.ts index 07dc1ae..bdf30d0 100644 --- a/source/queue.ts +++ b/source/queue.ts @@ -1,8 +1,8 @@ export type RunFunction = () => Promise; -export interface Queue { +export type Queue = { size: number; filter: (options: Partial) => Element[]; dequeue: () => Element | undefined; enqueue: (run: Element, options?: Partial) => void; -} +}; diff --git a/test/test.ts b/test/test.ts index cb44832..d511eae 100644 --- a/test/test.ts +++ b/test/test.ts @@ -1103,7 +1103,7 @@ test('should skip an aborted job', async t => { controller.abort(); // eslint-disable-next-line @typescript-eslint/no-empty-function await t.throwsAsync(queue.add(() => {}, {signal: controller.signal}), { - instanceOf: AbortError, + instanceOf: DOMException, }); }); @@ -1130,7 +1130,7 @@ test('aborting multiple jobs at the same time', async t => { controller2.abort(); }, 0); - await t.throwsAsync(task1, {instanceOf: AbortError}); - await t.throwsAsync(task2, {instanceOf: AbortError}); + await t.throwsAsync(task1, {instanceOf: DOMException}); + await t.throwsAsync(task2, {instanceOf: DOMException}); t.like(queue, {size: 0, pending: 0}); });