n4s
Version:
typed schema validation version of enforce
100 lines (90 loc) • 2.43 kB
text/typescript
import { hasOwnProperty } from 'vest-utils';
import { StandardSchemaV1 } from 'vest-utils/standardSchemaSpec';
import { RuleInstance } from '../../utils/RuleInstance';
import { CHAIN_PREPEND } from '../parsers/parserUtils';
import type { Predicate } from './chainExecutor';
import { getLazyRule } from './lazyRegistry';
export function createChainProxyHandlers<T extends RuleInstance<any, any>>(
rules: Record<string, (...args: any[]) => any>,
{
add,
test,
validate,
run,
parse,
message,
prepend,
'~standard': standard,
}: {
add: (p: Predicate) => T;
test: T['test'];
validate: T['validate'];
run: T['run'];
parse: T['parse'];
message: (msg: any) => T;
prepend: (p: Predicate) => T;
'~standard': StandardSchemaV1.Props<any, any>;
},
) {
const methods = {
'~standard': standard,
message,
parse,
run,
test,
validate,
};
const methodKeys = new Set([
'infer',
'test',
'validate',
'run',
'parse',
'message',
'~standard',
]);
return createProxyHandlersHelper(rules, methods, methodKeys, {
add,
prepend,
});
}
function createProxyHandlersHelper<T extends RuleInstance<any, any>>(
rules: Record<string, any>,
methods: Record<string, any>,
methodKeys: Set<string>,
inserters: { add: (p: Predicate) => T; prepend: (p: Predicate) => T },
) {
function getRuleHandler(prop: string | symbol) {
if (hasOwnProperty(rules, prop)) {
const insert = rules[prop][CHAIN_PREPEND]
? inserters.prepend
: inserters.add;
return (...args: any[]) =>
insert((value: any) => rules[prop](value, ...args));
}
if (typeof prop === 'string') {
const lazyRule = getLazyRule(prop);
if (lazyRule) {
return (...args: any[]) => inserters.add(lazyRule(...args));
}
}
return undefined;
}
return {
get(_target: T, prop: string | symbol, receiver: any) {
if (hasOwnProperty(methods, prop)) {
return methods[prop];
}
return (
getRuleHandler(prop) ?? Reflect.get(_target as object, prop, receiver)
);
},
has(_target: T, prop: string | symbol) {
if (typeof prop === 'string') {
if (methodKeys.has(prop) || getLazyRule(prop)) return true;
}
if (hasOwnProperty(rules, prop)) return true;
return Reflect.has(_target as object, prop);
},
};
}