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;
},
};
}