/* eslint-disable prefer-destructuring */ // eslint-disable-next-line @typescript-eslint/no-unused-vars import * as Def from "@effect/io/Deferred" import * as Eff from "@effect/io/Effect" import * as Exit from "@effect/io/Exit" import * as Fiber from "@effect/io/Fiber" import * as Layer from "@effect/io/Layer" import type { Option } from "@fp-ts/data/Option" import { curry, flow, pipe } from "./Function.js" export * from "@effect/io/Effect" /** * @macro traced * @tsplus fluent effect/io/Effect provideService */ export function provideService( self: Effect, tag: Tag, resource: T ): Effect, E, A> { return Eff.provideService(tag)(resource)(self) } /** * @tsplus static effect/io/Deferred.Ops await * @tsplus getter effect/io/Deferred await */ export const await_ = Def.await /** * @tsplus static effect/io/Effect.Ops unit */ export const unit = Eff.unit() /** * @tsplus static effect/io/Exit.Ops unit */ export const ex_unit = Exit.unit() /** * @tsplus static effect/io/Fiber.Ops unit */ export const fb_unit = Fiber.unit() /** * @tsplus static effect/io/Effect.Ops flatMapEither */ export const flatMapEither = (ei: (a: A2) => Either) => Eff.flatMap((a: A2) => Effect.fromEither(ei(a))) /** * @macro traced * @tsplus fluent effect/io/Effect flatMapOpt */ export function flatMapOpt( self: Effect>, fm: (a: A) => Effect ): Effect> { return self.flatMap(d => d.match( () => Effect(Opt.none), _ => fm(_).map(Opt.some) ) ) } /** * @macro traced * @tsplus fluent effect/io/Effect tapOpt */ export function tapOpt( self: Effect>, fm: (a: A) => Effect ): Effect> { return self.flatMap(d => d.match( () => Effect(Opt.none), _ => fm(_).map(() => Opt(_)) ) ) } /** * @macro traced * @tsplus fluent effect/io/Effect zipRightOpt */ export function zipRightOpt( self: Effect>, fm: Effect ) { return self.flatMap(d => d.match( () => Effect(Opt.none), _ => fm.map(() => Opt(_)) ) ) } /** * @macro traced * @tsplus fluent effect/io/Effect mapOpt */ export function mapOpt( self: Effect>, fm: (a: A) => A2 ): Effect> { return self.map(d => d.match( () => Opt.none, _ => Opt(fm(_)) ) ) } export type Erase = R & K extends K & infer R1 ? R1 : R /** * @tsplus static effect/io/Effect.Ops tryCatchPromiseWithInterrupt */ export function tryCatchPromiseWithInterrupt( promise: LazyArg>, onReject: (reason: unknown) => E, canceller: () => void ): Effect { return Effect.asyncInterruptEither(resolve => { promise() .then(x => pipe(x, Effect.succeed, resolve)) .catch(x => pipe(x, onReject, Effect.fail, resolve)) return Either.left(Effect(canceller)) }) } /** * @macro traced * @tsplus fluent effect/io/Effect tapBoth */ export const tapBoth_ = ( self: Effect, // official tapBoth has E2 instead of never f: (e: E) => Effect, g: (a: A) => Effect ) => self.tapError(f).tap(g) export const tapBoth = ( // official tapBoth has E2 instead of never f: (e: E) => Effect, g: (a: A) => Effect ) => (self: Effect) => tapBoth_(self, f, g) /** * @macro traced * @tsplus fluent effect/io/Effect tapBothInclAbort */ export const tapBothInclAbort_ = ( self: Effect, onError: (err: unknown) => Effect, onSuccess: (a: A) => Effect ) => self.exit.flatMap(_ => _.matchEffect(cause => { const firstError = getFirstError(cause) if (firstError) { return onError(firstError).flatMap(() => Effect.failCauseSync(() => cause)) } return Effect.failCauseSync(() => cause) }, _ => Effect(_).tap(onSuccess)) ) export function getFirstError(cause: Cause) { if (cause.isDie()) { const defects = cause.defects return defects.unsafeHead } if (cause.isFailure()) { const failures = cause.failures return failures.unsafeHead } return null } /** * @macro traced * @tsplus fluent effect/io/Effect tapErrorInclAbort */ export const tapErrorInclAbort_ = ( self: Effect, onError: (err: unknown) => Effect ) => self.exit.flatMap(_ => _.matchEffect(cause => { const firstError = getFirstError(cause) if (firstError) { return onError(firstError) .flatMap(() => Effect.failCauseSync(() => cause)) } return Effect.failCauseSync(() => cause) }, Effect.succeed) ) export function encaseOpt_( o: Option, onError: LazyArg ): Effect { return o.match(() => Effect.fail(onError()), Effect.succeed) } export function encaseOpt(onError: LazyArg) { return (o: Option) => encaseOpt_(o, onError) } export function liftM(a: (a: A) => B) { return flow(a, Effect.succeed) } /** * Takes [A, B], applies it to a curried Effect function, * taps the Effect, returning A. */ export function tupleTap( f: (b: B) => (a: A) => Effect ) { return (t: readonly [A, B]) => Effect(t[0]).tap(f(t[1])) } /** * Takes [A, B], applies it to an Effect function, * taps the Effect, returning A. */ export function tupleTap_(f: (a: A, b: B) => Effect) { return tupleTap(curry(f)) } export function ifDiffR(f: (i: I) => Effect) { return (n: I, orig: I) => ifDiff_(n, orig, f) } export function ifDiff_( n: I, orig: I, f: (i: I) => Effect ) { return n !== orig ? f(n) : Effect.unit } export const tapBothInclAbort = ( onError: (err: unknown) => Effect, onSuccess: (a: A) => Effect ) => (eff: Effect) => tapBothInclAbort_(eff, onError, onSuccess) export const tapErrorInclAbort = (onError: (err: unknown) => Effect) => (eff: Effect) => tapErrorInclAbort_(eff, onError) export function ifDiff(n: I, orig: I) { return (f: (i: I) => Effect) => ifDiff_(n, orig, f) } /** * @tsplus static effect/io/Layer.Ops effect */ export const LayerFromEffect = Layer.effect /** * @tsplus pipeable effect/io/Effect provideSomeEnvironmentReal */ export const provideSomeEnvironmentReal = ( ctx: Context ) => (self: Effect): Effect, E, A> => (self as Effect).provideSomeEnvironment((_: Context) => _.merge(ctx)) /** * @tsplus pipeable effect/io/Effect provideSomeEnvironmentEffect */ export const provideSomeEnvironmentEffect = ( makeCtx: Effect> ) => (self: Effect): Effect, E2 | E, A> => makeCtx.flatMap(ctx => (self as Effect).provideSomeEnvironment((_: Context) => _.merge(ctx)))