@travetto/schema
Version:
Data type registry for runtime validation, reflection and binding.
71 lines (64 loc) • 2.34 kB
text/typescript
import { castTo, type Class, type DeepPartial } from '@travetto/runtime';
import { BindUtil } from '../bind-util.ts';
import type { SchemaClassConfig, ViewFieldsConfig } from '../service/types.ts';
import type { ValidatorFn } from '../validate/types.ts';
import { SchemaRegistryIndex } from '../service/registry-index.ts';
/**
* Provides all the valid string type fields from a given type T
*/
type ValidStringField<T> = { [K in Extract<keyof T, string>]: T[K] extends string ? K : never }[Extract<keyof T, string>];
/**
* Register a class as a Schema
*
* @augments `@travetto/schema:Schema`
* @kind decorator
*/
export function Schema(config?: Partial<Pick<SchemaClassConfig, 'validators' | 'methods'>>) {
return <T, U extends Class<T>>(cls: U): void => {
cls.from ??= function <V>(this: Class<V>, data: DeepPartial<V>, view?: string): V {
return BindUtil.bindSchema(this, data, { view });
};
SchemaRegistryIndex.getForRegister(cls).registerClass(config);
};
}
/**
* Add a custom validator, can be at the class level
*
* @param fn The validator function
* @kind decorator
*/
export const Validator = <T>(fn: ValidatorFn<T, string>) =>
(cls: Class<T>): void => {
SchemaRegistryIndex.getForRegister(cls).register({ validators: [castTo(fn)] });
};
/**
* Register a specific view for a class
* @param name The name of the view
* @param fields The specific fields to add as part of a view
* @kind decorator
*/
export function View<T>(name: string, fields: ViewFieldsConfig<Partial<T>>) {
return (cls: Class<Partial<T>>): void => {
SchemaRegistryIndex.getForRegister(cls).register({ views: { [name]: fields } });
};
}
/**
* Register a class as a discriminated class, by a specific type
* @param type The type to use for discrimination
* @kind decorator
*/
export function SubType<T>(type?: string) {
return (cls: Class<Partial<T>>): void => {
SchemaRegistryIndex.getForRegister(cls).register({ discriminatedType: type });
};
}
/**
* Register a class as a discriminated class
* @param field The field to use for discrimination
* @kind decorator
*/
export function Discriminated<T>(field: ValidStringField<T>) {
return (cls: Class<Partial<T>>): void => {
SchemaRegistryIndex.getForRegister(cls).register({ discriminatedField: field, discriminatedBase: true });
};
}