// ets_tracing: off // copied from https://github.com/Effect-TS/schema/blob/master/packages/schema/src/These/index.ts import { pipe } from '@effect-ts/core' import * as Tp from '@effect-ts/core/Collections/Immutable/Tuple' import { _A, _E } from '@effect-ts/core/Effect' import { E, O, T } from './index.js' export class These { readonly [_E]!: () => E readonly [_A]!: () => A constructor(readonly either: E.Either]>>) {} } export function succeed(a: A) { return new These(E.right(Tp.tuple(a, O.none))) } export function warn(a: A, e: E) { return new These(E.right(Tp.tuple(a, O.some(e)))) } export function warnOption(a: A, e: O.Option) { return new These(E.right(Tp.tuple(a, e))) } export function fail(e: E) { return new These(E.left(e)) } export const isNonFailure = (self: These): self is These => E.isRight(self.either) export function foldM_( self: These, onSuccess: (a: A) => These, onBoth: (a: A, e: E) => These, onFail: (e: E) => These, ): These { return new These( E.fold_( self.either, (x): E.Either]>> => onFail(x).either, ({ tuple: [result, warnings] }) => warnings._tag === 'None' ? onSuccess(result).either : onBoth(result, warnings.value).either, ), ) } export function foldM( onSuccess: (a: A) => These, onBoth: (a: A, e: E) => These, onFail: (e: E) => These, ) { return (self: These): These => foldM_(self, onSuccess, onBoth, onFail) } export function map_(self: These, f: (a: A0) => A) { return foldM_( self, (a) => succeed(f(a)), (a, e) => warn(f(a), e), fail, ) } export function map(f: (a: A0) => A) { return (self: These) => map_(self, f) } export function mapError_(self: These, f: (a: E0) => E): These { return foldM_( self, (a) => succeed(a), (a, e) => warn(a, f(e)), (e) => fail(f(e)), ) } export function mapError(f: (a: E0) => E): (self: These) => These { return (self) => mapError_(self, f) } export function chain_(self: These, f: (a: A0, w: O.Option) => These) { return foldM_( self, (a) => f(a, O.none), (a, _) => f(a, O.some(_)), fail, ) } export function chain(f: (a: A0, w: O.Option) => These) { return (self: These) => chain_(self, f) } export function result(self: These): E.Either]>> { return self.either } export const errorOrWaning = (self: These): O.Option => { return E.fold_(self.either, O.some, (tp) => tp.get(1)) } /** Unpacks the provided `These` into a new `Effect` with errors as `E` and values as value/warning tuple */ export const toEffect = (self: These): T.Effect]>> => { return pipe(result(self), E.fold(T.fail, T.succeed)) } export const effectUnwrapValue = (effect: T.Effect>): T.Effect => { return pipe( effect, T.chain((these) => E.fold_(these.either, T.fail, ({ tuple: [a] }) => T.succeed(a))), ) } export const effectTapSuccess = (tapFn: (a: A) => T.Effect) => (effect: T.Effect>): T.Effect> => { return T.tap_(effect, (these) => pipe( result(these), E.fold( () => T.unit, (tp) => tapFn(tp.get(0)), ), ), ) } export const effectTapErrorOrWarning = (tapFn: (te2: TE2) => T.Effect) => (effect: T.Effect>): T.Effect> => { return T.tap_(effect, (these) => pipe( errorOrWaning(these), O.fold( () => T.unit, (e) => tapFn(e), ), ), ) } // export const effectValueOrElse = (effect: T.Effect>): T.Effect => { // return pipe( // effect, // T.chain((these) => E.fold_(these.either, T.fail, ({ tuple: [a] }) => T.succeed(a))), // ) // } /** Wraps the error channel of an Effect<_, _ These> into the These */ export const effectThese = ( effect: T.Effect>, ): T.Effect> => { return pipe( effect, T.either, T.map( E.fold( (e) => fail(e), (t) => t, ), ), ) } /** Casts warnings to errors (and ignores the value in the warning case) */ export const effectToEither = (effect: T.Effect>): T.Effect> => pipe( effect, T.map((these) => E.fold_( these.either, (e2) => E.left(e2), ({ tuple: [val, optE2] }) => O.fold_( optE2, () => E.right(val), (e2) => E.left(e2), ), ), ), )