import { IDecorator, Meta } from "oly"; import { olyMapperKeys } from "../constants/keys"; import { IField, IType } from "../interfaces"; export class FieldDecorator implements IDecorator { private readonly options: Partial; public constructor(options: Partial | IType = {}) { this.options = typeof options === "function" ? {type: options} : options; } public asProperty(target: object, propertyKey: string): void { const type = this.options.type || Meta.designType(target, propertyKey); Meta.of({key: olyMapperKeys.fields, target, propertyKey}).set({ name: this.options.name || propertyKey, required: this.options.required !== false, type, ...this.options, }); } public asParameter(target: object, propertyKey: string, index: number) { if (propertyKey === "$constructor") { const type = this.options.type || Meta.designParamTypes(target, propertyKey)[index]; const name = Meta.getParamNames(target.constructor as any)[index]; Meta.of({key: olyMapperKeys.fields, target, propertyKey: name}).set({ name: this.options.name || name, required: this.options.required !== false, type, ...this.options, }); } } } /** * ```ts * class Embedded { * @field title: string; * } * * class Data { * @field firstName: string; * @field lastName: string; * @field age: number; * @field something: Embedded; * } * ``` * * ### JSON Schema * * ```ts * class Data { * * @field({ * // json-schema options like minLength, ... * // "required" is also available * }) * propertyKey: string; * } * * json.schema(Data); // {properties: {... * ``` * * ### Type * * Mapping requires a "Type", most of the time TypeScript type annotations are enough. * * Exceptions: * - array (see @array) * - native type (see @date) * * ### Required by default * * Like a Typescript property, **a @field property is required by default**. * * ```ts * class A { * @field({required: false}) myProperty?: string; // now it's optional * } * ``` */ export const field = Meta.decorator | IType>(FieldDecorator);