From 05f1972a934cdd1613c851830f1cb6abf0135308 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Wed, 25 Aug 2021 13:52:34 +0200 Subject: [PATCH] Require Node.js 12.20 and move to ESM --- .github/workflows/main.yml | 6 ++--- index.d.ts | 46 +++++++++++++++++--------------------- index.js | 36 ++++++++++++++--------------- index.test-d.ts | 5 +++-- package.json | 18 ++++++++------- readme.md | 14 +++++------- test.js | 20 +++++++++-------- 7 files changed, 70 insertions(+), 75 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c1870cf..441975c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,12 +10,10 @@ jobs: fail-fast: false matrix: node-version: - - 14 - - 12 - - 10 + - 16 steps: - uses: actions/checkout@v2 - - uses: actions/setup-node@v1 + - uses: actions/setup-node@v2 with: node-version: ${{ matrix.node-version }} - run: npm install diff --git a/index.d.ts b/index.d.ts index 38c7e57..43b89da 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,21 +1,21 @@ -declare namespace pLocate { - interface Options { - /** - Number of concurrently pending promises returned by `tester`. Minimum: `1`. +export interface Options { + /** + The number of concurrently pending promises returned by `tester`. - @default Infinity - */ - readonly concurrency?: number; + Minimum: `1` - /** - Preserve `input` order when searching. + @default Infinity + */ + readonly concurrency?: number; - Disable this to improve performance if you don't care about the order. + /** + Preserve `input` order when searching. - @default true - */ - readonly preserveOrder?: boolean; - } + Disable this to improve performance if you don't care about the order. + + @default true + */ + readonly preserveOrder?: boolean; } /** @@ -27,8 +27,8 @@ Get the first fulfilled promise that satisfies the provided testing function. @example ``` -import pathExists = require('path-exists'); -import pLocate = require('p-locate'); +import {pathExists} from 'path-exists'; +import pLocate from 'p-locate'; const files = [ 'unicorn.png', @@ -36,18 +36,14 @@ const files = [ 'pony.png' ]; -(async () => { - const foundPath = await pLocate(files, file => pathExists(file)); +const foundPath = await pLocate(files, file => pathExists(file)); - console.log(foundPath); - //=> 'rainbow' -})(); +console.log(foundPath); +//=> 'rainbow' ``` */ -declare function pLocate( +export default function pLocate( input: Iterable | ValueType>, tester: (element: ValueType) => PromiseLike | boolean, - options?: pLocate.Options + options?: Options ): Promise; - -export = pLocate; diff --git a/index.js b/index.js index 641c3dd..5b38636 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,4 @@ -'use strict'; -const pLimit = require('p-limit'); +import pLimit from 'p-limit'; class EndError extends Error { constructor(value) { @@ -8,10 +7,10 @@ class EndError extends Error { } } -// The input can also be a promise, so we await it +// The input can also be a promise, so we await it. const testElement = async (element, tester) => tester(await element); -// The input can also be a promise, so we `Promise.all()` them both +// The input can also be a promise, so we `Promise.all()` them both. const finder = async element => { const values = await Promise.all(element); if (values[1] === true) { @@ -21,20 +20,21 @@ const finder = async element => { return false; }; -const pLocate = async (iterable, tester, options) => { - options = { - concurrency: Infinity, - preserveOrder: true, - ...options - }; - - const limit = pLimit(options.concurrency); - - // Start all the promises concurrently with optional limit +export default async function pLocate( + iterable, + tester, + { + concurrency = Number.POSITIVE_INFINITY, + preserveOrder = true, + } = {}, +) { + const limit = pLimit(concurrency); + + // Start all the promises concurrently with optional limit. const items = [...iterable].map(element => [element, limit(testElement, element, tester)]); - // Check the promises either serially or concurrently - const checkLimit = pLimit(options.preserveOrder ? 1 : Infinity); + // Check the promises either serially or concurrently. + const checkLimit = pLimit(preserveOrder ? 1 : Number.POSITIVE_INFINITY); try { await Promise.all(items.map(element => checkLimit(finder, element))); @@ -45,6 +45,4 @@ const pLocate = async (iterable, tester, options) => { throw error; } -}; - -module.exports = pLocate; +} diff --git a/index.test-d.ts b/index.test-d.ts index 43b8979..0f42ad6 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -1,10 +1,11 @@ +/* eslint-disable @typescript-eslint/no-floating-promises */ import {expectType} from 'tsd'; -import pLocate = require('.'); +import pLocate from './index.js'; const files = new Set([ 'unicorn.png', 'rainbow.png', - Promise.resolve('pony.png') + Promise.resolve('pony.png'), ]); pLocate(files, file => { diff --git a/package.json b/package.json index 2d5e447..6ab7862 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,10 @@ "email": "sindresorhus@gmail.com", "url": "https://sindresorhus.com" }, + "type": "module", + "exports": "./index.js", "engines": { - "node": ">=10" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "scripts": { "test": "xo && ava && tsd" @@ -41,14 +43,14 @@ "bluebird" ], "dependencies": { - "p-limit": "^3.0.2" + "p-limit": "^4.0.0" }, "devDependencies": { - "ava": "^2.4.0", - "delay": "^4.1.0", - "in-range": "^2.0.0", - "time-span": "^4.0.0", - "tsd": "^0.13.1", - "xo": "^0.32.1" + "ava": "^3.15.0", + "delay": "^5.0.0", + "in-range": "^3.0.0", + "time-span": "^5.0.0", + "tsd": "^0.17.0", + "xo": "^0.44.0" } } diff --git a/readme.md b/readme.md index fa9b551..9a2c0e3 100644 --- a/readme.md +++ b/readme.md @@ -15,8 +15,8 @@ $ npm install p-locate Here we find the first file that exists on disk, in array order. ```js -const pathExists = require('path-exists'); -const pLocate = require('p-locate'); +import {pathExists} from 'path-exists'; +import pLocate from 'p-locate'; const files = [ 'unicorn.png', @@ -24,12 +24,10 @@ const files = [ 'pony.png' ]; -(async () => { - const foundPath = await pLocate(files, file => pathExists(file)); +const foundPath = await pLocate(files, file => pathExists(file)); - console.log(foundPath); - //=> 'rainbow' -})(); +console.log(foundPath); +//=> 'rainbow' ``` *The above is just an example. Use [`locate-path`](https://github.com/sindresorhus/locate-path) if you need this.* @@ -62,7 +60,7 @@ Type: `number`\ Default: `Infinity`\ Minimum: `1` -Number of concurrently pending promises returned by `tester`. +The number of concurrently pending promises returned by `tester`. ##### preserveOrder diff --git a/test.js b/test.js index b53f8c8..27fe153 100644 --- a/test.js +++ b/test.js @@ -1,14 +1,14 @@ -import {serial as test} from 'ava'; +import test from 'ava'; import delay from 'delay'; import inRange from 'in-range'; import timeSpan from 'time-span'; -import pLocate from '.'; +import pLocate from './index.js'; const input = [ [1, 300], [2, 400], [3, 200], - Promise.resolve([4, 100]) // Ensures promises work in the input + Promise.resolve([4, 100]), // Ensures promises work in the input ]; const tester = async ([value, ms]) => { @@ -16,33 +16,35 @@ const tester = async ([value, ms]) => { return value === 2 || value === 3; }; -test('main', async t => { +test.serial('main', async t => { const end = timeSpan(); t.is((await pLocate(input, tester))[0], 2); t.true(inRange(end(), {start: 370, end: 450}), 'should be time of item `2`'); }); -test('option {preserveOrder:false}', async t => { +test.serial('option {preserveOrder:false}', async t => { const end = timeSpan(); t.is((await pLocate(input, tester, {preserveOrder: false}))[0], 3); t.true(inRange(end(), {start: 170, end: 250}), 'should be time of item `3`'); }); -test('option {concurrency:1}', async t => { +test.serial('option {concurrency:1}', async t => { const end = timeSpan(); t.is((await pLocate(input, tester, {concurrency: 1}))[0], 2); t.true(inRange(end(), {start: 670, end: 750}), 'should be time of items `1` and `2`, since they run serially'); }); -test('returns `undefined` when nothing could be found', async t => { +test.serial('returns `undefined` when nothing could be found', async t => { t.is((await pLocate([1, 2, 3], () => false)), undefined); }); -test('rejected return value in `tester` rejects the promise', async t => { +test.serial('rejected return value in `tester` rejects the promise', async t => { const fixtureError = new Error('fixture'); await t.throwsAsync( pLocate([1, 2, 3], () => Promise.reject(fixtureError)), - fixtureError.message + { + message: fixtureError.message, + }, ); });