Skip to content

Commit

Permalink
Merge pull request #149 from seasonedcc/tidy-up-docs-and-return-types
Browse files Browse the repository at this point in the history
docs: Tidy up docs and return types
  • Loading branch information
diogob authored Jun 12, 2024
2 parents 1a0f5e7 + 960adba commit 302cbea
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 100 deletions.
32 changes: 13 additions & 19 deletions src/combinators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type {
CanComposeInSequence,
Composable,
Last,
MapParametersReturn,
MergeObjects,
PipeReturn,
RecordToTuple,
Expand All @@ -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.
Expand Down Expand Up @@ -139,7 +139,7 @@ function collect<Fns extends Record<string, Composable>>(
}
> {
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<
(
Expand Down Expand Up @@ -234,15 +234,11 @@ function map<Fn extends Composable, O>(
function mapParameters<
Fn extends Composable,
NewParameters extends unknown[],
const O extends Parameters<Fn>,
const MapperOutput extends Parameters<Fn>,
>(
fn: Fn,
mapper: (...args: NewParameters) => Promise<O> | O,
): Composable<
(
...args: NewParameters
) => Internal.IsNever<Awaited<O>> extends true ? never : UnpackData<Fn>
> {
mapper: (...args: NewParameters) => Promise<MapperOutput> | MapperOutput,
): MapParametersReturn<Fn, NewParameters, MapperOutput> {
return async (...args) => {
const output = await composable(mapper)(...args)
if (!output.success) return failure(output.errors)
Expand Down Expand Up @@ -274,9 +270,8 @@ function catchFailure<
(
...args: Parameters<Fn>
) => Awaited<ReturnType<C>> extends never[]
? UnpackData<Fn> extends any[]
? UnpackData<Fn>
: Awaited<ReturnType<C>> | UnpackData<Fn>
? UnpackData<Fn> extends any[] ? UnpackData<Fn>
: Awaited<ReturnType<C>> | UnpackData<Fn>
: Awaited<ReturnType<C>> | UnpackData<Fn>
> {
return async (...args: Parameters<Fn>) => {
Expand Down Expand Up @@ -342,14 +337,13 @@ function trace(
): <P extends unknown[], Output>(
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)
}
}

/**
Expand Down
5 changes: 3 additions & 2 deletions src/environment/tests/branch.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export type {
FailToCompose,
Failure,
IncompatibleArguments,
MapParametersReturn,
MergeObjects,
ParserSchema,
PipeReturn,
Expand Down
115 changes: 52 additions & 63 deletions src/internal/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@ namespace Internal {
export type IsIncompatible<A, B> = Internal.CommonSubType<
A,
B
> extends IncompatibleArguments
? true
> extends IncompatibleArguments ? true
: false

export type FailToCompose<A, B> = IncompatibleArguments & {
argument1: A
argument2: B
}

export type Prettify<T> = {
[K in keyof T]: T[K]
// deno-lint-ignore ban-types
} & {}
export type Prettify<T> =
& {
[K in keyof T]: T[K]
}
& {}

export type IsNever<A> =
// prettier-ignore
Expand All @@ -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> = (
(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<Exclude<T, W>>, W]
) extends (_: any) => infer W ? [...UnionToTuple<Exclude<T, W>>, W]
: []

export type Keys<R extends Record<string, any>> = UnionToTuple<keyof R>
Expand All @@ -59,8 +57,8 @@ namespace Internal {
? Head extends string
? rest extends string[]
? RecordValuesFromKeysTuple<R, rest, [...ValuesTuple, R[Head]]>
: never
: ValuesTuple
: never
: ValuesTuple
: ValuesTuple

export type Zip<
Expand All @@ -73,90 +71,81 @@ namespace Internal {
? restK extends string[]
? restV extends unknown[]
? Prettify<Zip<restK, restV, O & { [key in HeadK]: HeadV }>>
: 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 any[], U> = T extends [
infer HEAD,
...infer TAIL,
]
? U extends HEAD
? EveryElementTakes<TAIL, U>
: FailToCompose<undefined, HEAD>
] ? U extends HEAD ? EveryElementTakes<TAIL, U>
: FailToCompose<undefined, HEAD>
: 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<headA, headB> extends true
? FailToCompose<headA, headB>
? TupleB extends [infer headB, ...infer restB]
? IsIncompatible<headA, headB> extends true
? FailToCompose<headA, headB>
: SubtypesTuple<restA, restB, [...Output, CommonSubType<headA, headB>]>
: // TupleB is partial
// We should handle partial case before recursion
TupleB extends Partial<[infer headPartial, ...infer restPartial]>
? IsIncompatible<headA, headPartial> extends true
? FailToCompose<headA, headPartial>
// TupleB is partial
// We should handle partial case before recursion
: TupleB extends Partial<[infer headPartial, ...infer restPartial]>
? IsIncompatible<headA, headPartial> extends true
? FailToCompose<headA, headPartial>
: SubtypesTuple<
restA,
Partial<restPartial>,
[...Output, CommonSubType<headA, Partial<headPartial>>]
>
restA,
Partial<restPartial>,
[...Output, CommonSubType<headA, Partial<headPartial>>]
>
: 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<headBNoA, headPartial> extends true
? FailToCompose<headBNoA, headPartial>
// TupleA is partial
// We should handle partial case before recursion
? TupleA extends Partial<[infer headPartial, ...infer restPartial]>
? IsIncompatible<headBNoA, headPartial> extends true
? FailToCompose<headBNoA, headPartial>
: SubtypesTuple<
restB,
Partial<restPartial>,
[...Output, CommonSubType<headBNoA, Partial<headPartial>>]
>
restB,
Partial<restPartial>,
[...Output, CommonSubType<headBNoA, Partial<headPartial>>]
>
: 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<headAPartial, headBPartial> extends true
? SubtypesTuple<
: TupleA extends Partial<[infer headAPartial, ...infer restAPartial]>
? TupleB extends Partial<[infer headBPartial, ...infer restBPartial]>
? IsIncompatible<headAPartial, headBPartial> extends true
? SubtypesTuple<
Partial<restAPartial>,
Partial<restBPartial>,
[...Output, ...Partial<[undefined]>]
>
: SubtypesTuple<
Partial<restAPartial>,
Partial<restBPartial>,
[...Output, ...Partial<[CommonSubType<headAPartial, headBPartial>]>]
>
Partial<restAPartial>,
Partial<restBPartial>,
[...Output, ...Partial<[CommonSubType<headAPartial, headBPartial>]>]
>
: never
: never

export type CommonSubType<A, B> = [A] extends [B]
? A
: [B] extends [A]
? B
: A extends { 'Incompatible arguments ': true }
? A
: B extends { 'Incompatible arguments ': true }
? B
export type CommonSubType<A, B> = [A] extends [B] ? A
: [B] extends [A] ? B
: A extends { 'Incompatible arguments ': true } ? A
: B extends { 'Incompatible arguments ': true } ? B
: A extends Record<PropertyKey, unknown>
? B extends Record<PropertyKey, unknown>
? Prettify<A & B>
? B extends Record<PropertyKey, unknown> ? Prettify<A & B>
: FailToCompose<A, B>
: FailToCompose<A, B>
}
Expand Down
5 changes: 3 additions & 2 deletions src/tests/catch-failure.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
6 changes: 3 additions & 3 deletions src/tests/errors.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { assertEquals, describe, it } from './prelude.ts'
import {
isInputError,
isEnvironmentError,
InputError,
EnvironmentError,
InputError,
isEnvironmentError,
isInputError,
} from '../index.ts'

describe('isInputError', () => {
Expand Down
5 changes: 3 additions & 2 deletions src/tests/map-errors.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
4 changes: 2 additions & 2 deletions src/tests/types.test.ts
Original file line number Diff line number Diff line change
@@ -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
Expand Down
34 changes: 27 additions & 7 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Internal } from './internal/types.ts'
import type { Internal } from './internal/types.ts'

/**
* The failure case of a Result.
Expand Down Expand Up @@ -208,12 +208,31 @@ type BranchReturn<
: CanComposeInSequence<[SourceComposable, Awaited<ReturnType<Resolver>>]>
: CanComposeInSequence<[SourceComposable, Composable<Resolver>]>

type ApplySchemaReturn<ParsedInput, ParsedEnvironment, Fn extends Composable> =
ParsedInput extends Parameters<Fn>[0]
? ParsedEnvironment extends Parameters<Fn>[1]
? ComposableWithSchema<UnpackData<Fn>>
: FailToCompose<ParsedEnvironment, Parameters<Fn>[1]>
: FailToCompose<ParsedInput, Parameters<Fn>[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<Fn>[0]
? ParsedEnvironment extends Parameters<Fn>[1]
? ComposableWithSchema<UnpackData<Fn>>
: FailToCompose<ParsedEnvironment, Parameters<Fn>[1]>
: FailToCompose<ParsedInput, Parameters<Fn>[0]>

/**
* The return type of the mapParameters function
*/
type MapParametersReturn<
Fn extends Composable,
NewParams extends any[],
O extends Parameters<Fn>,
> = Composable<
(
...args: NewParams
) => Internal.IsNever<O> extends true ? never : UnpackData<Fn>
>

// Re-exporting internal types
/**
Expand All @@ -236,6 +255,7 @@ export type {
Failure,
IncompatibleArguments,
Last,
MapParametersReturn,
MergeObjects,
ParserSchema,
PipeReturn,
Expand Down

0 comments on commit 302cbea

Please sign in to comment.