import { createGuardVisitedState, createVisitedState, innerGuard, innerValidate, OpaqueVisitedState, RuntypeBase, } from './runtype'; import { ValidationError } from './errors'; export interface Contract { enforce(f: (...a: A) => Z): (...a: A) => Z; } /** * Create a function contract. */ export function Contract( argTypes: { [key in keyof A]: key extends 'length' ? A['length'] : RuntypeBase }, returnType: RuntypeBase, ): Contract { return { enforce: (f: (...args: A) => Z) => (...args: A): Z => { if (args.length < argTypes.length) throw new ValidationError({ message: `Expected ${argTypes.length} arguments but only received ${args.length}`, }); const visited: OpaqueVisitedState = createVisitedState(); for (let i = 0; i < argTypes.length; i++) { const result = innerValidate(argTypes[i], args[i], visited, false); if (result.success) { args[i] = result.value; } else { throw new ValidationError(result); } } const rawResult = f(...args); const result = innerGuard(returnType, rawResult, createGuardVisitedState(), false, false); if (result) { throw new ValidationError(result); } return rawResult; }, }; }