UNPKG

@thisisagile/easy

Version:

Straightforward library for building domain-driven microservice architectures

129 lines (111 loc) 5.93 kB
import { Get, ofGet, Predicate } from './Get'; import { TypeGuard } from './TypeGuard'; import { Func } from './Func'; import { isDefined, isEmpty } from './Is'; import { validate } from '../validation/Validate'; import { tryTo } from './Try'; class CaseBuilder<V> { is = { true: <T>(pred: Predicate<V>, out: Get<T, V>): Case<T, V> => this.case(pred, out), false: <T>(pred: Predicate<V>, out: Get<T, V>): Case<T, V> => this.case(!ofGet(pred, this.v), out), truthy: <T>(prop: Func<unknown, V>, out: Get<T, V>): Case<T, V> => this.case(!!prop(this.v), out), falsy: <T>(prop: Func<unknown, V>, out: Get<T, V>): Case<T, V> => this.case(!prop(this.v), out), defined: <T>(prop: Func<unknown, V>, out: Get<T, V>): Case<T, V> => this.case(isDefined(prop(this.v)), out), empty: <T>(prop: Func<unknown, V>, out: Get<T, V>): Case<T, V> => this.case(isEmpty(prop(this.v)), out), valid: <T>(prop: Func<unknown, V>, out: Get<T, V>): Case<T, V> => this.case(validate(prop(this.v)).isValid, out), in: <T>(prop: Get<Array<V>, V>, out: Get<T, V>): Case<T, V> => this.case(ofGet(prop, this.v).includes(this.v), out), type: <T, U = unknown>(guard: TypeGuard<U>, out: Func<T, U>): Case<T, V> => this.type<T, U>(guard, out), not: { true: <T>(pred: Predicate<V>, out: Get<T, V>): Case<T, V> => this.case(!ofGet(pred, this.v), out), false: <T>(pred: Predicate<V>, out: Get<T, V>): Case<T, V> => this.case(pred, out), truthy: <T>(prop: Func<unknown, V>, out: Get<T, V>): Case<T, V> => this.case(!prop(this.v), out), falsy: <T>(prop: Func<unknown, V>, out: Get<T, V>): Case<T, V> => this.case(!!prop(this.v), out), defined: <T>(prop: Func<unknown, V>, out: Get<T, V>): Case<T, V> => this.case(!isDefined(prop(this.v)), out), empty: <T>(prop: Func<unknown, V>, out: Get<T, V>): Case<T, V> => this.case(!isEmpty(prop(this.v)), out), valid: <T>(prop: Func<unknown, V>, out: Get<T, V>): Case<T, V> => this.case(!validate(prop(this.v)).isValid, out), in: <T>(prop: Get<Array<V>, V>, out: Get<T, V>): Case<T, V> => this.case(!ofGet(prop, this.v).includes(this.v), out), type: <T, U = unknown>(guard: TypeGuard<U>, out: Get<T, V>): Case<T, V> => this.case(v => !guard(v as unknown), out), }, }; if = this.is; constructor(readonly v: V) {} case<T>(pred: Predicate<V>, out: Get<T, V>): Case<T, V> { return new Case<T, V>(this.v).case(pred, out); } type<T, U = unknown>(guard: TypeGuard<U>, out: Func<T, U>): Case<T, V> { return new Case<T, V>(this.v).type<U>(guard, out); } equals<T>(value: V, out: Get<T, V>): Case<T, V> { return new Case<T, V>(this.v).equals(value, out); } } class Case<T, V = unknown> { is = { true: (pred: Predicate<V>, out: Get<T, V>): Case<T, V> => this.case(pred, out), false: (pred: Predicate<V>, out: Get<T, V>): Case<T, V> => this.case(!ofGet(pred, this.value), out), truthy: (prop: Func<unknown, V>, out: Get<T, V>): Case<T, V> => this.case(!!prop(this.value), out), falsy: (prop: Func<unknown, V>, out: Get<T, V>): Case<T, V> => this.case(!prop(this.value), out), defined: (prop: Func<unknown, V>, out: Get<T, V>): Case<T, V> => this.case(isDefined(prop(this.value)), out), empty: (prop: Func<unknown, V>, out: Get<T, V>): Case<T, V> => this.case(isEmpty(prop(this.value)), out), valid: (prop: Func<unknown, V>, out: Get<T, V>): Case<T, V> => this.case(validate(prop(this.value)).isValid, out), in: (prop: Get<Array<V>, V>, out: Get<T, V>): Case<T, V> => this.case(ofGet(prop, this.value).includes(this.value), out), type: <U>(guard: TypeGuard<U>, out: Func<T, U>): Case<T, V> => this.type<U>(guard, out), not: { true: (pred: Predicate<V>, out: Get<T, V>): Case<T, V> => this.case(!ofGet(pred, this.value), out), false: (pred: Predicate<V>, out: Get<T, V>): Case<T, V> => this.case(pred, out), truthy: (prop: Func<unknown, V>, out: Get<T, V>): Case<T, V> => this.case(!prop(this.value), out), falsy: (prop: Func<unknown, V>, out: Get<T, V>): Case<T, V> => this.case(!!prop(this.value), out), defined: (prop: Func<unknown, V>, out: Get<T, V>): Case<T, V> => this.case(!isDefined(prop(this.value)), out), empty: (prop: Func<unknown, V>, out: Get<T, V>): Case<T, V> => this.case(!isEmpty(prop(this.value)), out), valid: (prop: Func<unknown, V>, out: Get<T, V>): Case<T, V> => this.case(!validate(prop(this.value)).isValid, out), in: (prop: Get<Array<V>, V>, out: Get<T, V>): Case<T, V> => this.case(!ofGet(prop, this.value).includes(this.value), out), type: <U>(guard: TypeGuard<U>, out: Get<T, V>): Case<T, V> => this.case(v => !guard(v as unknown), out), }, }; if = this.is; constructor( protected value: V, protected outcome?: T ) {} case(pred: Predicate<V>, out: Get<T, V>): Case<T, V> { return tryTo(pred, this.value) .is.true() .map(() => ofGet(out, this.value)) .map(res => new Found(this.value, res) as Case<T, V>) .or(this); } type<U>(guard: TypeGuard<U>, out: Func<T, U>): Case<T, V> { return tryTo(guard, this.value) .is.true() .map(() => out(this.value as unknown as U)) .map(res => new Found(this.value, res) as Case<T, V>) .or(this); } equals(value: V, out: Get<T, V>): Case<T, V> { return this.case(this.value === value, out); } else(alt: Get<T, V>): T { return ofGet<T, V>(alt, this.value); } } class Found<T, V> extends Case<T, V> { constructor( protected value: V, protected outcome: T ) { super(value, outcome); } case(pred: Predicate<V>, out: Get<T, V>): this { return this; } type<U>(guard: TypeGuard<U>, out: Func<T, U>): Case<T, V> { return this; } equals(value: V, out: Get<T, V>): Case<T, V> { return this; } else(alt: Get<T, V>): T { return this.outcome; } } export const choose = <V>(value: V) => new CaseBuilder<V>(value);