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 = { [K in Extract]: T[K] extends string ? K : never }[Extract]; /** * Register a class as a Schema * * @augments `@travetto/schema:Schema` * @kind decorator */ export function Schema(config?: Partial>) { return >(cls: U): void => { cls.from ??= function (this: Class, data: DeepPartial, 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 = (fn: ValidatorFn) => (cls: Class): 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(name: string, fields: ViewFieldsConfig>) { return (cls: Class>): 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(type?: string) { return (cls: Class>): 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(field: ValidStringField) { return (cls: Class>): void => { SchemaRegistryIndex.getForRegister(cls).register({ discriminatedField: field, discriminatedBase: true }); }; }