import { _intersect, memoize } from "../_utils"; import { identity } from "../Function"; import type { Encoder, OutputOf, TypeOf } from "./model"; export const nullable = (or: Encoder): Encoder => ({ encode: (a) => (a === null ? null : or.encode(a)) }); export const type =

>>( properties: P ): Encoder<{ [K in keyof P]: OutputOf }, { [K in keyof P]: TypeOf }> => ({ encode: (a) => { const o: Record = {} as any; for (const k in properties) { o[k] = properties[k].encode(a[k]); } return o; } }); export const partial =

>>( properties: P ): Encoder }>, Partial<{ [K in keyof P]: TypeOf }>> => ({ encode: (a) => { const o: Record = {} as any; for (const k in properties) { const v = a[k]; // don't add missing properties if (k in a) { // don't strip undefined properties o[k] = v === undefined ? undefined : properties[k].encode(v); } } return o; } }); export const record = (codomain: Encoder): Encoder, Record> => ({ encode: (r) => { const o: Record = {}; for (const k in r) { o[k] = codomain.encode(r[k]); } return o; } }); export const array = (item: Encoder): Encoder, ReadonlyArray> => ({ encode: (as) => as.map(item.encode) }); export const tuple = >>( ...components: C ): Encoder<{ [K in keyof C]: OutputOf }, { [K in keyof C]: TypeOf }> => ({ encode: (as) => components.map((c, i) => c.encode(as[i])) as any }); export const intersect = (right: Encoder) => (left: Encoder): Encoder => ({ encode: (ab) => _intersect(left.encode(ab), right.encode(ab)) }); export const sum_ = >>( tag: T, members: MS ): Encoder, TypeOf> => ({ encode: (a) => members[a[tag]].encode(a) }); export const sum = (tag: T) => >>( members: MS ): Encoder, TypeOf> => ({ encode: (a) => members[a[tag]].encode(a) }); export const lazy = (f: () => Encoder): Encoder => { const get = memoize>(f); return { encode: (a) => get().encode(a) }; }; export const contramap_ = (fa: Encoder, f: (b: B) => A): Encoder => ({ encode: (b) => fa.encode(f(b)) }); export const contramap: (f: (b: B) => A) => (fa: Encoder) => Encoder = (f) => (fa) => contramap_(fa, f); export const compose_ = (ab: Encoder, ea: Encoder): Encoder => contramap_(ea, ab.encode); export const compose: (ea: Encoder) => (ab: Encoder) => Encoder = (ea) => (ab) => compose_(ab, ea); export const id = (): Encoder => ({ encode: identity });