import * as t from "io-ts" export const SimpleFieldType = "SimpleField" export const SimpleField = t.strict({ TYPE: t.literal(SimpleFieldType), name: t.string, legacy: t.boolean, }) export type SimpleField = t.TypeOf export interface Group { TYPE: typeof GroupType name: string fields: { [key: string]: GroupOrField } } export const Group: t.Type = t.recursion("Group", () => t.strict({ TYPE: t.literal(GroupType), name: t.string, fields: t.record(t.string, GroupOrFieldC), }), ) export type GroupOrField = Simple | Group export const GroupOrFieldC: t.Type = t.recursion("GroupOrField", () => t.union([Simple, Group])) export type Field = GroupOrField | SliceZone export const FieldC: t.Type = t.recursion("Field", () => t.union([GroupOrFieldC, SliceZone])) export const SliceZoneType = "SliceZone" export interface SliceZone { TYPE: typeof SliceZoneType name: string slices: { [key: string]: GroupOrField | Slice } } export const SliceZone: t.Type = t.recursion("SliceZone", () => t.strict({ TYPE: t.literal(SliceZoneType), name: t.string, slices: t.record(t.string, t.union([GroupOrFieldC, Slice])), }), ) export interface Variation { TYPE: "Variation" nonRepeat: { fields: { [key: string]: GroupOrField } } repeat: { fields: { [key: string]: Field } } } export const VariationC: t.Type = t.recursion("Variation", () => t.strict({ TYPE: t.literal("Variation"), nonRepeat: t.strict({ fields: t.record(t.string, GroupOrFieldC), }), repeat: t.strict({ fields: t.record(t.string, FieldC), }), }), ) export const CompositeSliceType = "CompositeSlice" export const CompositeSlice = t.strict({ TYPE: t.literal(CompositeSliceType), nonRepeat: t.strict({ fields: t.record(t.string, GroupOrFieldC), TYPE: t.literal("NonRepeat"), }), repeat: t.strict({ fields: t.record(t.string, GroupOrFieldC), TYPE: t.literal("Repeat"), }), }) export type CompositeSlice = t.TypeOf export const SharedSliceType = "SharedSlice" export const SharedSlice = t.strict({ TYPE: t.literal(SharedSliceType), variations: t.record(t.string, VariationC), }) export type SharedSlice = t.TypeOf export const Slice = t.union([SharedSlice, CompositeSlice]) export type Slice = t.TypeOf export const GroupType = "Group" export interface DocRelation { TYPE: typeof DocRelationType name: string uuid: string fields: { [keyA: string]: { [keyB: string]: Field } } } export const DocRelationC: t.Type = t.recursion("DocRelation", () => { return t.strict({ TYPE: t.literal(DocRelationType), name: t.string, uuid: t.string, fields: t.record(t.string, t.record(t.string, FieldC)), }) }) export type Simple = DocRelation | SimpleField export const Simple = t.union([DocRelationC, SimpleField]) export const DocType = "Doc" export interface Doc { TYPE: typeof DocType typ: string fields: Record } export const Doc: t.Type = t.recursion("Field", () => t.strict({ TYPE: t.literal("Doc"), typ: t.string, fields: t.record(t.string, FieldC), }), ) export const Docs = t.recursion("Field", () => // TODO: handle proper typing for this kind of recursive codec /* eslint-disable @typescript-eslint/ban-ts-comment */ // @ts-ignore t.strict({ docs: t.record(t.string, t.union([DocRelationC, SimpleField, Group, SliceZone])), docRelationsMap: t.record(t.string, DocRelationC), }), ) export type Docs = t.TypeOf export const DocRelationType = "DocRelation" export function extractGroupOrFieldIfAny(fetchOpt: Field | undefined): GroupOrField | undefined { if ( fetchOpt !== undefined && (fetchOpt.TYPE === SimpleFieldType || fetchOpt.TYPE === DocRelationType || fetchOpt.TYPE === GroupType) ) { return fetchOpt } else { return undefined } } export function extractSliceFetchIfAny(fetchOpt: Field | undefined): SliceZone | undefined { if (fetchOpt !== undefined && fetchOpt.TYPE === SliceZoneType) { return fetchOpt } return undefined }