/* eslint-disable @typescript-eslint/no-explicit-any */ import type { Submission } from '@conform-to/dom' import type { Context, Env, Input as HonoInput, MiddlewareHandler, ValidationTargets } from 'hono' import { getFormDataFromContext } from './utils' type FormTargetValue = ValidationTargets['form']['string'] type GetInput = T extends (_: any) => infer S ? Awaited extends Submission ? V : never : never type GetSuccessSubmission = S extends { status: 'success' } ? S : never type ParseFn = (formData: FormData) => Submission | Promise> type Hook = ( submission: Awaited>, c: Context ) => Response | Promise | void | Promise export const conformValidator = < F extends ParseFn, E extends Env, P extends string, In = GetInput, Out = Awaited>, I extends HonoInput = { in: { form: { [K in keyof In]: FormTargetValue } } out: { form: GetSuccessSubmission } } >( parse: F, hook?: Hook ): MiddlewareHandler => { return async (c, next) => { const formData = await getFormDataFromContext(c) const submission = await parse(formData) if (hook) { const hookResult = hook(submission as any, c) if (hookResult instanceof Response || hookResult instanceof Promise) { return hookResult } } if (submission.status !== 'success') { return c.json(submission.reply(), 400) } c.req.addValidatedData('form', submission) await next() } }