diff --git a/README.md b/README.md index 257b9b6..05ce430 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,33 @@ const result = pipe( console.log(result); // "4" ``` +If you want to create a new function that composes multiple operators, use +`compose` like below. + +```ts +import { compose } from "@core/pipe/compose"; + +const operator = compose( + (v: number) => v + 1, // The first operator must be typed explicitly + (v) => v * 2, // inferred as (v: number) => number + (v) => v.toString(), // inferred as (v: number) => string +); +console.log(operator(1)); // "4" +``` + +Or use `async` module to compose multiple asynchronous operators. + +```ts +import { compose } from "@core/pipe/async/compose"; + +const operator = compose( + (v: number) => Promise.resolve(v + 1), // The first operator must be typed explicitly + (v) => Promise.resolve(v * 2), // inferred as (v: number) => number | Promise + (v) => Promise.resolve(v.toString()), // inferred as (v: number) => string | Promise +); +console.log(await operator(1)); // "4" +``` + ## Difference The `pipe` function in the root module is equivalent to function calls without diff --git a/async/compose.ts b/async/compose.ts new file mode 100644 index 0000000..e069659 --- /dev/null +++ b/async/compose.ts @@ -0,0 +1,470 @@ +import type { AsyncOperator } from "./operator.ts"; +import type { LastAsyncOperatorReturn } from "./_common.ts"; + +/** + * Composes a sequence of operators to create a new function. + * Supports type inference for operators and the return type of the final operator. + * + * > [!NOTE] + * > + * > If more than 20 operators are used, their types default to `AsyncOperator`, + * > requiring explicit type annotations. + * + * @param operators - A sequence of operators to apply to the value. + * @returns A function that processes the value through all operators and returns the final result. + * + * @example + * ```ts + * import { compose } from "@core/pipe/async"; + * + * const result = await compose( + * (v: number) => Promise.resolve(v + 1), // The first operator requires an explicit type + * (v) => Promise.resolve(v * 2), // inferred as (v: number) => number | Promise + * (v) => Promise.resolve(v.toString()), // inferred as (v: number) => string | Promise + * )(1); + * console.log(result); // "4" + * ``` + */ +export function compose( + o01: AsyncOperator, +): AsyncOperator; +export function compose( + o01: AsyncOperator, + o02: AsyncOperator, +): AsyncOperator; +export function compose( + o01: AsyncOperator, + o02: AsyncOperator, + o03: AsyncOperator, +): AsyncOperator; +export function compose( + o01: AsyncOperator, + o02: AsyncOperator, + o03: AsyncOperator, + o04: AsyncOperator, +): AsyncOperator; +export function compose( + o01: AsyncOperator, + o02: AsyncOperator, + o03: AsyncOperator, + o04: AsyncOperator, + o05: AsyncOperator, +): AsyncOperator; +export function compose( + o01: AsyncOperator, + o02: AsyncOperator, + o03: AsyncOperator, + o04: AsyncOperator, + o05: AsyncOperator, + o06: AsyncOperator, +): AsyncOperator; +export function compose( + o01: AsyncOperator, + o02: AsyncOperator, + o03: AsyncOperator, + o04: AsyncOperator, + o05: AsyncOperator, + o06: AsyncOperator, + o07: AsyncOperator, +): AsyncOperator; +export function compose( + o01: AsyncOperator, + o02: AsyncOperator, + o03: AsyncOperator, + o04: AsyncOperator, + o05: AsyncOperator, + o06: AsyncOperator, + o07: AsyncOperator, + o08: AsyncOperator, +): AsyncOperator; +export function compose( + o01: AsyncOperator, + o02: AsyncOperator, + o03: AsyncOperator, + o04: AsyncOperator, + o05: AsyncOperator, + o06: AsyncOperator, + o07: AsyncOperator, + o08: AsyncOperator, + o09: AsyncOperator, +): AsyncOperator; +export function compose( + o01: AsyncOperator, + o02: AsyncOperator, + o03: AsyncOperator, + o04: AsyncOperator, + o05: AsyncOperator, + o06: AsyncOperator, + o07: AsyncOperator, + o08: AsyncOperator, + o09: AsyncOperator, + o10: AsyncOperator, +): AsyncOperator; +export function compose< + V, + T01, + T02, + T03, + T04, + T05, + T06, + T07, + T08, + T09, + T10, + T11, +>( + o01: AsyncOperator, + o02: AsyncOperator, + o03: AsyncOperator, + o04: AsyncOperator, + o05: AsyncOperator, + o06: AsyncOperator, + o07: AsyncOperator, + o08: AsyncOperator, + o09: AsyncOperator, + o10: AsyncOperator, + o11: AsyncOperator, +): AsyncOperator; +export function compose< + V, + T01, + T02, + T03, + T04, + T05, + T06, + T07, + T08, + T09, + T10, + T11, + T12, +>( + o01: AsyncOperator, + o02: AsyncOperator, + o03: AsyncOperator, + o04: AsyncOperator, + o05: AsyncOperator, + o06: AsyncOperator, + o07: AsyncOperator, + o08: AsyncOperator, + o09: AsyncOperator, + o10: AsyncOperator, + o11: AsyncOperator, + o12: AsyncOperator, +): AsyncOperator; +export function compose< + V, + T01, + T02, + T03, + T04, + T05, + T06, + T07, + T08, + T09, + T10, + T11, + T12, + T13, +>( + o01: AsyncOperator, + o02: AsyncOperator, + o03: AsyncOperator, + o04: AsyncOperator, + o05: AsyncOperator, + o06: AsyncOperator, + o07: AsyncOperator, + o08: AsyncOperator, + o09: AsyncOperator, + o10: AsyncOperator, + o11: AsyncOperator, + o12: AsyncOperator, + o13: AsyncOperator, +): AsyncOperator; +export function compose< + V, + T01, + T02, + T03, + T04, + T05, + T06, + T07, + T08, + T09, + T10, + T11, + T12, + T13, + T14, +>( + o01: AsyncOperator, + o02: AsyncOperator, + o03: AsyncOperator, + o04: AsyncOperator, + o05: AsyncOperator, + o06: AsyncOperator, + o07: AsyncOperator, + o08: AsyncOperator, + o09: AsyncOperator, + o10: AsyncOperator, + o11: AsyncOperator, + o12: AsyncOperator, + o13: AsyncOperator, + o14: AsyncOperator, +): AsyncOperator; +export function compose< + V, + T01, + T02, + T03, + T04, + T05, + T06, + T07, + T08, + T09, + T10, + T11, + T12, + T13, + T14, + T15, +>( + o01: AsyncOperator, + o02: AsyncOperator, + o03: AsyncOperator, + o04: AsyncOperator, + o05: AsyncOperator, + o06: AsyncOperator, + o07: AsyncOperator, + o08: AsyncOperator, + o09: AsyncOperator, + o10: AsyncOperator, + o11: AsyncOperator, + o12: AsyncOperator, + o13: AsyncOperator, + o14: AsyncOperator, + o15: AsyncOperator, +): AsyncOperator; +export function compose< + V, + T01, + T02, + T03, + T04, + T05, + T06, + T07, + T08, + T09, + T10, + T11, + T12, + T13, + T14, + T15, + T16, +>( + o01: AsyncOperator, + o02: AsyncOperator, + o03: AsyncOperator, + o04: AsyncOperator, + o05: AsyncOperator, + o06: AsyncOperator, + o07: AsyncOperator, + o08: AsyncOperator, + o09: AsyncOperator, + o10: AsyncOperator, + o11: AsyncOperator, + o12: AsyncOperator, + o13: AsyncOperator, + o14: AsyncOperator, + o15: AsyncOperator, + o16: AsyncOperator, +): AsyncOperator; +export function compose< + V, + T01, + T02, + T03, + T04, + T05, + T06, + T07, + T08, + T09, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, +>( + o01: AsyncOperator, + o02: AsyncOperator, + o03: AsyncOperator, + o04: AsyncOperator, + o05: AsyncOperator, + o06: AsyncOperator, + o07: AsyncOperator, + o08: AsyncOperator, + o09: AsyncOperator, + o10: AsyncOperator, + o11: AsyncOperator, + o12: AsyncOperator, + o13: AsyncOperator, + o14: AsyncOperator, + o15: AsyncOperator, + o16: AsyncOperator, + o17: AsyncOperator, +): AsyncOperator; +export function compose< + V, + T01, + T02, + T03, + T04, + T05, + T06, + T07, + T08, + T09, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, +>( + o01: AsyncOperator, + o02: AsyncOperator, + o03: AsyncOperator, + o04: AsyncOperator, + o05: AsyncOperator, + o06: AsyncOperator, + o07: AsyncOperator, + o08: AsyncOperator, + o09: AsyncOperator, + o10: AsyncOperator, + o11: AsyncOperator, + o12: AsyncOperator, + o13: AsyncOperator, + o14: AsyncOperator, + o15: AsyncOperator, + o16: AsyncOperator, + o17: AsyncOperator, + o18: AsyncOperator, +): AsyncOperator; +export function compose< + V, + T01, + T02, + T03, + T04, + T05, + T06, + T07, + T08, + T09, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, +>( + o01: AsyncOperator, + o02: AsyncOperator, + o03: AsyncOperator, + o04: AsyncOperator, + o05: AsyncOperator, + o06: AsyncOperator, + o07: AsyncOperator, + o08: AsyncOperator, + o09: AsyncOperator, + o10: AsyncOperator, + o11: AsyncOperator, + o12: AsyncOperator, + o13: AsyncOperator, + o14: AsyncOperator, + o15: AsyncOperator, + o16: AsyncOperator, + o17: AsyncOperator, + o18: AsyncOperator, + o19: AsyncOperator, +): AsyncOperator; +export function compose< + V, + T01, + T02, + T03, + T04, + T05, + T06, + T07, + T08, + T09, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, +>( + o01: AsyncOperator, + o02: AsyncOperator, + o03: AsyncOperator, + o04: AsyncOperator, + o05: AsyncOperator, + o06: AsyncOperator, + o07: AsyncOperator, + o08: AsyncOperator, + o09: AsyncOperator, + o10: AsyncOperator, + o11: AsyncOperator, + o12: AsyncOperator, + o13: AsyncOperator, + o14: AsyncOperator, + o15: AsyncOperator, + o16: AsyncOperator, + o17: AsyncOperator, + o18: AsyncOperator, + o19: AsyncOperator, + o20: AsyncOperator, +): AsyncOperator; + +export function compose< + V, + // deno-lint-ignore no-explicit-any + AsyncOperators extends AsyncOperator[], +>( + ...operators: AsyncOperators +): AsyncOperator>; + +// deno-lint-ignore no-explicit-any +export function compose(...operators: AsyncOperator[]) { + return async (value: V) => { + return await operators.reduce( + async (result, next) => next(await result), + Promise.resolve(value), + ); + }; +} diff --git a/async/compose_test.ts b/async/compose_test.ts new file mode 100644 index 0000000..83dacd7 --- /dev/null +++ b/async/compose_test.ts @@ -0,0 +1,158 @@ +import { test } from "@cross/test"; +import { assertEquals } from "@std/assert"; +import { assertType, type IsExact } from "@std/testing/types"; +import { compose } from "./compose.ts"; + +await test("compose with no operators should return an identity function", async () => { + assertEquals(await compose()(1), 1); +}); + +await test("compose with one operator should return the operator", async () => { + assertEquals(await compose((v: number) => Promise.resolve(v * 2))(1), 2); +}); + +await test("compose with one operator requires explicity type annotation", () => { + compose((v) => { + assertType>(true); + }); + compose((v: number) => { + assertType>(true); + return v.toString(); + }); +}); + +await test("compose with two operators should return a composed operator", async () => { + assertEquals( + await compose( + (v: number) => Promise.resolve(v * 2), + (v) => Promise.resolve(v * 2), + )(1), + 4, + ); +}); + +await test("compose with two operators should resolve the type properly", () => { + compose((v: number) => { + assertType>(true); + return v.toString(); + }, (v) => { + assertType>(true); + return v.length; + }); +}); + +await test("compose with three operators should return a composed operator", async () => { + assertEquals( + await compose( + (v: number) => Promise.resolve(v * 2), + (v) => Promise.resolve(v * 2), + (v) => Promise.resolve(v * 2), + )(1), + 8, + ); +}); + +await test("compose with three operators should resolve the type properly", () => { + compose((v: number) => { + assertType>(true); + return v.toString(); + }, (v) => { + assertType>(true); + return v.length; + }, (v) => { + assertType>(true); + return v.toString(); + }); +}); + +await test("compose with twenty operators should return a composed operator", async () => { + assertEquals( + await compose(...Array(20).fill((v: number) => Promise.resolve(v * 2)))(1), + 2 ** 20, + ); +}); + +await test("compose with twenty operators should resolve the type properly", () => { + compose( + (v: number) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + ); +}); diff --git a/async/mod.ts b/async/mod.ts index 2985ca8..d32b5d9 100644 --- a/async/mod.ts +++ b/async/mod.ts @@ -1,2 +1,3 @@ export type { AsyncOperator } from "./operator.ts"; +export * from "./compose.ts"; export * from "./pipe.ts"; diff --git a/compose.ts b/compose.ts new file mode 100644 index 0000000..038cfca --- /dev/null +++ b/compose.ts @@ -0,0 +1,467 @@ +import type { Operator } from "./operator.ts"; +import type { LastOperatorReturn } from "./_common.ts"; + +/** + * Composes a sequence of operators to create a new function. + * Supports type inference for operators and the return type of the final operator. + * + * > [!NOTE] + * > + * > If more than 20 operators are used, their types default to `Operator`, + * > requiring explicit type annotations. + * + * @param operators - A sequence of operators to apply to the value. + * @returns A function that processes the value through all operators and returns the final result. + * + * @example + * ```ts + * import { compose } from "@core/pipe"; + * + * const result = compose( + * (v: number) => v + 1, // The first operator requires an explicit type + * (v) => v * 2, // inferred as (v: number) => number + * (v) => v.toString(), // inferred as (v: number) => string + * )(1); + * console.log(result); // "4" + * ``` + */ +export function compose( + o01: Operator, +): Operator; +export function compose( + o01: Operator, + o02: Operator, +): Operator; +export function compose( + o01: Operator, + o02: Operator, + o03: Operator, +): Operator; +export function compose( + o01: Operator, + o02: Operator, + o03: Operator, + o04: Operator, +): Operator; +export function compose( + o01: Operator, + o02: Operator, + o03: Operator, + o04: Operator, + o05: Operator, +): Operator; +export function compose( + o01: Operator, + o02: Operator, + o03: Operator, + o04: Operator, + o05: Operator, + o06: Operator, +): Operator; +export function compose( + o01: Operator, + o02: Operator, + o03: Operator, + o04: Operator, + o05: Operator, + o06: Operator, + o07: Operator, +): Operator; +export function compose( + o01: Operator, + o02: Operator, + o03: Operator, + o04: Operator, + o05: Operator, + o06: Operator, + o07: Operator, + o08: Operator, +): Operator; +export function compose( + o01: Operator, + o02: Operator, + o03: Operator, + o04: Operator, + o05: Operator, + o06: Operator, + o07: Operator, + o08: Operator, + o09: Operator, +): Operator; +export function compose( + o01: Operator, + o02: Operator, + o03: Operator, + o04: Operator, + o05: Operator, + o06: Operator, + o07: Operator, + o08: Operator, + o09: Operator, + o10: Operator, +): Operator; +export function compose< + V, + T01, + T02, + T03, + T04, + T05, + T06, + T07, + T08, + T09, + T10, + T11, +>( + o01: Operator, + o02: Operator, + o03: Operator, + o04: Operator, + o05: Operator, + o06: Operator, + o07: Operator, + o08: Operator, + o09: Operator, + o10: Operator, + o11: Operator, +): Operator; +export function compose< + V, + T01, + T02, + T03, + T04, + T05, + T06, + T07, + T08, + T09, + T10, + T11, + T12, +>( + o01: Operator, + o02: Operator, + o03: Operator, + o04: Operator, + o05: Operator, + o06: Operator, + o07: Operator, + o08: Operator, + o09: Operator, + o10: Operator, + o11: Operator, + o12: Operator, +): Operator; +export function compose< + V, + T01, + T02, + T03, + T04, + T05, + T06, + T07, + T08, + T09, + T10, + T11, + T12, + T13, +>( + o01: Operator, + o02: Operator, + o03: Operator, + o04: Operator, + o05: Operator, + o06: Operator, + o07: Operator, + o08: Operator, + o09: Operator, + o10: Operator, + o11: Operator, + o12: Operator, + o13: Operator, +): Operator; +export function compose< + V, + T01, + T02, + T03, + T04, + T05, + T06, + T07, + T08, + T09, + T10, + T11, + T12, + T13, + T14, +>( + o01: Operator, + o02: Operator, + o03: Operator, + o04: Operator, + o05: Operator, + o06: Operator, + o07: Operator, + o08: Operator, + o09: Operator, + o10: Operator, + o11: Operator, + o12: Operator, + o13: Operator, + o14: Operator, +): Operator; +export function compose< + V, + T01, + T02, + T03, + T04, + T05, + T06, + T07, + T08, + T09, + T10, + T11, + T12, + T13, + T14, + T15, +>( + o01: Operator, + o02: Operator, + o03: Operator, + o04: Operator, + o05: Operator, + o06: Operator, + o07: Operator, + o08: Operator, + o09: Operator, + o10: Operator, + o11: Operator, + o12: Operator, + o13: Operator, + o14: Operator, + o15: Operator, +): Operator; +export function compose< + V, + T01, + T02, + T03, + T04, + T05, + T06, + T07, + T08, + T09, + T10, + T11, + T12, + T13, + T14, + T15, + T16, +>( + o01: Operator, + o02: Operator, + o03: Operator, + o04: Operator, + o05: Operator, + o06: Operator, + o07: Operator, + o08: Operator, + o09: Operator, + o10: Operator, + o11: Operator, + o12: Operator, + o13: Operator, + o14: Operator, + o15: Operator, + o16: Operator, +): Operator; +export function compose< + V, + T01, + T02, + T03, + T04, + T05, + T06, + T07, + T08, + T09, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, +>( + o01: Operator, + o02: Operator, + o03: Operator, + o04: Operator, + o05: Operator, + o06: Operator, + o07: Operator, + o08: Operator, + o09: Operator, + o10: Operator, + o11: Operator, + o12: Operator, + o13: Operator, + o14: Operator, + o15: Operator, + o16: Operator, + o17: Operator, +): Operator; +export function compose< + V, + T01, + T02, + T03, + T04, + T05, + T06, + T07, + T08, + T09, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, +>( + o01: Operator, + o02: Operator, + o03: Operator, + o04: Operator, + o05: Operator, + o06: Operator, + o07: Operator, + o08: Operator, + o09: Operator, + o10: Operator, + o11: Operator, + o12: Operator, + o13: Operator, + o14: Operator, + o15: Operator, + o16: Operator, + o17: Operator, + o18: Operator, +): Operator; +export function compose< + V, + T01, + T02, + T03, + T04, + T05, + T06, + T07, + T08, + T09, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, +>( + o01: Operator, + o02: Operator, + o03: Operator, + o04: Operator, + o05: Operator, + o06: Operator, + o07: Operator, + o08: Operator, + o09: Operator, + o10: Operator, + o11: Operator, + o12: Operator, + o13: Operator, + o14: Operator, + o15: Operator, + o16: Operator, + o17: Operator, + o18: Operator, + o19: Operator, +): Operator; +export function compose< + V, + T01, + T02, + T03, + T04, + T05, + T06, + T07, + T08, + T09, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, +>( + o01: Operator, + o02: Operator, + o03: Operator, + o04: Operator, + o05: Operator, + o06: Operator, + o07: Operator, + o08: Operator, + o09: Operator, + o10: Operator, + o11: Operator, + o12: Operator, + o13: Operator, + o14: Operator, + o15: Operator, + o16: Operator, + o17: Operator, + o18: Operator, + o19: Operator, + o20: Operator, +): Operator; + +// deno-lint-ignore no-explicit-any +export function compose[]>( + ...operators: Operators +): Operator>; + +// deno-lint-ignore no-explicit-any +export function compose(...operators: Operator[]) { + return (value: V) => { + return operators.reduce( + (result, next) => next(result), + value, + ); + }; +} diff --git a/compose_test.ts b/compose_test.ts new file mode 100644 index 0000000..e08042a --- /dev/null +++ b/compose_test.ts @@ -0,0 +1,142 @@ +import { test } from "@cross/test"; +import { assertEquals } from "@std/assert"; +import { assertType, type IsExact } from "@std/testing/types"; +import { compose } from "./compose.ts"; + +await test("compose with no operators should return an identity function", () => { + assertEquals(compose()(1), 1); +}); + +await test("compose with one operator should return the operator", () => { + assertEquals(compose((v: number) => v * 2)(1), 2); +}); + +await test("compose with one operator requires explicity type annotation", () => { + compose((v) => { + assertType>(true); + }); + compose((v: number) => { + assertType>(true); + return v.toString(); + }); +}); + +await test("compose with two operators should return a composed operator", () => { + assertEquals(compose((v: number) => v * 2, (v) => v * 2)(1), 4); +}); + +await test("compose with two operators should resolve the type properly", () => { + compose((v: number) => { + assertType>(true); + return v.toString(); + }, (v) => { + assertType>(true); + return v.length; + }); +}); + +await test("compose with three operators should return a composed operator", () => { + assertEquals(compose((v: number) => v * 2, (v) => v * 2, (v) => v * 2)(1), 8); +}); + +await test("compose with three operators should resolve the type properly", () => { + compose((v: number) => { + assertType>(true); + return v.toString(); + }, (v) => { + assertType>(true); + return v.length; + }, (v) => { + assertType>(true); + return v.toString(); + }); +}); + +await test("compose with twenty operators should return a composed operator", () => { + assertEquals(compose(...Array(20).fill((v: number) => v * 2))(1), 2 ** 20); +}); + +await test("compose with twenty operators should resolve the type properly", () => { + compose( + (v: number) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + (v) => { + assertType>(true); + return v; + }, + ); +}); diff --git a/deno.jsonc b/deno.jsonc index b65d377..c65f81f 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -4,8 +4,10 @@ "exports": { ".": "./mod.ts", "./async": "./async/mod.ts", + "./async/compose": "./async/compose.ts", "./async/operator": "./async/operator.ts", "./async/pipe": "./async/pipe.ts", + "./compose": "./compose.ts", "./operator": "./operator.ts", "./pipe": "./pipe.ts" }, diff --git a/mod.ts b/mod.ts index fef5067..083e9a6 100644 --- a/mod.ts +++ b/mod.ts @@ -1,2 +1,3 @@ export type { Operator } from "./operator.ts"; +export * from "./compose.ts"; export * from "./pipe.ts";