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 { is = { true: (pred: Predicate, out: Get): Case => this.case(pred, out), false: (pred: Predicate, out: Get): Case => this.case(!ofGet(pred, this.v), out), truthy: (prop: Func, out: Get): Case => this.case(!!prop(this.v), out), falsy: (prop: Func, out: Get): Case => this.case(!prop(this.v), out), defined: (prop: Func, out: Get): Case => this.case(isDefined(prop(this.v)), out), empty: (prop: Func, out: Get): Case => this.case(isEmpty(prop(this.v)), out), valid: (prop: Func, out: Get): Case => this.case(validate(prop(this.v)).isValid, out), in: (prop: Get, V>, out: Get): Case => this.case(ofGet(prop, this.v).includes(this.v), out), type: (guard: TypeGuard, out: Func): Case => this.type(guard, out), not: { true: (pred: Predicate, out: Get): Case => this.case(!ofGet(pred, this.v), out), false: (pred: Predicate, out: Get): Case => this.case(pred, out), truthy: (prop: Func, out: Get): Case => this.case(!prop(this.v), out), falsy: (prop: Func, out: Get): Case => this.case(!!prop(this.v), out), defined: (prop: Func, out: Get): Case => this.case(!isDefined(prop(this.v)), out), empty: (prop: Func, out: Get): Case => this.case(!isEmpty(prop(this.v)), out), valid: (prop: Func, out: Get): Case => this.case(!validate(prop(this.v)).isValid, out), in: (prop: Get, V>, out: Get): Case => this.case(!ofGet(prop, this.v).includes(this.v), out), type: (guard: TypeGuard, out: Get): Case => this.case(v => !guard(v as unknown), out), }, }; if = this.is; constructor(readonly v: V) {} case(pred: Predicate, out: Get): Case { return new Case(this.v).case(pred, out); } type(guard: TypeGuard, out: Func): Case { return new Case(this.v).type(guard, out); } equals(value: V, out: Get): Case { return new Case(this.v).equals(value, out); } } class Case { is = { true: (pred: Predicate, out: Get): Case => this.case(pred, out), false: (pred: Predicate, out: Get): Case => this.case(!ofGet(pred, this.value), out), truthy: (prop: Func, out: Get): Case => this.case(!!prop(this.value), out), falsy: (prop: Func, out: Get): Case => this.case(!prop(this.value), out), defined: (prop: Func, out: Get): Case => this.case(isDefined(prop(this.value)), out), empty: (prop: Func, out: Get): Case => this.case(isEmpty(prop(this.value)), out), valid: (prop: Func, out: Get): Case => this.case(validate(prop(this.value)).isValid, out), in: (prop: Get, V>, out: Get): Case => this.case(ofGet(prop, this.value).includes(this.value), out), type: (guard: TypeGuard, out: Func): Case => this.type(guard, out), not: { true: (pred: Predicate, out: Get): Case => this.case(!ofGet(pred, this.value), out), false: (pred: Predicate, out: Get): Case => this.case(pred, out), truthy: (prop: Func, out: Get): Case => this.case(!prop(this.value), out), falsy: (prop: Func, out: Get): Case => this.case(!!prop(this.value), out), defined: (prop: Func, out: Get): Case => this.case(!isDefined(prop(this.value)), out), empty: (prop: Func, out: Get): Case => this.case(!isEmpty(prop(this.value)), out), valid: (prop: Func, out: Get): Case => this.case(!validate(prop(this.value)).isValid, out), in: (prop: Get, V>, out: Get): Case => this.case(!ofGet(prop, this.value).includes(this.value), out), type: (guard: TypeGuard, out: Get): Case => this.case(v => !guard(v as unknown), out), }, }; if = this.is; constructor( protected value: V, protected outcome?: T ) {} case(pred: Predicate, out: Get): Case { return tryTo(pred, this.value) .is.true() .map(() => ofGet(out, this.value)) .map(res => new Found(this.value, res) as Case) .or(this); } type(guard: TypeGuard, out: Func): Case { return tryTo(guard, this.value) .is.true() .map(() => out(this.value as unknown as U)) .map(res => new Found(this.value, res) as Case) .or(this); } equals(value: V, out: Get): Case { return this.case(this.value === value, out); } else(alt: Get): T { return ofGet(alt, this.value); } } class Found extends Case { constructor( protected value: V, protected outcome: T ) { super(value, outcome); } case(pred: Predicate, out: Get): this { return this; } type(guard: TypeGuard, out: Func): Case { return this; } equals(value: V, out: Get): Case { return this; } else(alt: Get): T { return this.outcome; } } export const choose = (value: V) => new CaseBuilder(value);