From 960adbabc9ef611bc97af71e8dd8d88b6aa8feb1 Mon Sep 17 00:00:00 2001 From: Guga Guichard Date: Wed, 12 Jun 2024 15:19:55 -0300 Subject: [PATCH] docs: Tidy up docs and return types --- src/combinators.ts | 32 +++----- src/environment/tests/branch.test.ts | 5 +- src/index.ts | 1 + src/internal/types.ts | 115 ++++++++++++--------------- src/tests/catch-failure.test.ts | 5 +- src/tests/errors.test.ts | 6 +- src/tests/map-errors.test.ts | 5 +- src/tests/types.test.ts | 4 +- src/types.ts | 34 ++++++-- 9 files changed, 107 insertions(+), 100 deletions(-) diff --git a/src/combinators.ts b/src/combinators.ts index 912678a9..ec4bc0bf 100644 --- a/src/combinators.ts +++ b/src/combinators.ts @@ -4,6 +4,7 @@ import type { CanComposeInSequence, Composable, Last, + MapParametersReturn, MergeObjects, PipeReturn, RecordToTuple, @@ -13,7 +14,6 @@ import type { UnpackData, } from './types.ts' import { composable, failure, fromSuccess, success } from './constructors.ts' -import { Internal } from './internal/types.ts' /** * Merges a list of objects into a single object. @@ -139,7 +139,7 @@ function collect>( } > { const fnsWithKey = Object.entries(fns).map(([key, cf]) => - map(cf, (result) => ({ [key]: result })), + map(cf, (result) => ({ [key]: result })) ) return map(all(...(fnsWithKey as any)), mergeObjects) as Composable< ( @@ -234,15 +234,11 @@ function map( function mapParameters< Fn extends Composable, NewParameters extends unknown[], - const O extends Parameters, + const MapperOutput extends Parameters, >( fn: Fn, - mapper: (...args: NewParameters) => Promise | O, -): Composable< - ( - ...args: NewParameters - ) => Internal.IsNever> extends true ? never : UnpackData -> { + mapper: (...args: NewParameters) => Promise | MapperOutput, +): MapParametersReturn { return async (...args) => { const output = await composable(mapper)(...args) if (!output.success) return failure(output.errors) @@ -274,9 +270,8 @@ function catchFailure< ( ...args: Parameters ) => Awaited> extends never[] - ? UnpackData extends any[] - ? UnpackData - : Awaited> | UnpackData + ? UnpackData extends any[] ? UnpackData + : Awaited> | UnpackData : Awaited> | UnpackData > { return async (...args: Parameters) => { @@ -342,14 +337,13 @@ function trace( ):

( fn: Composable<(...args: P) => Output>, ) => Composable<(...args: P) => Output> { - return (fn) => - async (...args) => { - const originalResult = await fn(...args) - const traceResult = await composable(traceFn)(originalResult, ...args) - if (traceResult.success) return originalResult + return (fn) => async (...args) => { + const originalResult = await fn(...args) + const traceResult = await composable(traceFn)(originalResult, ...args) + if (traceResult.success) return originalResult - return failure(traceResult.errors) - } + return failure(traceResult.errors) + } } /** diff --git a/src/environment/tests/branch.test.ts b/src/environment/tests/branch.test.ts index 00fffdf5..d510f332 100644 --- a/src/environment/tests/branch.test.ts +++ b/src/environment/tests/branch.test.ts @@ -54,8 +54,9 @@ describe('branch', () => { })) const b = withSchema(z.object({ id: z.number() }))(({ id }) => String(id)) const c = withSchema(z.object({ id: z.number() }))(({ id }) => id * 2) - const d = environment.branch(a, (output) => - output.next === 'multiply' ? c : b, + const d = environment.branch( + a, + (output) => output.next === 'multiply' ? c : b, ) type _R = Expect< Equal< diff --git a/src/index.ts b/src/index.ts index 11efb293..e008bf85 100644 --- a/src/index.ts +++ b/src/index.ts @@ -48,6 +48,7 @@ export type { FailToCompose, Failure, IncompatibleArguments, + MapParametersReturn, MergeObjects, ParserSchema, PipeReturn, diff --git a/src/internal/types.ts b/src/internal/types.ts index 9136ca58..91281759 100644 --- a/src/internal/types.ts +++ b/src/internal/types.ts @@ -8,8 +8,7 @@ namespace Internal { export type IsIncompatible = Internal.CommonSubType< A, B - > extends IncompatibleArguments - ? true + > extends IncompatibleArguments ? true : false export type FailToCompose = IncompatibleArguments & { @@ -17,10 +16,11 @@ namespace Internal { argument2: B } - export type Prettify = { - [K in keyof T]: T[K] - // deno-lint-ignore ban-types - } & {} + export type Prettify = + & { + [K in keyof T]: T[K] + } + & {} export type IsNever = // prettier-ignore @@ -41,12 +41,10 @@ namespace Internal { // This will not preserve union order but we don't care since this is for Composable paralel application export type UnionToTuple = ( (T extends any ? (t: T) => T : never) extends infer U - ? (U extends any ? (u: U) => any : never) extends (v: infer V) => any - ? V - : never + ? (U extends any ? (u: U) => any : never) extends (v: infer V) => any ? V + : never : never - ) extends (_: any) => infer W - ? [...UnionToTuple>, W] + ) extends (_: any) => infer W ? [...UnionToTuple>, W] : [] export type Keys> = UnionToTuple @@ -59,8 +57,8 @@ namespace Internal { ? Head extends string ? rest extends string[] ? RecordValuesFromKeysTuple - : never - : ValuesTuple + : never + : ValuesTuple : ValuesTuple export type Zip< @@ -73,90 +71,81 @@ namespace Internal { ? restK extends string[] ? restV extends unknown[] ? Prettify> - : V // in this case V has the CanComposeInParallel failure type - : never + : V // in this case V has the CanComposeInParallel failure type : never : never + : never : O export type EveryElementTakes = T extends [ infer HEAD, ...infer TAIL, - ] - ? U extends HEAD - ? EveryElementTakes - : FailToCompose + ] ? U extends HEAD ? EveryElementTakes + : FailToCompose : true export type SubtypesTuple< TupleA extends unknown[], TupleB extends unknown[], Output extends unknown[] = [], - > = TupleA extends [] - ? [...Output, ...TupleB] - : TupleB extends [] - ? [...Output, ...TupleA] + > = TupleA extends [] ? [...Output, ...TupleB] + : TupleB extends [] ? [...Output, ...TupleA] : TupleA extends [infer headA, ...infer restA] - ? TupleB extends [infer headB, ...infer restB] - ? IsIncompatible extends true - ? FailToCompose + ? TupleB extends [infer headB, ...infer restB] + ? IsIncompatible extends true + ? FailToCompose : SubtypesTuple]> - : // TupleB is partial - // We should handle partial case before recursion - TupleB extends Partial<[infer headPartial, ...infer restPartial]> - ? IsIncompatible extends true - ? FailToCompose + // TupleB is partial + // We should handle partial case before recursion + : TupleB extends Partial<[infer headPartial, ...infer restPartial]> + ? IsIncompatible extends true + ? FailToCompose : SubtypesTuple< - restA, - Partial, - [...Output, CommonSubType>] - > + restA, + Partial, + [...Output, CommonSubType>] + > : never : TupleB extends [infer headBNoA, ...infer restB] - ? // TupleA is partial - // We should handle partial case before recursion - TupleA extends Partial<[infer headPartial, ...infer restPartial]> - ? IsIncompatible extends true - ? FailToCompose + // TupleA is partial + // We should handle partial case before recursion + ? TupleA extends Partial<[infer headPartial, ...infer restPartial]> + ? IsIncompatible extends true + ? FailToCompose : SubtypesTuple< - restB, - Partial, - [...Output, CommonSubType>] - > + restB, + Partial, + [...Output, CommonSubType>] + > : never - : /* + /* * We should continue the recursion checking optional parameters * We can pattern match optionals using Partial * We should start handling partials as soon one side of mandatory ends * Remove ...TupleA, ...TupleB bellow */ - TupleA extends Partial<[infer headAPartial, ...infer restAPartial]> - ? TupleB extends Partial<[infer headBPartial, ...infer restBPartial]> - ? IsIncompatible extends true - ? SubtypesTuple< + : TupleA extends Partial<[infer headAPartial, ...infer restAPartial]> + ? TupleB extends Partial<[infer headBPartial, ...infer restBPartial]> + ? IsIncompatible extends true + ? SubtypesTuple< Partial, Partial, [...Output, ...Partial<[undefined]>] > : SubtypesTuple< - Partial, - Partial, - [...Output, ...Partial<[CommonSubType]>] - > + Partial, + Partial, + [...Output, ...Partial<[CommonSubType]>] + > : never : never - export type CommonSubType = [A] extends [B] - ? A - : [B] extends [A] - ? B - : A extends { 'Incompatible arguments ': true } - ? A - : B extends { 'Incompatible arguments ': true } - ? B + export type CommonSubType = [A] extends [B] ? A + : [B] extends [A] ? B + : A extends { 'Incompatible arguments ': true } ? A + : B extends { 'Incompatible arguments ': true } ? B : A extends Record - ? B extends Record - ? Prettify + ? B extends Record ? Prettify : FailToCompose : FailToCompose } diff --git a/src/tests/catch-failure.test.ts b/src/tests/catch-failure.test.ts index d86d1142..b9e59204 100644 --- a/src/tests/catch-failure.test.ts +++ b/src/tests/catch-failure.test.ts @@ -51,8 +51,9 @@ describe('catchFailure', () => { }) it('receives the list of errors as input to another function and returns a new composable', async () => { - const fn = catchFailure(faultyAdd, (errors, a, b) => - errors.length > 1 ? NaN : a + b, + const fn = catchFailure( + faultyAdd, + (errors, a, b) => errors.length > 1 ? NaN : a + b, ) const res = await fn(1, 2) diff --git a/src/tests/errors.test.ts b/src/tests/errors.test.ts index 62571f4d..12ed3955 100644 --- a/src/tests/errors.test.ts +++ b/src/tests/errors.test.ts @@ -1,9 +1,9 @@ import { assertEquals, describe, it } from './prelude.ts' import { - isInputError, - isEnvironmentError, - InputError, EnvironmentError, + InputError, + isEnvironmentError, + isInputError, } from '../index.ts' describe('isInputError', () => { diff --git a/src/tests/map-errors.test.ts b/src/tests/map-errors.test.ts index b5c62e60..70ed4f16 100644 --- a/src/tests/map-errors.test.ts +++ b/src/tests/map-errors.test.ts @@ -39,8 +39,9 @@ describe('mapErrors', () => { }) it('accepts an async mapper', async () => { - const fn = mapErrors(faultyAdd, (errors) => - Promise.resolve(errors.map(cleanError)), + const fn = mapErrors( + faultyAdd, + (errors) => Promise.resolve(errors.map(cleanError)), ) const res = await fn(1, 2) diff --git a/src/tests/types.test.ts b/src/tests/types.test.ts index 191c8b09..89b73f47 100644 --- a/src/tests/types.test.ts +++ b/src/tests/types.test.ts @@ -1,8 +1,8 @@ // deno-lint-ignore-file no-namespace ban-ts-comment import { withSchema } from '../index.ts' import { assertEquals, describe, it } from './prelude.ts' -import * as Subject from '../types.ts' -import { Internal } from '../internal/types.ts' +import type * as Subject from '../types.ts' +import type { Internal } from '../internal/types.ts' namespace MergeObjects { const obj1 = { a: 1, b: 2 } as const diff --git a/src/types.ts b/src/types.ts index 081db0be..e00c3c83 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,4 +1,4 @@ -import { Internal } from './internal/types.ts' +import type { Internal } from './internal/types.ts' /** * The failure case of a Result. @@ -208,12 +208,31 @@ type BranchReturn< : CanComposeInSequence<[SourceComposable, Awaited>]> : CanComposeInSequence<[SourceComposable, Composable]> -type ApplySchemaReturn = - ParsedInput extends Parameters[0] - ? ParsedEnvironment extends Parameters[1] - ? ComposableWithSchema> - : FailToCompose[1]> - : FailToCompose[0]> +/** + * Ensure that schemas are compatible with composable input and environment otherwise return a FailToCompose. + */ +type ApplySchemaReturn< + ParsedInput, + ParsedEnvironment, + Fn extends Composable, +> = ParsedInput extends Parameters[0] + ? ParsedEnvironment extends Parameters[1] + ? ComposableWithSchema> + : FailToCompose[1]> + : FailToCompose[0]> + +/** + * The return type of the mapParameters function + */ +type MapParametersReturn< + Fn extends Composable, + NewParams extends any[], + O extends Parameters, +> = Composable< + ( + ...args: NewParams + ) => Internal.IsNever extends true ? never : UnpackData +> // Re-exporting internal types /** @@ -236,6 +255,7 @@ export type { Failure, IncompatibleArguments, Last, + MapParametersReturn, MergeObjects, ParserSchema, PipeReturn,