composable-functions
Advanced tools
Comparing version 0.0.0-experimental-20240419-1 to 0.0.0-experimental-20240422-1
{ | ||
"name": "composable-functions", | ||
"version": "0.0.0-experimental-20240419-1", | ||
"version": "0.0.0-experimental-20240422-1", | ||
"description": "Decouple your business logic from your controllers. With first-class type inference from end to end.", | ||
@@ -5,0 +5,0 @@ "author": "Seasoned", |
@@ -1,2 +0,6 @@ | ||
# Composable Functions | ||
<picture> | ||
<source media="(prefers-color-scheme: dark)" srcset="https://github.com/seasonedcc/composable-functions/assets/566971/c6534a6a-fcf1-4e70-93bf-c72a2f661ba5"> | ||
<source media="(prefers-color-scheme: light)" srcset="https://github.com/seasonedcc/composable-functions/assets/566971/17048e80-271a-4c8b-9914-7bd10fba5e42"> | ||
<img alt="Composable Functions" src="https://user-images.githubusercontent.com/25423296/163456779-a8556205-d0a5-45e2-ac17-42d089e3c3f8.png](https://github.com/seasonedcc/composable-functions/assets/566971/17048e80-271a-4c8b-9914-7bd10fba5e42"> | ||
</picture> | ||
@@ -3,0 +7,0 @@ ## Quickstart |
@@ -1,2 +0,2 @@ | ||
import type { AllArguments, CollectArguments, Composable, MergeObjs, PipeArguments, PipeReturn, RecordToTuple, Result, UnpackAll, UnpackData } from './types.js'; | ||
import type { AllArguments, Composable, MergeObjs, PipeArguments, PipeReturn, RecordToTuple, Result, UnpackAll, UnpackData } from './types.js'; | ||
/** | ||
@@ -29,3 +29,3 @@ * Merges a list of objects into a single object. | ||
*/ | ||
declare function pipe<Fns extends [Composable, ...Composable[]]>(...fns: Fns & PipeArguments<Fns>): PipeReturn<Fns>; | ||
declare function pipe<Fns extends [Composable, ...Composable[]]>(...fns: Fns): PipeReturn<PipeArguments<Fns>>; | ||
/** | ||
@@ -42,3 +42,3 @@ * Creates a single function out of multiple Composables. It will pass the same input to each provided function. The functions will run in parallel. If all constituent functions are successful, The data field will be a tuple containing each function's output. | ||
*/ | ||
declare function all<Fns extends Composable[]>(...fns: Fns & AllArguments<Fns>): Composable<(...args: Parameters<AllArguments<Fns>[0]>) => { [k in keyof Fns]: UnpackData<Fns[k]>; }>; | ||
declare function all<Fns extends Composable[]>(...fns: Fns): Composable<(...args: Parameters<NonNullable<AllArguments<Fns>[0]>>) => { [k in keyof Fns]: UnpackData<Fns[k]>; }>; | ||
/** | ||
@@ -54,3 +54,3 @@ * Receives a Record of Composables, runs them all in parallel and preserves the shape of this record for the data property in successful results. | ||
*/ | ||
declare function collect<Fns extends Record<string, Composable>>(fns: Fns & CollectArguments<Fns>): Composable<(...args: Parameters<AllArguments<RecordToTuple<Fns>>[0]>) => { [key in keyof Fns]: UnpackData<Fns[key]>; }>; | ||
declare function collect<Fns extends Record<string, Composable>>(fns: Fns): Composable<(...args: Parameters<Exclude<AllArguments<RecordToTuple<Fns>>[0], undefined>>) => { [key in keyof Fns]: UnpackData<Fns[key]>; }>; | ||
/** | ||
@@ -66,3 +66,3 @@ * Works like `pipe` but it will collect the output of every function in a tuple. | ||
*/ | ||
declare function sequence<Fn extends [Composable, ...Composable[]]>(...fns: Fn & PipeArguments<Fn>): Composable<(...args: Parameters<Fn[0]>) => UnpackAll<Fn>>; | ||
declare function sequence<Fns extends [Composable, ...Composable[]]>(...fns: Fns): Composable<(...args: Parameters<Fns[0]>) => UnpackAll<Fns>>; | ||
/** | ||
@@ -88,4 +88,4 @@ * It takes a Composable and a predicate to apply a transformation over the resulting `data`. It only runs if the function was successfull. When the given function fails, its error is returned wihout changes. | ||
*/ | ||
declare function merge<Fn extends Composable[]>(...fns: Fn & AllArguments<Fn>): Composable<(...args: Parameters<AllArguments<Fn>[0]>) => MergeObjs<{ | ||
[key in keyof Fn]: UnpackData<Fn[key]>; | ||
declare function merge<Fns extends Composable[]>(...fns: Fns): Composable<(...args: Parameters<NonNullable<AllArguments<Fns>[0]>>) => MergeObjs<{ | ||
[key in keyof Fns]: UnpackData<Fns[key]>; | ||
}>>; | ||
@@ -102,3 +102,3 @@ /** | ||
*/ | ||
declare function first<Fn extends Composable[]>(...fns: Fn & AllArguments<Fn>): Composable<(...args: Parameters<AllArguments<Fn>[0]>) => UnpackData<Fn[number]>>; | ||
declare function first<Fns extends Composable[]>(...fns: Fns): Composable<(...args: Parameters<NonNullable<AllArguments<Fns>[0]>>) => UnpackData<Fns[number]>>; | ||
/** | ||
@@ -105,0 +105,0 @@ * Creates a new function that will try to recover from a resulting Failure. When the given function succeeds, its result is returned without changes. |
declare namespace Internal { | ||
type IncompatibleArguments<A, B> = { | ||
'Incompatible arguments ': true; | ||
argument1: A; | ||
argument2: B; | ||
}; | ||
type IsIncompatible<A, B> = Internal.CommonSubType<A, B> extends { | ||
'Incompatible arguments ': true; | ||
} ? true : false; | ||
type FailToCompose<A, B> = ['Fail to compose', A, 'does not fit in', B]; | ||
type Prettify<T> = { | ||
@@ -15,18 +24,10 @@ [K in keyof T]: T[K]; | ||
...infer TAIL | ||
] ? U extends HEAD ? EveryElementTakes<TAIL, U> : ['Fail to compose', undefined, 'does not fit in', HEAD] : true; | ||
type SubtypesTuple<TupleA extends unknown[], TupleB extends unknown[], Output extends unknown[] = []> = TupleA extends [] ? [...Output, ...TupleB] : TupleB extends [] ? [...Output, ...TupleA] : TupleA extends [infer headA, ...infer restA] ? TupleB extends [infer headB, ...infer restB] ? CommonSubType<headA, headB> extends { | ||
'Incompatible arguments ': true; | ||
} ? CommonSubType<headA, headB> : SubtypesTuple<restA, restB, [...Output, CommonSubType<headA, headB>]> : TupleB extends Partial<[infer headPartial, ...infer restPartial]> ? CommonSubType<headA, headPartial> extends { | ||
'Incompatible arguments ': true; | ||
} ? CommonSubType<headA, headPartial> : SubtypesTuple<restA, restPartial, [ | ||
] ? U extends HEAD ? EveryElementTakes<TAIL, U> : FailToCompose<undefined, HEAD> : true; | ||
type SubtypesTuple<TupleA extends unknown[], TupleB extends unknown[], Output extends unknown[] = []> = 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 ? IncompatibleArguments<headA, headB> : SubtypesTuple<restA, restB, [...Output, CommonSubType<headA, headB>]> : TupleB extends Partial<[infer headPartial, ...infer restPartial]> ? IsIncompatible<headA, headPartial> extends true ? IncompatibleArguments<headA, headPartial> : SubtypesTuple<restA, Partial<restPartial>, [ | ||
...Output, | ||
CommonSubType<headA, headPartial> | ||
]> : never : TupleB extends [infer headBNoA, ...infer restB] ? TupleA extends Partial<[infer headPartial, ...infer restPartial]> ? CommonSubType<headBNoA, headPartial> extends { | ||
'Incompatible arguments ': true; | ||
} ? CommonSubType<headBNoA, headPartial> : SubtypesTuple<restB, restPartial, [ | ||
CommonSubType<headA, Partial<headPartial>> | ||
]> : never : TupleB extends [infer headBNoA, ...infer restB] ? TupleA extends Partial<[infer headPartial, ...infer restPartial]> ? IsIncompatible<headBNoA, headPartial> extends true ? IncompatibleArguments<headBNoA, headPartial> : SubtypesTuple<restB, Partial<restPartial>, [ | ||
...Output, | ||
CommonSubType<headBNoA, headPartial> | ||
]> : never : TupleA extends Partial<[infer headAPartial, ...infer restAPartial]> ? TupleB extends Partial<[infer headBPartial, ...infer restBPartial]> ? CommonSubType<headAPartial, headBPartial> extends { | ||
'Incompatible arguments ': true; | ||
} ? SubtypesTuple<Partial<restAPartial>, Partial<restBPartial>, [ | ||
CommonSubType<headBNoA, Partial<headPartial>> | ||
]> : never : 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, | ||
@@ -38,12 +39,4 @@ ...Partial<[undefined]> | ||
]> : never : never; | ||
type CommonSubType<A, B> = [A] extends [B] ? A : [B] extends [A] ? B : A extends Record<PropertyKey, any> ? B extends Record<PropertyKey, any> ? Prettify<A & B> : { | ||
'Incompatible arguments ': true; | ||
argument1: A; | ||
argument2: B; | ||
} : { | ||
'Incompatible arguments ': true; | ||
argument1: A; | ||
argument2: B; | ||
}; | ||
type CommonSubType<A, B> = [A] extends [B] ? A : [B] extends [A] ? B : A extends Record<PropertyKey, any> ? B extends Record<PropertyKey, any> ? Prettify<A & B> : IncompatibleArguments<A, B> : IncompatibleArguments<A, B>; | ||
} | ||
export type { Internal }; |
@@ -37,15 +37,12 @@ import { Internal } from './internal/types.js'; | ||
...infer rest | ||
] ? Internal.IsNever<OA> extends true ? ['Fail to compose, "never" does not fit in', PB] : Awaited<OA> extends PB ? PipeReturn<[Composable<(...args: PA) => OB>, ...rest]> : ['Fail to compose', Awaited<OA>, 'does not fit in', PB] : Fns extends [Composable<(...args: infer P) => infer O>] ? Composable<(...args: P) => O> : never; | ||
] ? Internal.IsNever<OA> extends true ? Internal.FailToCompose<never, PB> : Awaited<OA> extends PB ? PipeReturn<[Composable<(...args: PA) => OB>, ...rest]> : Internal.FailToCompose<Awaited<OA>, PB> : Fns extends [Composable<(...args: infer P) => infer O>] ? Composable<(...args: P) => O> : Fns; | ||
type PipeArguments<Fns extends any[], Arguments extends any[] = []> = Fns extends [Composable<(...a: infer PA) => infer OA>, ...infer restA] ? restA extends [ | ||
Composable<(firstParameter: infer FirstBParameter, ...b: infer PB) => any>, | ||
...unknown[] | ||
] ? Internal.IsNever<Awaited<OA>> extends true ? ['Fail to compose, "never" does not fit in', FirstBParameter] : Awaited<OA> extends FirstBParameter ? Internal.EveryElementTakes<PB, undefined> extends true ? PipeArguments<restA, [...Arguments, Composable<(...a: PA) => OA>]> : Internal.EveryElementTakes<PB, undefined> : ['Fail to compose', Awaited<OA>, 'does not fit in', FirstBParameter] : [...Arguments, Composable<(...a: PA) => OA>] : never; | ||
type AllArguments<Fns extends any[], Arguments extends any[] = []> = Fns extends [Composable<(...a: infer PA) => infer OA>, ...infer restA] ? restA extends [Composable<(...b: infer PB) => infer OB>, ...infer restB] ? Internal.SubtypesTuple<PA, PB, []> extends [...infer MergedP] ? AllArguments<[ | ||
] ? Internal.IsNever<Awaited<OA>> extends true ? Internal.FailToCompose<never, FirstBParameter> : Awaited<OA> extends FirstBParameter ? Internal.EveryElementTakes<PB, undefined> extends true ? PipeArguments<restA, [...Arguments, Composable<(...a: PA) => OA>]> : Internal.EveryElementTakes<PB, undefined> : Internal.FailToCompose<Awaited<OA>, FirstBParameter> : [...Arguments, Composable<(...a: PA) => OA>] : never; | ||
type AllArguments<Fns extends any[], OriginalFns extends any[] = Fns> = Fns extends [Composable<(...a: infer PA) => any>, ...infer restA] ? restA extends [Composable<(...b: infer PB) => infer OB>, ...infer restB] ? Internal.SubtypesTuple<PA, PB> extends [...infer MergedP] ? AllArguments<[ | ||
Composable<(...args: MergedP) => OB>, | ||
...restB | ||
], [ | ||
...Arguments, | ||
Composable<(...a: MergedP) => OA> | ||
]> : ['Fail to compose', PA, 'does not fit in', PB] : [...Arguments, Composable<(...a: PA) => OA>] : never; | ||
type CollectArguments<T extends Record<string, Composable>> = AllArguments<Internal.UnionToTuple<T[keyof T]>> extends ['Fail to compose', ...any[]] ? AllArguments<Internal.UnionToTuple<T[keyof T]>> : Internal.Zip<Internal.Keys<T>, AllArguments<Internal.UnionToTuple<T[keyof T]>>>; | ||
], OriginalFns> : Internal.FailToCompose<PA, PB> : ApplyArgumentsToFns<OriginalFns, PA> : never; | ||
type ApplyArgumentsToFns<Fns extends any[], Args extends any[], Output extends any[] = []> = Fns extends [(...a: any[]) => infer OA, ...infer restA] ? ApplyArgumentsToFns<restA, Args, [...Output, (...a: Args) => OA]> : Output; | ||
type RecordToTuple<T extends Record<string, Composable>> = Internal.RecordValuesFromKeysTuple<T, Internal.Keys<T>>; | ||
@@ -80,2 +77,2 @@ type SerializableError<T extends Error = Error> = { | ||
type Last<T extends readonly unknown[]> = T extends [...infer _I, infer L] ? L : never; | ||
export type { AllArguments, CollectArguments, Composable, Failure, Last, MergeObjs, ParserSchema, PipeArguments, PipeReturn, RecordToTuple, Result, SerializableError, SerializedResult, Success, UnpackAll, UnpackData, }; | ||
export type { AllArguments, Composable, Failure, Last, MergeObjs, ParserSchema, PipeArguments, PipeReturn, RecordToTuple, Result, SerializableError, SerializedResult, Success, UnpackAll, UnpackData, }; |
97762
179
1973