From 6fe367e1b951ce32500e10768d717c5c5bcd2ac3 Mon Sep 17 00:00:00 2001 From: Tyler <26290074+thegitduck@users.noreply.github.com> Date: Sat, 21 Dec 2024 15:34:30 -0800 Subject: [PATCH] add mapSeries --- README.md | 18 +++++++++++++++ src/index.ts | 3 ++- src/map-series.ts | 34 +++++++++++++++++++++++++++ src/test/map-series.test.ts | 46 +++++++++++++++++++++++++++++++++++++ src/test/props.test.ts | 2 +- 5 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 src/map-series.ts create mode 100644 src/test/map-series.test.ts diff --git a/README.md b/README.md index a9b8cd1..ed4b157 100644 --- a/README.md +++ b/README.md @@ -22,3 +22,21 @@ const result = await duckhawk.props({ three: fetch("https://pokeapi.co/api/v2/pokemon/3").then((res) => res.json()), }); ``` + +### mapSeries + +Bluebird equivalent: http://bluebirdjs.com/docs/api/promise.mapseries.html + +This awaits each promise in series and passes the result to the iterator. The result of the iterator is +returned as an array. + +```ts +import duckhawk from "duckhawk"; + +const result = await duckhawk.mapSeries( + [Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)], + (item) => item + 1 +); + +console.log(result); // [2, 3, 4] +``` diff --git a/src/index.ts b/src/index.ts index 6b1b217..a5be186 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,4 @@ import { props } from "./props.ts"; +import { mapSeries } from "./map-series.ts"; -export default { props }; +export default { props, mapSeries }; diff --git a/src/map-series.ts b/src/map-series.ts new file mode 100644 index 0000000..fec2d7b --- /dev/null +++ b/src/map-series.ts @@ -0,0 +1,34 @@ +// deno-lint-ignore-file no-explicit-any + +/** + * run Promises all in series + * + * @param arr list of promises + * @param iterator map callback for each promise result + * @returns result of iterator for each promise + * + * @example + * ```ts + * const result = await duckhawk.mapSeries([ + * Promise.resolve(1), + * Promise.resolve(2), + * Promise.resolve(3), + * ], (item) => item + 1); + * + * console.log(result); // [2, 3, 4] + * ``` + */ +export const mapSeries = async < + PromiseGiven extends Promise, + IteratorResult +>( + arr: PromiseGiven[], + iterator: (item: Awaited, index: number) => IteratorResult +): Promise => { + const results: IteratorResult[] = []; + for (let i = 0; i < arr.length; i++) { + const result = await iterator(await arr[i], i); + results.push(result); + } + return results; +}; diff --git a/src/test/map-series.test.ts b/src/test/map-series.test.ts new file mode 100644 index 0000000..7d4ab78 --- /dev/null +++ b/src/test/map-series.test.ts @@ -0,0 +1,46 @@ +import { mapSeries } from "../map-series.ts"; +import { expect } from "@std/expect"; + +Deno.test("mapSeries simple", async () => { + const result = await mapSeries( + [Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)], + (item) => item + 1 + ); + expect(result).toEqual([2, 3, 4]); +}); + +Deno.test("mapSeries with async", async () => { + const result = await mapSeries( + [Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)], + async (item) => item + (await Promise.resolve(1)) + ); + expect(result).toEqual([2, 3, 4]); +}); + +Deno.test("mapSeries with mixed types", async () => { + const result = await mapSeries( + [ + Promise.resolve(1), + Promise.resolve("hi"), + Promise.resolve({ foo: "bar" }), + ], + (item) => (typeof item === "object" ? item : item + "!") + ); + expect(result).toEqual(["1!", "hi!", { foo: "bar" }]); +}); + +Deno.test("mapSeries executes in order", async () => { + const order: number[] = []; + const result = await mapSeries( + [Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)], + (item, ind) => { + order.push(item); + expect(order).toEqual( + Array.from({ length: ind + 1 }).map((_, i) => i + 1) + ); + return item; + } + ); + + expect(result).toEqual([1, 2, 3]); +}); diff --git a/src/test/props.test.ts b/src/test/props.test.ts index f383586..60af4ff 100644 --- a/src/test/props.test.ts +++ b/src/test/props.test.ts @@ -2,7 +2,7 @@ import { props } from "../props.ts"; import { expect } from "@std/expect"; import { delayedReject } from "./utils.ts"; -Deno.test("props", async () => { +Deno.test("props simple", async () => { const result = await props({ a: Promise.resolve(1), b: Promise.resolve(2), -- 2.51.2