import * as S from "@principia/prelude/Show";
import { memoize } from "../_utils";
import * as A from "../Array";
import { pipe } from "../Function";
import type { ReadonlyRecord } from "../Record";
import * as R from "../Record";
import type { Show } from "./model";
/*
* -------------------------------------------
* Show Combinators
* -------------------------------------------
*/
export * from "@principia/prelude/Show/combinators";
export const named_ = (show: Show, name: string | undefined): Show =>
S.fromShow((a) => (typeof name !== "undefined" ? `<${name}>(${show.show(a)})` : show.show(a)));
export const named = (name: string | undefined) => (show: Show): Show => named_(show, name);
export const nullable = (or: Show): Show => S.fromShow((a) => (a === null ? "null" : or.show(a)));
export const undefinable = (or: Show): Show =>
S.fromShow((a) => (typeof a === "undefined" ? "undefined" : or.show(a)));
export const type: >>(
shows: { [K in keyof A]: Show }
) => Show<{ [K in keyof A]: A[K] }> = S.getStructShow;
export const partial = >>(
properties: { [K in keyof A]: Show }
): Show> =>
pipe(
properties,
R.map((s: Show) => undefinable(s)),
type
);
export const record: (codomain: Show) => Show> = R.getShow;
export const array: (item: Show) => Show> = A.getShow;
export const tuple: >(
...components: { [K in keyof A]: Show }
) => Show = S.getTupleShow as any;
export const intersect_ = (left: Show, right: Show): Show =>
S.fromShow((a) => `${left.show(a)} & ${right.show(a)}`);
export const intersect = (right: Show) => (left: Show): Show => intersect_(left, right);
export const sum_ = (
tag: T,
members: { [K in keyof A]: Show> }
): Show => S.fromShow((a: ReadonlyRecord) => members[a[tag]].show(a));
export const sum = (tag: T) => (
members: { [K in keyof A]: Show> }
): Show => sum_(tag, members);
export const lazy = (f: () => Show): Show => {
const get = memoize>(f);
return S.fromShow((a) => get().show(a));
};