From 8c7325a4c59c4ecd1edbc196a36450655821776f Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sun, 28 Mar 2021 16:13:13 +0700 Subject: [PATCH] Require Node.js 12 and move to ESM Closes #132 Closes #127 --- .github/workflows/main.yml | 1 - bench.ts | 6 +-- package.json | 40 +++++++-------- readme.md | 30 ++++++----- source/index.ts | 10 ++-- source/lower-bound.ts | 2 +- source/options.ts | 2 +- source/priority-queue.ts | 10 ++-- test/test.ts | 101 +++++++++++++++++++++---------------- tsconfig.json | 5 +- 10 files changed, 109 insertions(+), 98 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c1870cf..41fe626 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -12,7 +12,6 @@ jobs: node-version: - 14 - 12 - - 10 steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v1 diff --git a/bench.ts b/bench.ts index 0d47ddd..4abc3d8 100644 --- a/bench.ts +++ b/bench.ts @@ -1,6 +1,5 @@ -import Benchmark = require('benchmark'); -import {Deferred, Event} from 'benchmark'; -import PQueue from './source'; +import Benchmark, {Deferred, Event} from 'benchmark'; +import PQueue from './source/index.js'; const suite = new Benchmark.Suite(); @@ -54,7 +53,6 @@ suite } await queue.onEmpty(); - // @ts-expect-error benchmark typings incorrect deferred.resolve(); } }) diff --git a/package.json b/package.json index 2745536..9872b7e 100644 --- a/package.json +++ b/package.json @@ -5,14 +5,15 @@ "license": "MIT", "repository": "sindresorhus/p-queue", "funding": "https://github.com/sponsors/sindresorhus", - "main": "dist/index.js", + "type": "module", + "exports": "./dist/index.js", "engines": { - "node": ">=10" + "node": ">=12" }, "scripts": { "build": "del dist && tsc", "test": "xo && npm run build && nyc ava", - "bench": "ts-node bench.ts", + "bench": "node --loader=ts-node/esm bench.ts", "prepublishOnly": "npm run build" }, "files": [ @@ -46,41 +47,40 @@ "p-timeout": "^4.1.0" }, "devDependencies": { - "@sindresorhus/tsconfig": "^0.7.0", + "@sindresorhus/tsconfig": "^1.0.0", "@types/benchmark": "^2.1.0", - "@types/node": "^14.14.19", - "ava": "^2.4.0", + "@types/node": "^14.14.37", + "ava": "^3.15.0", "benchmark": "^2.1.4", "codecov": "^3.8.1", "del-cli": "^3.0.1", - "delay": "^4.4.0", - "in-range": "^2.0.0", + "delay": "^5.0.0", + "in-range": "^3.0.0", "nyc": "^15.1.0", "random-int": "^2.0.1", "time-span": "^4.0.0", "ts-node": "^9.1.1", - "typescript": "^4.1.3", - "xo": "^0.37.1" + "typescript": "^4.2.3", + "xo": "^0.38.2" }, "ava": { - "babel": false, - "compileEnhancements": false, - "extensions": [ - "ts" - ], - "require": [ - "ts-node/register" - ], "files": [ "test/**" + ], + "extensions": { + "ts": "module" + }, + "nonSemVerExperiments": { + "configurableModuleFormat": true + }, + "nodeArguments": [ + "--loader=ts-node/esm" ] }, "xo": { "rules": { "@typescript-eslint/member-ordering": "off", - "node/no-unsupported-features/es-syntax": "off", "@typescript-eslint/no-floating-promises": "off", - "import/no-named-default": "off", "@typescript-eslint/no-invalid-void-type": "off" } }, diff --git a/readme.md b/readme.md index edb6547..142851f 100644 --- a/readme.md +++ b/readme.md @@ -15,8 +15,8 @@ $ npm install p-queue Here we run only one promise at the time. For example, set `concurrency` to 4 to run four promises at the same time. ```js -const {default: PQueue} = require('p-queue'); -const got = require('got'); +import PQueue from 'p-queue'; +import got from 'got'; const queue = new PQueue({concurrency: 1}); @@ -170,6 +170,8 @@ Size of the queue, filtered by the given options. For example, this can be used to find the number of items remaining in the queue with a specific priority level. ```js +import PQueue from 'p-queue'; + const queue = new PQueue(); queue.add(async () => '🦄', {priority: 1}); @@ -202,8 +204,8 @@ Whether the queue is currently paused. Emitted as each item is processed in the queue for the purpose of tracking progress. ```js -const delay = require('delay'); -const {default: PQueue} = require('p-queue'); +import delay from 'delay'; +import PQueue from 'p-queue'; const queue = new PQueue({concurrency: 2}); @@ -218,13 +220,14 @@ queue.add(() => Promise.resolve()); queue.add(() => Promise.resolve()); queue.add(() => delay(500)); ``` + #### idle Emitted every time the queue becomes empty and all promises have completed; `queue.size === 0 && queue.pending === 0`. ```js -const delay = require('delay'); -const {default: PQueue} = require('p-queue'); +import delay from 'delay'; +import PQueue from 'p-queue'; const queue = new PQueue(); @@ -254,14 +257,15 @@ Emitted every time the add method is called and the number of pending or queued Emitted every time a task is completed and the number of pending or queued tasks is decreased. ```js -const delay = require('delay'); -const {default: PQueue} = require('p-queue'); +import delay from 'delay'; +import PQueue from 'p-queue'; const queue = new PQueue(); queue.on('add', () => { console.log(`Task is added. Size: ${queue.size} Pending: ${queue.pending}`); }); + queue.on('next', () => { console.log(`Task is completed. Size: ${queue.size} Pending: ${queue.pending}`); }); @@ -284,8 +288,8 @@ await queue.add(() => delay(600)); A more advanced example to help you understand the flow. ```js -const delay = require('delay'); -const {default: PQueue} = require('p-queue'); +import delay from 'delay'; +import PQueue from 'p-queue'; const queue = new PQueue({concurrency: 1}); @@ -354,6 +358,8 @@ $ node example.js For implementing more complex scheduling policies, you can provide a QueueClass in the options: ```js +import PQueue from 'p-queue'; + class QueueClass { constructor() { this._queue = []; @@ -376,9 +382,7 @@ class QueueClass { } } -const queue = new PQueue({ - queueClass: QueueClass -}); +const queue = new PQueue({queueClass: QueueClass}); ``` `p-queue` will call corresponding methods to put and get operations from this queue. diff --git a/source/index.ts b/source/index.ts index c32dd17..4818c8a 100644 --- a/source/index.ts +++ b/source/index.ts @@ -1,8 +1,8 @@ -import EventEmitter = require('eventemitter3'); -import {default as pTimeout, TimeoutError} from 'p-timeout'; -import {Queue, RunFunction} from './queue'; -import PriorityQueue from './priority-queue'; -import {QueueAddOptions, DefaultAddOptions, Options} from './options'; +import EventEmitter from 'eventemitter3'; +import pTimeout, {TimeoutError} from 'p-timeout'; +import {Queue, RunFunction} from './queue.js'; +import PriorityQueue from './priority-queue.js'; +import {QueueAddOptions, DefaultAddOptions, Options} from './options.js'; type ResolveFunction = (value?: T | PromiseLike) => void; diff --git a/source/lower-bound.ts b/source/lower-bound.ts index 2100d67..5f0c927 100644 --- a/source/lower-bound.ts +++ b/source/lower-bound.ts @@ -8,7 +8,7 @@ export default function lowerBound(array: readonly T[], value: T, comparator: const step = Math.trunc(count / 2); let it = first + step; - if (comparator(array[it], value) <= 0) { + if (comparator(array[it]!, value) <= 0) { first = ++it; count -= step + 1; } else { diff --git a/source/options.ts b/source/options.ts index 4a134d7..82fd7b1 100644 --- a/source/options.ts +++ b/source/options.ts @@ -1,4 +1,4 @@ -import {Queue, RunFunction} from './queue'; +import {Queue, RunFunction} from './queue.js'; export type QueueAddOptions = Readonly>; diff --git a/source/priority-queue.ts b/source/priority-queue.ts index 331c936..31a037d 100644 --- a/source/priority-queue.ts +++ b/source/priority-queue.ts @@ -1,6 +1,6 @@ -import {Queue, RunFunction} from './queue'; -import lowerBound from './lower-bound'; -import {QueueAddOptions} from './options'; +import {Queue, RunFunction} from './queue.js'; +import lowerBound from './lower-bound.js'; +import {QueueAddOptions} from './options.js'; export interface PriorityQueueOptions extends QueueAddOptions { priority?: number; @@ -20,7 +20,7 @@ export default class PriorityQueue implements Queue= options.priority!) { + if (this.size && this._queue[this.size - 1]?.priority! >= options.priority!) { this._queue.push(element); return; } @@ -40,7 +40,7 @@ export default class PriorityQueue implements Queue>): RunFunction[] { return this._queue.filter( (element: Readonly) => element.priority === options.priority - ).map((element: Readonly<{ run: RunFunction }>) => element.run); + ).map((element: Readonly<{run: RunFunction}>) => element.run); } get size(): number { diff --git a/test/test.ts b/test/test.ts index eeba6a2..f7f2d58 100644 --- a/test/test.ts +++ b/test/test.ts @@ -1,11 +1,11 @@ /* eslint-disable no-new */ -import EventEmitter = require('eventemitter3'); +import EventEmitter from 'eventemitter3'; import test from 'ava'; import delay from 'delay'; -import inRange = require('in-range'); -import timeSpan = require('time-span'); -import randomInt = require('random-int'); -import PQueue from '../source'; +import inRange from 'in-range'; +import timeSpan from 'time-span'; +import randomInt from 'random-int'; +import PQueue from '../source/index.js'; const fixture = Symbol('fixture'); @@ -42,9 +42,9 @@ test('.add() - concurrency: 1', async t => { const end = timeSpan(); const queue = new PQueue({concurrency: 1}); - const mapper = async ([value, ms]: readonly number[]): Promise => queue.add(async () => { - await delay(ms); - return value; + const mapper = async ([value, ms]: readonly number[]) => queue.add(async () => { + await delay(ms!); + return value!; }); // eslint-disable-next-line unicorn/no-array-callback-reference @@ -57,7 +57,7 @@ test('.add() - concurrency: 5', async t => { const queue = new PQueue({concurrency}); let running = 0; - const input = new Array(100).fill(0).map(async () => queue.add(async () => { + const input = Array.from({length: 100}).fill(0).map(async () => queue.add(async () => { running++; t.true(running <= concurrency); t.true(queue.pending <= concurrency); @@ -73,7 +73,7 @@ test('.add() - update concurrency', async t => { const queue = new PQueue({concurrency}); let running = 0; - const input = new Array(100).fill(0).map(async (_value, index) => queue.add(async () => { + const input = Array.from({length: 100}).fill(0).map(async (_value, index) => queue.add(async () => { running++; t.true(running <= concurrency); @@ -263,14 +263,14 @@ test('enforce number in options.concurrency', t => { () => { new PQueue({concurrency: 0}); }, - TypeError + {instanceOf: TypeError} ); t.throws( () => { new PQueue({concurrency: undefined}); }, - TypeError + {instanceOf: TypeError} ); t.notThrows(() => { @@ -291,7 +291,7 @@ test('enforce number in queue.concurrency', t => { () => { (new PQueue()).concurrency = 0; }, - TypeError + {instanceOf: TypeError} ); t.throws( @@ -299,7 +299,7 @@ test('enforce number in queue.concurrency', t => { // @ts-expect-error (new PQueue()).concurrency = undefined; }, - TypeError + {instanceOf: TypeError} ); t.notThrows(() => { @@ -320,14 +320,14 @@ test('enforce number in options.intervalCap', t => { () => { new PQueue({intervalCap: 0}); }, - TypeError + {instanceOf: TypeError} ); t.throws( () => { new PQueue({intervalCap: undefined}); }, - TypeError + {instanceOf: TypeError} ); t.notThrows(() => { @@ -348,14 +348,14 @@ test('enforce finite in options.interval', t => { () => { new PQueue({interval: -1}); }, - TypeError + {instanceOf: TypeError} ); t.throws( () => { new PQueue({interval: undefined}); }, - TypeError + {instanceOf: TypeError} ); t.throws(() => { @@ -474,7 +474,7 @@ test.failing('.add() - handle task throwing error', async t => { throw new Error('broken'); } ), - 'broken' + {message: 'broken'} ); queue.add(() => 'sync 2'); @@ -492,7 +492,7 @@ test('.add() - handle task promise failure', async t => { throw new Error('broken'); } ), - 'broken' + {message: 'broken'} ); queue.add(() => 'task #1'); @@ -576,10 +576,12 @@ test('.add() - throttled, carryoverConcurrencyCount false', async t => { }); const values = [0, 1]; - values.forEach(async value => queue.add(async () => { - await delay(600); - result.push(value); - })); + for (const value of values) { + queue.add(async () => { + await delay(600); + result.push(value); + }); + } queue.start(); @@ -610,10 +612,12 @@ test('.add() - throttled, carryoverConcurrencyCount true', async t => { }); const values = [0, 1]; - values.forEach(async value => queue.add(async () => { - await delay(600); - result.push(value); - })); + for (const value of values) { + queue.add(async () => { + await delay(600); + result.push(value); + }); + } queue.start(); @@ -641,7 +645,7 @@ test('.add() - throttled, carryoverConcurrencyCount true', async t => { })(); await delay(1650); - t.deepEqual(result, [0, 1]); + t.deepEqual(result, values); }); test('.add() - throttled 10, concurrency 5', async t => { @@ -654,13 +658,16 @@ test('.add() - throttled 10, concurrency 5', async t => { autoStart: false }); - const firstValue = [...new Array(5).keys()]; - const secondValue = [...new Array(10).keys()]; - const thirdValue = [...new Array(13).keys()]; - thirdValue.forEach(async value => queue.add(async () => { - await delay(300); - result.push(value); - })); + const firstValue = [...Array.from({length: 5}).keys()]; + const secondValue = [...Array.from({length: 10}).keys()]; + const thirdValue = [...Array.from({length: 13}).keys()]; + + for (const value of thirdValue) { + queue.add(async () => { + await delay(300); + result.push(value); + }); + } queue.start(); @@ -700,10 +707,13 @@ test('.add() - throttled finish and resume', async t => { const values = [0, 1]; const firstValue = [0, 1]; const secondValue = [0, 1, 2]; - values.forEach(async value => queue.add(async () => { - await delay(100); - result.push(value); - })); + + for (const value of values) { + queue.add(async () => { + await delay(100); + result.push(value); + }); + } queue.start(); @@ -739,10 +749,13 @@ test('pause should work when throttled', async t => { const values = [0, 1, 2, 3]; const firstValue = [0, 1]; const secondValue = [0, 1, 2, 3]; - values.forEach(async value => queue.add(async () => { - await delay(100); - result.push(value); - })); + + for (const value of values) { + queue.add(async () => { + await delay(100); + result.push(value); + }); + } queue.start(); diff --git a/tsconfig.json b/tsconfig.json index 0626141..19f10b8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,10 +2,7 @@ "extends": "@sindresorhus/tsconfig", "compilerOptions": { "outDir": "dist", - "target": "es2017", - "lib": [ - "es2017" - ] + "noPropertyAccessFromIndexSignature": false }, "include": [ "source"