Comparing version 0.2.0 to 0.2.1
@@ -150,5 +150,4 @@ import { Effect } from "./types.js"; | ||
with: < | ||
H extends ( | ||
effected: EffectedDraft<E, E, R>, | ||
) => EffectedDraft<E, Effect, unknown>, | ||
S extends EffectedDraft<E, Effect, unknown>, | ||
H extends (effected: EffectedDraft<E, E, R>) => S, | ||
>( | ||
@@ -160,5 +159,4 @@ handler: H, | ||
with: < | ||
H extends <R>( | ||
effected: EffectedDraft<E, E, R>, | ||
) => EffectedDraft<E, Effect, unknown>, | ||
S extends EffectedDraft<E, Effect, unknown>, | ||
H extends <R>(effected: EffectedDraft<E, E, R>) => S, | ||
>( | ||
@@ -225,3 +223,3 @@ handler: H, | ||
...payloads: Payloads | ||
) => Effected<F, void> | ||
) => void | Generator<F, void, unknown> | Effected<F, void> | ||
: E extends Effect<Name, infer Payloads, infer R> ? | ||
@@ -239,3 +237,3 @@ ( | ||
...payloads: Payloads | ||
) => Effected<F, void> | ||
) => void | Generator<F, void, unknown> | Effected<F, void> | ||
: never, | ||
@@ -255,3 +253,3 @@ ): Effected<Exclude<E, Effect<Name>> | F, R | T>; | ||
...payloads: Payloads | ||
) => Effected<F, void> | ||
) => void | Generator<F, void, unknown> | Effected<F, void> | ||
: E extends Effect<Name, infer Payloads, infer R> ? | ||
@@ -269,117 +267,5 @@ ( | ||
...payloads: Payloads | ||
) => Effected<F, void> | ||
) => void | Generator<F, void, unknown> | Effected<F, void> | ||
: never, | ||
): Effected<Exclude<E, Effect<Name>> | F, R | T>; | ||
handle<Name extends E["name"], T = R, F extends Effect = never>( | ||
effect: Name, | ||
handler: E extends Unresumable<Effect<Name, infer Payloads>> ? | ||
( | ||
{ | ||
effect, | ||
terminate, | ||
}: { | ||
effect: Extract<E, Effect<Name>>; | ||
terminate: (value: T) => void; | ||
}, | ||
...payloads: Payloads | ||
) => Generator<F, void, unknown> | ||
: E extends Effect<Name, infer Payloads, infer R> ? | ||
( | ||
{ | ||
effect, | ||
resume, | ||
terminate, | ||
}: { | ||
effect: Extract<E, Effect<Name>>; | ||
resume: (value: R) => void; | ||
terminate: (value: T) => void; | ||
}, | ||
...payloads: Payloads | ||
) => Generator<F, void, unknown> | ||
: never, | ||
): Effected<Exclude<E, Effect<Name>> | F, R | T>; | ||
handle<Name extends string | symbol, T = R, F extends Effect = never>( | ||
effect: (name: E["name"]) => name is Name, | ||
handler: E extends Unresumable<Effect<Name, infer Payloads>> ? | ||
( | ||
{ | ||
effect, | ||
terminate, | ||
}: { | ||
effect: Extract<E, Effect<Name>>; | ||
terminate: (value: T) => void; | ||
}, | ||
...payloads: Payloads | ||
) => Generator<F, void, unknown> | ||
: E extends Effect<Name, infer Payloads, infer R> ? | ||
( | ||
{ | ||
effect, | ||
resume, | ||
terminate, | ||
}: { | ||
effect: Extract<E, Effect<Name>>; | ||
resume: (value: R) => void; | ||
terminate: (value: T) => void; | ||
}, | ||
...payloads: Payloads | ||
) => Generator<F, void, unknown> | ||
: never, | ||
): Effected<Exclude<E, Effect<Name>> | F, R | T>; | ||
handle<Name extends E["name"], T = R>( | ||
effect: Name, | ||
handler: E extends Unresumable<Effect<Name, infer Payloads>> ? | ||
( | ||
{ | ||
effect, | ||
terminate, | ||
}: { | ||
effect: Extract<E, Effect<Name>>; | ||
terminate: (value: T) => void; | ||
}, | ||
...payloads: Payloads | ||
) => void | ||
: E extends Effect<Name, infer Payloads, infer R> ? | ||
( | ||
{ | ||
effect, | ||
resume, | ||
terminate, | ||
}: { | ||
effect: Extract<E, Effect<Name>>; | ||
resume: (value: R) => void; | ||
terminate: (value: T) => void; | ||
}, | ||
...payloads: Payloads | ||
) => void | ||
: never, | ||
): Effected<Exclude<E, Effect<Name>>, R | T>; | ||
handle<Name extends string | symbol, T = R>( | ||
effect: (name: E["name"]) => name is Name, | ||
handler: E extends Unresumable<Effect<Name, infer Payloads>> ? | ||
( | ||
{ | ||
effect, | ||
terminate, | ||
}: { | ||
effect: Extract<E, Effect<Name>>; | ||
terminate: (value: T) => void; | ||
}, | ||
...payloads: Payloads | ||
) => void | ||
: E extends Effect<Name, infer Payloads, infer R> ? | ||
( | ||
{ | ||
effect, | ||
resume, | ||
terminate, | ||
}: { | ||
effect: Extract<E, Effect<Name>>; | ||
resume: (value: R) => void; | ||
terminate: (value: T) => void; | ||
}, | ||
...payloads: Payloads | ||
) => void | ||
: never, | ||
): Effected<Exclude<E, Effect<Name>>, R | T>; | ||
/** | ||
@@ -402,3 +288,3 @@ * Resume an effect with the return value of the handler. | ||
handler: E extends Effect<Name, infer Payloads, infer R> ? | ||
(...payloads: Payloads) => Effected<F, R> | ||
(...payloads: Payloads) => R | Generator<F, R, unknown> | Effected<F, R> | ||
: never, | ||
@@ -409,32 +295,5 @@ ): Effected<Exclude<E, Effect<Name>> | F, R>; | ||
handler: E extends Effect<Name, infer Payloads, infer R> ? | ||
(...payloads: Payloads) => Effected<F, R> | ||
(...payloads: Payloads) => R | Generator<F, R, unknown> | Effected<F, R> | ||
: never, | ||
): Effected<Exclude<E, Effect<Name>> | F, R>; | ||
resume< | ||
Name extends Exclude<E, Unresumable<Effect>>["name"], | ||
F extends Effect = never, | ||
>( | ||
effect: Name, | ||
handler: E extends Effect<Name, infer Payloads, infer R> ? | ||
(...payloads: Payloads) => Generator<F, R, unknown> | ||
: never, | ||
): Effected<Exclude<E, Effect<Name>> | F, R>; | ||
resume<Name extends string | symbol, F extends Effect = never>( | ||
effect: (name: Exclude<E, Unresumable<Effect>>["name"]) => name is Name, | ||
handler: E extends Effect<Name, infer Payloads, infer R> ? | ||
(...payloads: Payloads) => Generator<F, R, unknown> | ||
: never, | ||
): Effected<Exclude<E, Effect<Name>> | F, R>; | ||
resume<Name extends Exclude<E, Unresumable<Effect>>["name"]>( | ||
effect: Name, | ||
handler: E extends Effect<Name, infer Payloads, infer R> ? | ||
(...payloads: Payloads) => R | ||
: never, | ||
): Effected<Exclude<E, Effect<Name>>, R>; | ||
resume<Name extends string | symbol>( | ||
effect: (name: Exclude<E, Unresumable<Effect>>["name"]) => name is Name, | ||
handler: E extends Effect<Name, infer Payloads, infer R> ? | ||
(...payloads: Payloads) => R | ||
: never, | ||
): Effected<Exclude<E, Effect<Name>>, R>; | ||
/** | ||
@@ -454,3 +313,3 @@ * Terminate an effect with the return value of the handler. | ||
handler: E extends Effect<Name, infer Payloads> ? | ||
(...payloads: Payloads) => Effected<F, T> | ||
(...payloads: Payloads) => Generator<F, T, unknown> | Effected<F, T> | ||
: never, | ||
@@ -461,17 +320,5 @@ ): Effected<Exclude<E, Effect<Name>> | F, R | T>; | ||
handler: E extends Effect<Name, infer Payloads> ? | ||
(...payloads: Payloads) => Effected<F, T> | ||
(...payloads: Payloads) => Generator<F, T, unknown> | Effected<F, T> | ||
: never, | ||
): Effected<Exclude<E, Effect<Name>> | F, R | T>; | ||
terminate<Name extends E["name"], T, F extends Effect = never>( | ||
effect: Name, | ||
handler: E extends Effect<Name, infer Payloads> ? | ||
(...payloads: Payloads) => Generator<F, T, unknown> | ||
: never, | ||
): Effected<Exclude<E, Effect<Name>> | F, R | T>; | ||
terminate<Name extends string | symbol, T, F extends Effect = never>( | ||
effect: (name: E["name"]) => name is Name, | ||
handler: E extends Effect<Name, infer Payloads> ? | ||
(...payloads: Payloads) => Generator<F, T, unknown> | ||
: never, | ||
): Effected<Exclude<E, Effect<Name>> | F, R | T>; | ||
terminate<Name extends E["name"], T>( | ||
@@ -495,9 +342,18 @@ effect: Name, | ||
map<S, F extends Effect = never>( | ||
handler: (value: R) => Effected<F, S>, | ||
handler: (value: R) => Generator<F, S, unknown> | Effected<F, S>, | ||
): Effected<E | F, S>; | ||
map<S, F extends Effect = never>( | ||
handler: (value: R) => Generator<F, S, unknown>, | ||
): Effected<E | F, S>; | ||
map<S>(handler: (value: R) => S): Effected<E, S>; | ||
/** | ||
* Tap the return value of the effected program. | ||
* @param handler The function to tap the return value. | ||
* @returns | ||
* | ||
* @since 0.2.1 | ||
*/ | ||
tap<F extends Effect = never>( | ||
handler: ( | ||
value: R, | ||
) => void | Generator<F, void, unknown> | Effected<F, void>, | ||
): Effected<E | F, R>; | ||
/** | ||
* Catch an error effect with a handler. | ||
@@ -514,12 +370,4 @@ * | ||
effect: Name, | ||
handler: (message?: string) => Effected<F, T>, | ||
handler: (message?: string) => Generator<F, T, unknown> | Effected<F, T>, | ||
): Effected<Exclude<E, Effect.Error<Name>> | F, R | T>; | ||
catch<Name extends ErrorName<E>, T, F extends Effect = never>( | ||
effect: Name, | ||
handler: (message?: string) => Generator<F, T, unknown>, | ||
): Effected<Exclude<E, Effect.Error<Name>> | F, R | T>; | ||
catch<Name extends ErrorName<E>, T, F extends Effect = never>( | ||
effect: Name, | ||
handler: (message?: string) => Generator<F, T, unknown>, | ||
): Effected<Exclude<E, Effect.Error<Name>> | F, R | T>; | ||
catch<Name extends ErrorName<E>, T>( | ||
@@ -535,9 +383,6 @@ effect: Name, | ||
catchAll<T, F extends Effect = never>( | ||
handler: (error: ErrorName<E>, message?: string) => Effected<F, T>, | ||
): Effected<Exclude<E, Effect.Error> | F, R | T>; | ||
catchAll<T, F extends Effect = never>( | ||
handler: ( | ||
error: ErrorName<E>, | ||
message?: string, | ||
) => Generator<F, T, unknown>, | ||
) => Generator<F, T, unknown> | Effected<F, T>, | ||
): Effected<Exclude<E, Effect.Error> | F, R | T>; | ||
@@ -592,15 +437,6 @@ catchAll<T>( | ||
name: Name, | ||
getter: E extends Effect.Dependency<Name, infer R> ? () => Effected<F, R> | ||
: never, | ||
): Effected<Exclude<E, Effect.Dependency<Name>> | F, R>; | ||
provideBy<Name extends DependencyName<E>, F extends Effect = never>( | ||
name: Name, | ||
getter: E extends Effect.Dependency<Name, infer R> ? | ||
() => Generator<F, R, unknown> | ||
() => R | Generator<F, R, unknown> | Effected<F, R> | ||
: never, | ||
): Effected<Exclude<E, Effect.Dependency<Name>> | F, R>; | ||
provideBy<Name extends DependencyName<E>>( | ||
name: Name, | ||
getter: E extends Effect.Dependency<Name, infer R> ? () => R : never, | ||
): Effected<Exclude<E, Effect.Dependency<Name>>, R>; | ||
/** | ||
@@ -625,297 +461,123 @@ * Apply a handler to the effected program. | ||
> extends Iterable<E, R, unknown> { | ||
readonly handle: { | ||
<Name extends E["name"], T = R, F extends Effect = never>( | ||
effect: Name, | ||
handler: E extends Unresumable<Effect<Name, infer Payloads>> ? | ||
( | ||
{ | ||
effect, | ||
terminate, | ||
}: { | ||
effect: Extract<E, Effect<Name>>; | ||
terminate: (value: T) => void; | ||
}, | ||
...payloads: Payloads | ||
) => Effected<F, void> | ||
: E extends Effect<Name, infer Payloads, infer R> ? | ||
( | ||
{ | ||
effect, | ||
resume, | ||
terminate, | ||
}: { | ||
effect: Extract<E, Effect<Name>>; | ||
resume: (value: R) => void; | ||
terminate: (value: T) => void; | ||
}, | ||
...payloads: Payloads | ||
) => Effected<F, void> | ||
: never, | ||
): EffectedDraft<P, Exclude<E, Effect<Name>> | F, R | T>; | ||
<Name extends string | symbol, T = R, F extends Effect = never>( | ||
effect: (name: E["name"]) => name is Name, | ||
handler: E extends Unresumable<Effect<Name, infer Payloads>> ? | ||
( | ||
{ | ||
effect, | ||
terminate, | ||
}: { | ||
effect: Extract<E, Effect<Name>>; | ||
terminate: (value: T) => void; | ||
}, | ||
...payloads: Payloads | ||
) => Effected<F, void> | ||
: E extends Effect<Name, infer Payloads, infer R> ? | ||
( | ||
{ | ||
effect, | ||
resume, | ||
terminate, | ||
}: { | ||
effect: Extract<E, Effect<Name>>; | ||
resume: (value: R) => void; | ||
terminate: (value: T) => void; | ||
}, | ||
...payloads: Payloads | ||
) => Effected<F, void> | ||
: never, | ||
): EffectedDraft<P, Exclude<E, Effect<Name>> | F, R | T>; | ||
<Name extends E["name"], T = R, F extends Effect = never>( | ||
effect: Name, | ||
handler: E extends Unresumable<Effect<Name, infer Payloads>> ? | ||
( | ||
{ | ||
effect, | ||
terminate, | ||
}: { | ||
effect: Extract<E, Effect<Name>>; | ||
terminate: (value: T) => void; | ||
}, | ||
...payloads: Payloads | ||
) => Generator<F, void, unknown> | ||
: E extends Effect<Name, infer Payloads, infer R> ? | ||
( | ||
{ | ||
effect, | ||
resume, | ||
terminate, | ||
}: { | ||
effect: Extract<E, Effect<Name>>; | ||
resume: (value: R) => void; | ||
terminate: (value: T) => void; | ||
}, | ||
...payloads: Payloads | ||
) => Generator<F, void, unknown> | ||
: never, | ||
): EffectedDraft<P, Exclude<E, Effect<Name>> | F, R | T>; | ||
<Name extends string | symbol, T = R, F extends Effect = never>( | ||
effect: (name: E["name"]) => name is Name, | ||
handler: E extends Unresumable<Effect<Name, infer Payloads>> ? | ||
( | ||
{ | ||
effect, | ||
terminate, | ||
}: { | ||
effect: Extract<E, Effect<Name>>; | ||
terminate: (value: T) => void; | ||
}, | ||
...payloads: Payloads | ||
) => Generator<F, void, unknown> | ||
: E extends Effect<Name, infer Payloads, infer R> ? | ||
( | ||
{ | ||
effect, | ||
resume, | ||
terminate, | ||
}: { | ||
effect: Extract<E, Effect<Name>>; | ||
resume: (value: R) => void; | ||
terminate: (value: T) => void; | ||
}, | ||
...payloads: Payloads | ||
) => Generator<F, void, unknown> | ||
: never, | ||
): EffectedDraft<P, Exclude<E, Effect<Name>> | F, R | T>; | ||
<Name extends E["name"], T = R>( | ||
effect: Name, | ||
handler: E extends Unresumable<Effect<Name, infer Payloads>> ? | ||
( | ||
{ | ||
effect, | ||
terminate, | ||
}: { | ||
effect: Extract<E, Effect<Name>>; | ||
terminate: (value: T) => void; | ||
}, | ||
...payloads: Payloads | ||
) => void | ||
: E extends Effect<Name, infer Payloads, infer R> ? | ||
( | ||
{ | ||
effect, | ||
resume, | ||
terminate, | ||
}: { | ||
effect: Extract<E, Effect<Name>>; | ||
resume: (value: R) => void; | ||
terminate: (value: T) => void; | ||
}, | ||
...payloads: Payloads | ||
) => void | ||
: never, | ||
): EffectedDraft<P, Exclude<E, Effect<Name>>, R | T>; | ||
<Name extends string | symbol, T = R>( | ||
effect: (name: E["name"]) => name is Name, | ||
handler: E extends Unresumable<Effect<Name, infer Payloads>> ? | ||
( | ||
{ | ||
effect, | ||
terminate, | ||
}: { | ||
effect: Extract<E, Effect<Name>>; | ||
terminate: (value: T) => void; | ||
}, | ||
...payloads: Payloads | ||
) => void | ||
: E extends Effect<Name, infer Payloads, infer R> ? | ||
( | ||
{ | ||
effect, | ||
resume, | ||
terminate, | ||
}: { | ||
effect: Extract<E, Effect<Name>>; | ||
resume: (value: R) => void; | ||
terminate: (value: T) => void; | ||
}, | ||
...payloads: Payloads | ||
) => void | ||
: never, | ||
): EffectedDraft<P, Exclude<E, Effect<Name>>, R | T>; | ||
}; | ||
readonly resume: { | ||
< | ||
Name extends Exclude<E, Unresumable<Effect>>["name"], | ||
F extends Effect = never, | ||
>( | ||
effect: Name, | ||
handler: E extends Effect<Name, infer Payloads, infer R> ? | ||
(...payloads: Payloads) => Effected<F, R> | ||
: never, | ||
): EffectedDraft<P, Exclude<E, Effect<Name>> | F, R>; | ||
<Name extends string | symbol, F extends Effect = never>( | ||
effect: (name: Exclude<E, Unresumable<Effect>>["name"]) => name is Name, | ||
handler: E extends Effect<Name, infer Payloads, infer R> ? | ||
(...payloads: Payloads) => Effected<F, R> | ||
: never, | ||
): EffectedDraft<P, Exclude<E, Effect<Name>> | F, R>; | ||
< | ||
Name extends Exclude<E, Unresumable<Effect>>["name"], | ||
F extends Effect = never, | ||
>( | ||
effect: Name, | ||
handler: E extends Effect<Name, infer Payloads, infer R> ? | ||
(...payloads: Payloads) => Generator<F, R, unknown> | ||
: never, | ||
): EffectedDraft<P, Exclude<E, Effect<Name>> | F, R>; | ||
<Name extends string | symbol, F extends Effect = never>( | ||
effect: (name: Exclude<E, Unresumable<Effect>>["name"]) => name is Name, | ||
handler: E extends Effect<Name, infer Payloads, infer R> ? | ||
(...payloads: Payloads) => Generator<F, R, unknown> | ||
: never, | ||
): EffectedDraft<P, Exclude<E, Effect<Name>> | F, R>; | ||
<Name extends Exclude<E, Unresumable<Effect>>["name"]>( | ||
effect: Name, | ||
handler: E extends Effect<Name, infer Payloads, infer R> ? | ||
(...payloads: Payloads) => R | ||
: never, | ||
): EffectedDraft<P, Exclude<E, Effect<Name>>, R>; | ||
<Name extends string | symbol>( | ||
effect: (name: Exclude<E, Unresumable<Effect>>["name"]) => name is Name, | ||
handler: E extends Effect<Name, infer Payloads, infer R> ? | ||
(...payloads: Payloads) => R | ||
: never, | ||
): EffectedDraft<P, Exclude<E, Effect<Name>>, R>; | ||
}; | ||
readonly terminate: { | ||
<Name extends E["name"], T, F extends Effect = never>( | ||
effect: Name, | ||
handler: E extends Effect<Name, infer Payloads> ? | ||
(...payloads: Payloads) => Effected<F, T> | ||
: never, | ||
): EffectedDraft<P, Exclude<E, Effect<Name>> | F, R | T>; | ||
<Name extends string | symbol, T, F extends Effect = never>( | ||
effect: (name: E["name"]) => name is Name, | ||
handler: E extends Effect<Name, infer Payloads> ? | ||
(...payloads: Payloads) => Effected<F, T> | ||
: never, | ||
): EffectedDraft<P, Exclude<E, Effect<Name>> | F, R | T>; | ||
<Name extends E["name"], T, F extends Effect = never>( | ||
effect: Name, | ||
handler: E extends Effect<Name, infer Payloads> ? | ||
(...payloads: Payloads) => Generator<F, T, unknown> | ||
: never, | ||
): EffectedDraft<P, Exclude<E, Effect<Name>> | F, R | T>; | ||
<Name extends E["name"], T, F extends Effect = never>( | ||
effect: Name, | ||
handler: E extends Effect<Name, infer Payloads> ? | ||
(...payloads: Payloads) => Generator<F, T, unknown> | ||
: never, | ||
): EffectedDraft<P, Exclude<E, Effect<Name>> | F, R | T>; | ||
<Name extends string | symbol, T, F extends Effect = never>( | ||
effect: (name: E["name"]) => name is Name, | ||
handler: E extends Effect<Name, infer Payloads> ? | ||
(...payloads: Payloads) => Generator<F, T, unknown> | ||
: never, | ||
): EffectedDraft<P, Exclude<E, Effect<Name>> | F, R | T>; | ||
<Name extends E["name"], T>( | ||
effect: Name, | ||
handler: E extends Effect<Name, infer Payloads> ? | ||
(...payloads: Payloads) => T | ||
: never, | ||
): EffectedDraft<P, Exclude<E, Effect<Name>>, R | T>; | ||
<Name extends string | symbol, T>( | ||
effect: (name: E["name"]) => name is Name, | ||
handler: E extends Effect<Name, infer Payloads> ? | ||
(...payloads: Payloads) => T | ||
: never, | ||
): EffectedDraft<P, Exclude<E, Effect<Name>>, R | T>; | ||
}; | ||
readonly map: { | ||
<S, F extends Effect = never>( | ||
handler: (value: R) => Effected<F, S>, | ||
): EffectedDraft<P, E | F, S>; | ||
<S, F extends Effect = never>( | ||
handler: (value: R) => Generator<F, S, unknown>, | ||
): EffectedDraft<P, E | F, S>; | ||
<S>(handler: (value: R) => S): EffectedDraft<P, E, S>; | ||
}; | ||
readonly catch: { | ||
<Name extends ErrorName<E>, T, F extends Effect = never>( | ||
effect: Name, | ||
handler: (message?: string) => Effected<F, T>, | ||
): EffectedDraft<P, Exclude<E, Effect.Error<Name>> | F, R | T>; | ||
<Name extends ErrorName<E>, T, F extends Effect = never>( | ||
effect: Name, | ||
handler: (message?: string) => Generator<F, T, unknown>, | ||
): EffectedDraft<P, Exclude<E, Effect.Error<Name>> | F, R | T>; | ||
<Name extends ErrorName<E>, T>( | ||
effect: Name, | ||
handler: (message?: string) => T, | ||
): EffectedDraft<P, Exclude<E, Effect.Error<Name>>, R | T>; | ||
}; | ||
readonly catchAll: { | ||
<T, F extends Effect = never>( | ||
handler: (effect: ErrorName<E>, message?: string) => Effected<F, T>, | ||
): Effected<Exclude<E, Effect.Error> | F, R | T>; | ||
<T, F extends Effect = never>( | ||
handler: ( | ||
effect: ErrorName<E>, | ||
message?: string, | ||
) => Generator<F, T, unknown>, | ||
): Effected<Exclude<E, Effect.Error> | F, R | T>; | ||
<T>( | ||
handler: (effect: ErrorName<E>, message?: string) => T, | ||
): Effected<Exclude<E, Effect.Error>, R | T>; | ||
}; | ||
handle<Name extends E["name"], T = R, F extends Effect = never>( | ||
effect: Name, | ||
handler: E extends Unresumable<Effect<Name, infer Payloads>> ? | ||
( | ||
{ | ||
effect, | ||
terminate, | ||
}: { | ||
effect: Extract<E, Effect<Name>>; | ||
terminate: (value: T) => void; | ||
}, | ||
...payloads: Payloads | ||
) => void | Generator<F, void, unknown> | Effected<F, void> | ||
: E extends Effect<Name, infer Payloads, infer R> ? | ||
( | ||
{ | ||
effect, | ||
resume, | ||
terminate, | ||
}: { | ||
effect: Extract<E, Effect<Name>>; | ||
resume: (value: R) => void; | ||
terminate: (value: T) => void; | ||
}, | ||
...payloads: Payloads | ||
) => void | Generator<F, void, unknown> | Effected<F, void> | ||
: never, | ||
): EffectedDraft<P, Exclude<E, Effect<Name>> | F, R | T>; | ||
handle<Name extends string | symbol, T = R, F extends Effect = never>( | ||
effect: (name: E["name"]) => name is Name, | ||
handler: E extends Unresumable<Effect<Name, infer Payloads>> ? | ||
( | ||
{ | ||
effect, | ||
terminate, | ||
}: { | ||
effect: Extract<E, Effect<Name>>; | ||
terminate: (value: T) => void; | ||
}, | ||
...payloads: Payloads | ||
) => void | Generator<F, void, unknown> | Effected<F, void> | ||
: E extends Effect<Name, infer Payloads, infer R> ? | ||
( | ||
{ | ||
effect, | ||
resume, | ||
terminate, | ||
}: { | ||
effect: Extract<E, Effect<Name>>; | ||
resume: (value: R) => void; | ||
terminate: (value: T) => void; | ||
}, | ||
...payloads: Payloads | ||
) => void | Generator<F, void, unknown> | Effected<F, void> | ||
: never, | ||
): EffectedDraft<P, Exclude<E, Effect<Name>> | F, R | T>; | ||
resume< | ||
Name extends Exclude<E, Unresumable<Effect>>["name"], | ||
F extends Effect = never, | ||
>( | ||
effect: Name, | ||
handler: E extends Effect<Name, infer Payloads, infer R> ? | ||
(...payloads: Payloads) => R | Generator<F, R, unknown> | Effected<F, R> | ||
: never, | ||
): EffectedDraft<P, Exclude<E, Effect<Name>> | F, R>; | ||
resume<Name extends string | symbol, F extends Effect = never>( | ||
effect: (name: Exclude<E, Unresumable<Effect>>["name"]) => name is Name, | ||
handler: E extends Effect<Name, infer Payloads, infer R> ? | ||
(...payloads: Payloads) => R | Generator<F, R, unknown> | Effected<F, R> | ||
: never, | ||
): EffectedDraft<P, Exclude<E, Effect<Name>> | F, R>; | ||
terminate<Name extends E["name"], T, F extends Effect = never>( | ||
effect: Name, | ||
handler: E extends Effect<Name, infer Payloads> ? | ||
(...payloads: Payloads) => Generator<F, T, unknown> | Effected<F, T> | ||
: never, | ||
): EffectedDraft<P, Exclude<E, Effect<Name>> | F, R | T>; | ||
terminate<Name extends string | symbol, T, F extends Effect = never>( | ||
effect: (name: E["name"]) => name is Name, | ||
handler: E extends Effect<Name, infer Payloads> ? | ||
(...payloads: Payloads) => Generator<F, T, unknown> | Effected<F, T> | ||
: never, | ||
): EffectedDraft<P, Exclude<E, Effect<Name>> | F, R | T>; | ||
terminate<Name extends E["name"], T>( | ||
effect: Name, | ||
handler: E extends Effect<Name, infer Payloads> ? | ||
(...payloads: Payloads) => T | ||
: never, | ||
): EffectedDraft<P, Exclude<E, Effect<Name>>, R | T>; | ||
terminate<Name extends string | symbol, T>( | ||
effect: (name: E["name"]) => name is Name, | ||
handler: E extends Effect<Name, infer Payloads> ? | ||
(...payloads: Payloads) => T | ||
: never, | ||
): EffectedDraft<P, Exclude<E, Effect<Name>>, R | T>; | ||
map<S, F extends Effect = never>( | ||
handler: (value: R) => Generator<F, S, unknown> | Effected<F, S>, | ||
): EffectedDraft<P, E | F, S>; | ||
map<S>(handler: (value: R) => S): EffectedDraft<P, E, S>; | ||
tap<F extends Effect = never>( | ||
handler: ( | ||
value: R, | ||
) => void | Generator<F, void, unknown> | Effected<F, void>, | ||
): EffectedDraft<P, E | F, R>; | ||
catch<Name extends ErrorName<E>, T, F extends Effect = never>( | ||
effect: Name, | ||
handler: (message?: string) => Generator<F, T, unknown> | Effected<F, T>, | ||
): EffectedDraft<P, Exclude<E, Effect.Error<Name>> | F, R | T>; | ||
catch<Name extends ErrorName<E>, T>( | ||
effect: Name, | ||
handler: (message?: string) => T, | ||
): EffectedDraft<P, Exclude<E, Effect.Error<Name>>, R | T>; | ||
catchAll<T, F extends Effect = never>( | ||
handler: ( | ||
effect: ErrorName<E>, | ||
message?: string, | ||
) => Generator<F, T, unknown> | Effected<F, T>, | ||
): Effected<Exclude<E, Effect.Error> | F, R | T>; | ||
catchAll<T>( | ||
handler: (effect: ErrorName<E>, message?: string) => T, | ||
): Effected<Exclude<E, Effect.Error>, R | T>; | ||
readonly catchAndThrow: <Name extends ErrorName<E>>( | ||
@@ -934,29 +596,16 @@ name: Name, | ||
) => EffectedDraft<P, Exclude<E, Effect.Dependency<Name>>, R>; | ||
readonly provideBy: { | ||
<Name extends DependencyName<E>, F extends Effect = never>( | ||
name: Name, | ||
getter: E extends Effect.Dependency<Name, infer R> ? () => Effected<F, R> | ||
: never, | ||
): EffectedDraft<P, Exclude<E, Effect.Dependency<Name>> | F, R>; | ||
<Name extends DependencyName<E>, F extends Effect = never>( | ||
name: Name, | ||
getter: E extends Effect.Dependency<Name, infer R> ? | ||
() => Generator<F, R, unknown> | ||
: never, | ||
): EffectedDraft<P, Exclude<E, Effect.Dependency<Name>> | F, R>; | ||
<Name extends DependencyName<E>>( | ||
name: Name, | ||
getter: E extends Effect.Dependency<Name, infer R> ? () => R : never, | ||
): EffectedDraft<P, Exclude<E, Effect.Dependency<Name>>, R>; | ||
}; | ||
readonly with: { | ||
<F extends Effect, G extends Effect, S>( | ||
handler: ( | ||
effected: EffectedDraft<never, never, R>, | ||
) => EffectedDraft<F, G, S>, | ||
): EffectedDraft<P, Exclude<E, F> | G, S>; | ||
<F extends Effect, S>( | ||
handler: (effected: Effected<E, R>) => Effected<F, S>, | ||
): EffectedDraft<P, F, S>; | ||
}; | ||
provideBy<Name extends DependencyName<E>, F extends Effect = never>( | ||
name: Name, | ||
getter: E extends Effect.Dependency<Name, infer R> ? | ||
() => R | Generator<F, R, unknown> | Effected<F, R> | ||
: never, | ||
): EffectedDraft<P, Exclude<E, Effect.Dependency<Name>> | F, R>; | ||
with<F extends Effect, G extends Effect, S>( | ||
handler: ( | ||
effected: EffectedDraft<never, never, R>, | ||
) => EffectedDraft<F, G, S>, | ||
): EffectedDraft<P, Exclude<E, F> | G, S>; | ||
with<F extends Effect, S>( | ||
handler: (effected: Effected<E, R>) => Effected<F, S>, | ||
): EffectedDraft<P, F, S>; | ||
} | ||
@@ -963,0 +612,0 @@ /** |
120
effected.js
@@ -67,3 +67,3 @@ import { UnhandledEffectError } from "./errors.js"; | ||
result, | ||
typeof name === "string" ? name : name.description || "", | ||
typeof name === "string" ? name : name.toString().slice(7, -1) || "", | ||
); | ||
@@ -156,3 +156,3 @@ } | ||
) | ||
console.warn( | ||
logger.warn( | ||
"You should not call the constructor of `Effected` directly. Use `effected` instead.", | ||
@@ -256,3 +256,3 @@ ); | ||
message += "). Only the first handler will be used."; | ||
console.warn(message); | ||
logger.warn(message); | ||
}; | ||
@@ -321,10 +321,14 @@ const resume = (...args) => { | ||
!(handlerResult instanceof Effected) && | ||
!isGenerator(handlerResult) | ||
!isGenerator(handlerResult) && | ||
!isEffectedIterator(handlerResult) | ||
) | ||
return { done: false, value: constructHandledEffect() }; | ||
const it = handlerResult[Symbol.iterator](); | ||
const iter = | ||
Symbol.iterator in handlerResult ? | ||
handlerResult[Symbol.iterator]() | ||
: handlerResult; | ||
interceptIterator = { | ||
next: (...args) => { | ||
const result = it.next(...args); | ||
const result = iter.next(...args); | ||
if (result.done) { | ||
@@ -362,5 +366,11 @@ interceptIterator = null; | ||
if (!(it instanceof Effected) && !isGenerator(it)) return resume(it); | ||
return (function* () { | ||
resume(yield* it); | ||
})(); | ||
const iterator = it[Symbol.iterator](); | ||
return { | ||
_effectedIterator: true, | ||
next: (...args) => { | ||
const result = iterator.next(...args); | ||
if (result.done) return { done: true, value: resume(result.value) }; | ||
return result; | ||
}, | ||
}; | ||
}); | ||
@@ -385,5 +395,12 @@ } | ||
if (!(it instanceof Effected) && !isGenerator(it)) return terminate(it); | ||
return (function* () { | ||
terminate(yield* it); | ||
})(); | ||
const iterator = it[Symbol.iterator](); | ||
return { | ||
_effectedIterator: true, | ||
next: (...args) => { | ||
const result = iterator.next(...args); | ||
if (result.done) | ||
return { done: true, value: terminate(result.value) }; | ||
return result; | ||
}, | ||
}; | ||
}); | ||
@@ -411,5 +428,9 @@ } | ||
const it = handler(result.value); | ||
if (!(it instanceof Effected) && !isGenerator(it)) | ||
if ( | ||
!(it instanceof Effected) && | ||
!isGenerator(it) && | ||
!isEffectedIterator(it) | ||
) | ||
return { done: true, value: it }; | ||
appendedIterator = it[Symbol.iterator](); | ||
appendedIterator = Symbol.iterator in it ? it[Symbol.iterator]() : it; | ||
return appendedIterator.next(); | ||
@@ -422,2 +443,25 @@ }, | ||
/** | ||
* Tap the return value of the effected program. | ||
* @param handler The function to tap the return value. | ||
* @returns | ||
* | ||
* @since 0.2.1 | ||
*/ | ||
tap(handler) { | ||
return this.map((value) => { | ||
const it = handler(value); | ||
if (!(it instanceof Effected) && !isGenerator(it)) return value; | ||
const iterator = it[Symbol.iterator](); | ||
return { | ||
_effectedIterator: true, | ||
next: (...args) => { | ||
const result = iterator.next(...args); | ||
if (result.done) return { done: true, value }; | ||
return result; | ||
}, | ||
}; | ||
}); | ||
} | ||
/** | ||
* Catch an error effect with a handler. | ||
@@ -450,5 +494,12 @@ * | ||
if (!(it instanceof Effected) && !isGenerator(it)) return terminate(it); | ||
return (function* () { | ||
terminate(yield* it); | ||
})(); | ||
const iterator = it[Symbol.iterator](); | ||
return { | ||
_effectedIterator: true, | ||
next: (...args) => { | ||
const result = iterator.next(...args); | ||
if (result.done) | ||
return { done: true, value: terminate(result.value) }; | ||
return result; | ||
}, | ||
}; | ||
}, | ||
@@ -514,3 +565,2 @@ ); | ||
*/ | ||
provideBy(name, getter) { | ||
@@ -764,2 +814,16 @@ return this.resume(`dependency:${name}`, getter); | ||
/** | ||
* Check if a value is an `EffectedIterator` (i.e., an {@link Iterator} with an `_effectedIterator` | ||
* property set to `true`). | ||
* | ||
* This is only used internally as an alternative to generators to reduce the overhead of creating | ||
* generator functions. | ||
* @param value | ||
* @returns | ||
*/ | ||
const isEffectedIterator = (value) => | ||
typeof value === "object" && | ||
value !== null && | ||
value._effectedIterator === true; | ||
/** | ||
* Capitalize the first letter of a string. | ||
@@ -863,3 +927,3 @@ * @param str The string to capitalize. | ||
if (className !== "Array ") | ||
result = `${className.trimEnd()}(${value.length}) ${result}`; | ||
result = `${className.trim()}(${value.length}) ${result}`; | ||
return result; | ||
@@ -887,1 +951,19 @@ } | ||
}; | ||
// `console` is not standard in JavaScript. Though rare, it is possible that `console` is not | ||
// available in some environments. We use a proxy to handle this case and ignore errors if `console` | ||
// is not available. | ||
const logger = new Proxy( | ||
{}, | ||
{ | ||
get: | ||
(_, prop) => | ||
(...args) => { | ||
try { | ||
console[prop](...args); | ||
} catch (e2) { | ||
// Ignore | ||
} | ||
}, | ||
}, | ||
); |
{ | ||
"name": "tinyeffect", | ||
"version": "0.2.0", | ||
"version": "0.2.1", | ||
"description": "A tiny TypeScript library for handling side effects in a unified way using algebraic effects, offering a type-safe approach for async operations, error handling, dependency injection, and more.", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
@@ -751,2 +751,35 @@ <h1 align="center">tinyeffect</h1> | ||
Besides `.map(handler)`, the `.tap(handler)` method offers a useful alternative when you want to execute side effects without altering the return value. Unlike `.map()`, `.tap()` ignores the return value of the handler function, ensuring the original value is preserved. This makes it ideal for operations like logging, where the action doesn’t modify the main data flow. | ||
For instance, you can use `.tap()` to simulate a `defer` effect similar to Go’s `defer` statement: | ||
```typescript | ||
type Defer = Effect<"defer", [fn: () => void], void>; | ||
const defer: EffectFactory<Defer> = effect("defer"); | ||
const deferHandler = defineHandlerFor<Defer>().with((effected) => { | ||
const deferredActions: Array<() => void> = []; | ||
return effected | ||
.resume("defer", (fn) => { | ||
deferredActions.push(fn); | ||
}) | ||
.tap(() => { | ||
deferredActions.forEach((fn) => fn()); | ||
}); | ||
}); | ||
const program = effected(function* () { | ||
yield* defer(() => console.log("Deferred action")); | ||
console.log("Normal action"); | ||
}).with(deferHandler); | ||
``` | ||
When you run `program.runSync()`, you’ll see the following output: | ||
```text | ||
Normal action | ||
Deferred action | ||
``` | ||
### Handling multiple effects in one handler | ||
@@ -753,0 +786,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1168
2498716
1753