import Maybe, { just, nothing } from "true-myth/maybe"; import * as v from "@atcute/lexicons/validations"; type IsUnion = T extends unknown ? ([U] extends [T] ? false : true) : never; type MaybeifyUnion = T extends unknown ? (T extends object ? Maybeify : T) : never; export type Maybeify = { [K in keyof T]-?: undefined extends T[K] ? T[K] extends Array | undefined ? Maybe[]> : IsUnion> extends true ? Maybe>> : T[K] extends object | undefined ? Maybe>> : Maybe> : T[K] extends Array ? Maybeify[] : IsUnion extends true ? MaybeifyUnion : T[K] extends object ? Maybeify : T[K]; }; type AnySchema = v.BaseSchema; function resolveMemberSchema( member: v.ObjectSchema | v.RecordSchema, ): v.ObjectSchema { return (member as { type: string }).type === "record" ? (member as v.RecordSchema).object : (member as v.ObjectSchema); } function resolveLiteralFromShape(shape: Record): string | undefined { const typeSchema = shape["$type"] as AnySchema | undefined; if (typeSchema === undefined) { return undefined; } const inner = (typeSchema as { type: string }).type === "optional" ? (typeSchema as v.OptionalSchema).wrapped : typeSchema; if ((inner as { type: string }).type === "literal") { return (inner as v.LiteralSchema).expected; } return undefined; } export function maybeify( schema: TSchema, value: v.InferOutput, ): Maybeify> { const schemaType = (schema as { type: string }).type; if (schemaType === "optional") { const wrapped = (schema as unknown as v.OptionalSchema).wrapped; if (value === undefined) { return nothing() as unknown as Maybeify>; } return just(maybeify(wrapped, value as never)) as unknown as Maybeify>; } if (schemaType === "record") { const objectSchema = (schema as unknown as v.RecordSchema) .object; return maybeify(objectSchema, value as never) as unknown as Maybeify>; } if (schemaType === "object") { const objectSchema = schema as unknown as v.ObjectSchema>; const result: Record = {}; for (const [key, propSchema] of Object.entries(objectSchema.shape)) { const propValue = (value as Record)[key]; result[key] = maybeify(propSchema as AnySchema, propValue as never); } return result as unknown as Maybeify>; } if (schemaType === "array") { const arraySchema = schema as unknown as v.ArraySchema; return (value as unknown[]).map((item) => maybeify(arraySchema.item, item as never), ) as unknown as Maybeify>; } if (schemaType === "variant") { const variantSchema = schema as unknown as v.VariantSchema; const typeValue = (value as Record)["$type"] as string | undefined; if (typeValue !== undefined) { for (const member of variantSchema.members) { const memberSchema = resolveMemberSchema(member); const expectedType = resolveLiteralFromShape( memberSchema.shape as Record, ); if (expectedType === typeValue) { return maybeify(memberSchema, value as never) as unknown as Maybeify< v.InferOutput >; } } } return value as unknown as Maybeify>; } return value as unknown as Maybeify>; }