From 9552412c25a8b56eb3d66d119fa6ccfc0d52506a Mon Sep 17 00:00:00 2001 From: Richie Bendall Date: Sun, 27 Jun 2021 01:23:52 +1200 Subject: [PATCH 1/8] Add `.skip` Signed-off-by: Richie Bendall --- index.d.ts | 33 ++++++++++++++++++++++++++++++++- index.js | 15 ++++++++++++++- index.test-d.ts | 10 +++++++++- readme.md | 29 +++++++++++++++++++++++++++++ test.js | 10 +++++++++- 5 files changed, 93 insertions(+), 4 deletions(-) diff --git a/index.d.ts b/index.d.ts index 7478fee..badd5d9 100644 --- a/index.d.ts +++ b/index.d.ts @@ -58,4 +58,35 @@ export default function pMap( input: Iterable, mapper: Mapper, options?: Options -): Promise; +): Promise>>; + +/** +Return this value from a `mapper` function to skip adding a value in the returned array. + +@example +```js +import pMap, {skip} from 'p-map'; +import got from 'got'; + +const sites = [ + getWebsiteFromUsername('sindresorhus'), //=> Promise + 'https://avajs.dev', + 'https://github.com' +]; + +const mapper = async site => { + try { + const {requestUrl} = await got.head(site); + return requestUrl; + } catch { + return skip + } +}; + +const result = await pMap(sites, mapper, {concurrency: 2}); + +console.log(result); +//=> ['https://sindresorhus.com/', 'https://avajs.dev/', 'https://github.com/'] +``` +*/ +export const skip: unique symbol; diff --git a/index.js b/index.js index 15f3da2..2c553f1 100644 --- a/index.js +++ b/index.js @@ -19,6 +19,7 @@ export default async function pMap( const result = []; const errors = []; + const skippedIndexes = []; const iterator = iterable[Symbol.iterator](); let isRejected = false; let isIterableDone = false; @@ -41,6 +42,10 @@ export default async function pMap( if (!stopOnError && errors.length > 0) { reject(new AggregateError(errors)); } else { + for (const skippedIndex of skippedIndexes) { + result.splice(skippedIndex, 1); + } + resolve(result); } } @@ -53,7 +58,13 @@ export default async function pMap( (async () => { try { const element = await nextItem.value; - result[index] = await mapper(element, index); + const value = await mapper(element, index); + if (value === skip) { + skippedIndexes.push(index); + } else { + result[index] = value; + } + resolvingCount--; next(); } catch (error) { @@ -78,3 +89,5 @@ export default async function pMap( } }); } + +export const skip = Symbol('skip'); diff --git a/index.test-d.ts b/index.test-d.ts index f5595ce..95523c8 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -1,5 +1,5 @@ import {expectType, expectAssignable} from 'tsd'; -import pMap, {Options, Mapper} from './index.js'; +import pMap, {Options, Mapper, skip} from './index.js'; const sites = [ 'https://sindresorhus.com', @@ -40,3 +40,11 @@ expectType>(pMap(sites, (site: string) => site)); expectType>(pMap(sites, (site: string) => site.length)); expectType>(pMap(numbers, (number: number) => number * 2)); + +expectType>(pMap(numbers, (number: number) => { + if (number % 2 === 0) { + return number * 2; + } + + return skip; +})); diff --git a/readme.md b/readme.md index 0222b16..945b65c 100644 --- a/readme.md +++ b/readme.md @@ -72,6 +72,35 @@ Default: `true` When set to `false`, instead of stopping when a promise rejects, it will wait for all the promises to settle and then reject with an [aggregated error](https://github.com/sindresorhus/aggregate-error) containing all the errors from the rejected promises. +### pMap.skip + +Return this value from a `mapper` function to skip adding a value in the returned array. + +```js +import pMap, {skip} from 'p-map'; +import got from 'got'; + +const sites = [ + getWebsiteFromUsername('sindresorhus'), //=> Promise + 'https://avajs.dev', + 'https://github.com' +]; + +const mapper = async site => { + try { + const {requestUrl} = await got.head(site); + return requestUrl; + } catch { + return skip + } +}; + +const result = await pMap(sites, mapper, {concurrency: 2}); + +console.log(result); +//=> ['https://sindresorhus.com/', 'https://avajs.dev/', 'https://github.com/'] +``` + ## p-map for enterprise Available as part of the Tidelift Subscription. diff --git a/test.js b/test.js index 35d361a..f0a5bf9 100644 --- a/test.js +++ b/test.js @@ -4,7 +4,7 @@ import inRange from 'in-range'; import timeSpan from 'time-span'; import randomInt from 'random-int'; import AggregateError from 'aggregate-error'; -import pMap from './index.js'; +import pMap, {skip} from './index.js'; const sharedInput = [ Promise.resolve([10, 300]), @@ -107,3 +107,11 @@ test('aggregate errors when stopOnError is false', async t => { await t.throwsAsync(pMap(errorInput1, mapper, {concurrency: 1, stopOnError: false}), {instanceOf: AggregateError, message: /foo(.|\n)*bar/}); await t.throwsAsync(pMap(errorInput2, mapper, {concurrency: 1, stopOnError: false}), {instanceOf: AggregateError, message: /bar(.|\n)*foo/}); }); + +test('.skip', async t => { + t.deepEqual(await pMap([ + 1, + skip, + 2 + ], async value => value), [1, 2]); +}); From 90e40cf7fb286c20f5397a20a4e98d4e9ebdb131 Mon Sep 17 00:00:00 2001 From: Richie Bendall Date: Sun, 27 Jun 2021 12:21:58 +1200 Subject: [PATCH 2/8] Demonstrate skipping in example Signed-off-by: Richie Bendall --- index.d.ts | 1 + readme.md | 1 + 2 files changed, 2 insertions(+) diff --git a/index.d.ts b/index.d.ts index badd5d9..e464730 100644 --- a/index.d.ts +++ b/index.d.ts @@ -71,6 +71,7 @@ import got from 'got'; const sites = [ getWebsiteFromUsername('sindresorhus'), //=> Promise 'https://avajs.dev', + 'https://example.invalid', 'https://github.com' ]; diff --git a/readme.md b/readme.md index 945b65c..89ab99a 100644 --- a/readme.md +++ b/readme.md @@ -83,6 +83,7 @@ import got from 'got'; const sites = [ getWebsiteFromUsername('sindresorhus'), //=> Promise 'https://avajs.dev', + 'https://example.invalid', 'https://github.com' ]; From ad605877a572d81010b3c9e7f700775c0e27e6b8 Mon Sep 17 00:00:00 2001 From: Richie Bendall Date: Sun, 27 Jun 2021 20:36:37 +1200 Subject: [PATCH 3/8] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 89ab99a..144a196 100644 --- a/readme.md +++ b/readme.md @@ -72,7 +72,7 @@ Default: `true` When set to `false`, instead of stopping when a promise rejects, it will wait for all the promises to settle and then reject with an [aggregated error](https://github.com/sindresorhus/aggregate-error) containing all the errors from the rejected promises. -### pMap.skip +### skip Return this value from a `mapper` function to skip adding a value in the returned array. From 1b985f2b1be6a62850838943e1a3fb247239421c Mon Sep 17 00:00:00 2001 From: Richie Bendall Date: Sun, 27 Jun 2021 22:18:34 +1200 Subject: [PATCH 4/8] Rename `skip` to `pMapSkip` Signed-off-by: Richie Bendall --- index.d.ts | 8 ++++---- index.js | 4 ++-- index.test-d.ts | 4 ++-- readme.md | 6 +++--- test.js | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/index.d.ts b/index.d.ts index e464730..3f719ed 100644 --- a/index.d.ts +++ b/index.d.ts @@ -58,14 +58,14 @@ export default function pMap( input: Iterable, mapper: Mapper, options?: Options -): Promise>>; +): Promise>>; /** Return this value from a `mapper` function to skip adding a value in the returned array. @example ```js -import pMap, {skip} from 'p-map'; +import pMap, {pMapSkip} from 'p-map'; import got from 'got'; const sites = [ @@ -80,7 +80,7 @@ const mapper = async site => { const {requestUrl} = await got.head(site); return requestUrl; } catch { - return skip + return pMapSkip } }; @@ -90,4 +90,4 @@ console.log(result); //=> ['https://sindresorhus.com/', 'https://avajs.dev/', 'https://github.com/'] ``` */ -export const skip: unique symbol; +export const pMapSkip: unique symbol; diff --git a/index.js b/index.js index 2c553f1..7ed929a 100644 --- a/index.js +++ b/index.js @@ -59,7 +59,7 @@ export default async function pMap( try { const element = await nextItem.value; const value = await mapper(element, index); - if (value === skip) { + if (value === pMapSkip) { skippedIndexes.push(index); } else { result[index] = value; @@ -90,4 +90,4 @@ export default async function pMap( }); } -export const skip = Symbol('skip'); +export const pMapSkip = Symbol('skip'); diff --git a/index.test-d.ts b/index.test-d.ts index 95523c8..46de879 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -1,5 +1,5 @@ import {expectType, expectAssignable} from 'tsd'; -import pMap, {Options, Mapper, skip} from './index.js'; +import pMap, {Options, Mapper, pMapSkip} from './index.js'; const sites = [ 'https://sindresorhus.com', @@ -46,5 +46,5 @@ expectType>(pMap(numbers, (number: number) => { return number * 2; } - return skip; + return pMapSkip; })); diff --git a/readme.md b/readme.md index 144a196..789374a 100644 --- a/readme.md +++ b/readme.md @@ -72,12 +72,12 @@ Default: `true` When set to `false`, instead of stopping when a promise rejects, it will wait for all the promises to settle and then reject with an [aggregated error](https://github.com/sindresorhus/aggregate-error) containing all the errors from the rejected promises. -### skip +### pMapSkip Return this value from a `mapper` function to skip adding a value in the returned array. ```js -import pMap, {skip} from 'p-map'; +import pMap, {pMapSkip} from 'p-map'; import got from 'got'; const sites = [ @@ -92,7 +92,7 @@ const mapper = async site => { const {requestUrl} = await got.head(site); return requestUrl; } catch { - return skip + return pMapSkip } }; diff --git a/test.js b/test.js index f0a5bf9..8b71125 100644 --- a/test.js +++ b/test.js @@ -4,7 +4,7 @@ import inRange from 'in-range'; import timeSpan from 'time-span'; import randomInt from 'random-int'; import AggregateError from 'aggregate-error'; -import pMap, {skip} from './index.js'; +import pMap, {pMapSkip} from './index.js'; const sharedInput = [ Promise.resolve([10, 300]), @@ -111,7 +111,7 @@ test('aggregate errors when stopOnError is false', async t => { test('.skip', async t => { t.deepEqual(await pMap([ 1, - skip, + pMapSkip, 2 ], async value => value), [1, 2]); }); From 550125cd05d2cd7d7873a1a1571ce07336a61f9a Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Mon, 28 Jun 2021 11:38:29 +0700 Subject: [PATCH 5/8] Update index.d.ts --- index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index 3f719ed..d982bb3 100644 --- a/index.d.ts +++ b/index.d.ts @@ -64,7 +64,7 @@ export default function pMap( Return this value from a `mapper` function to skip adding a value in the returned array. @example -```js +``` import pMap, {pMapSkip} from 'p-map'; import got from 'got'; From 482e21813902977aee6ecd1abf6e2e640dd484f3 Mon Sep 17 00:00:00 2001 From: Richie Bendall Date: Mon, 28 Jun 2021 20:09:40 +1200 Subject: [PATCH 6/8] Update readme.md Co-authored-by: Sindre Sorhus --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 789374a..a058c27 100644 --- a/readme.md +++ b/readme.md @@ -74,7 +74,7 @@ When set to `false`, instead of stopping when a promise rejects, it will wait fo ### pMapSkip -Return this value from a `mapper` function to skip adding a value in the returned array. +Return this value from a `mapper` function to skip including the value in the returned array. ```js import pMap, {pMapSkip} from 'p-map'; From 7767b2bfa07aaf23b0f54084a883b0d918b483f3 Mon Sep 17 00:00:00 2001 From: Richie Bendall Date: Mon, 28 Jun 2021 20:10:06 +1200 Subject: [PATCH 7/8] Update index.d.ts --- index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index d982bb3..f517455 100644 --- a/index.d.ts +++ b/index.d.ts @@ -61,7 +61,7 @@ export default function pMap( ): Promise>>; /** -Return this value from a `mapper` function to skip adding a value in the returned array. +Return this value from a `mapper` function to skip including the value in the returned array. @example ``` From b2eca042ef439c50698d271a4d471104e94e0e42 Mon Sep 17 00:00:00 2001 From: Richie Bendall Date: Mon, 28 Jun 2021 20:20:54 +1200 Subject: [PATCH 8/8] Update index.js --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 00265a2..05c8165 100644 --- a/index.js +++ b/index.js @@ -64,7 +64,7 @@ export default async function pMap( } const value = await mapper(element, index); - if (value === pMapSkip) { + if (value === pMapSkip) { skippedIndexes.push(index); } else { result[index] = value;