import { BaseSchema, Schema, SchemaOptions, SchemaType } from "../../Schema"; import { JsonError } from "./JsonError"; import { ParseError } from "./ParseError"; export interface SchemaUtils { optional: () => Schema; transform: (transformer: SchemaTransformer) => Schema; parseOrThrow: (raw: unknown, opts?: SchemaOptions) => Promise; jsonOrThrow: (raw: unknown, opts?: SchemaOptions) => Promise; } export interface SchemaTransformer { transform: (parsed: Parsed) => Transformed; untransform: (transformed: any) => Parsed; } export function getSchemaUtils(schema: BaseSchema): SchemaUtils { return { optional: () => optional(schema), transform: (transformer) => transform(schema, transformer), parseOrThrow: async (raw, opts) => { const parsed = await schema.parse(raw, opts); if (parsed.ok) { return parsed.value; } throw new ParseError(parsed.errors); }, jsonOrThrow: async (parsed, opts) => { const raw = await schema.json(parsed, opts); if (raw.ok) { return raw.value; } throw new JsonError(raw.errors); }, }; } /** * schema utils are defined in one file to resolve issues with circular imports */ export function optional( schema: BaseSchema ): Schema { const baseSchema: BaseSchema = { parse: (raw, opts) => { if (raw == null) { return { ok: true, value: undefined, }; } return schema.parse(raw, opts); }, json: (parsed, opts) => { if (parsed == null) { return { ok: true, value: null, }; } return schema.json(parsed, opts); }, getType: () => SchemaType.OPTIONAL, }; return { ...baseSchema, ...getSchemaUtils(baseSchema), }; } export function transform( schema: BaseSchema, transformer: SchemaTransformer ): Schema { const baseSchema: BaseSchema = { parse: async (raw, opts) => { const parsed = await schema.parse(raw, opts); if (!parsed.ok) { return parsed; } return { ok: true, value: transformer.transform(parsed.value), }; }, json: async (transformed, opts) => { const parsed = await transformer.untransform(transformed); return schema.json(parsed, opts); }, getType: () => schema.getType(), }; return { ...baseSchema, ...getSchemaUtils(baseSchema), }; }