Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: Tidy up docs and return types #149

Merged
merged 1 commit into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading