import { CaseConvention, convertCase } from './case' import { isNumber, isString, Morphism } from './utils' export interface RenameOptions { serialize?: string deserialize?: string } export interface RenameAllOptions { serialize?: CaseConvention deserialize?: CaseConvention } export interface ContainerOptions { // deserialization only default?: () => T rename?: RenameOptions | string renameAll?: RenameAllOptions | CaseConvention // deserialization only denyUnknownFields?: boolean tag?: string content?: string untagged?: boolean expecting?: string } export interface ConditionalSkipOptions { if: (value: any) => boolean } export interface SkipOptions { serializing?: ConditionalSkipOptions | boolean deserializing?: ConditionalSkipOptions | boolean } export interface PropertyOptions { alias?: string flatten?: boolean rename?: RenameOptions | string serializeWith?: Morphism deserializeWith: Morphism skip?: SkipOptions | boolean } export const Stage = Object.freeze({ Serialize: 0, Deserialize: 1 } as const) export type Stage = typeof Stage[keyof typeof Stage] export class SerdeOptions { private readonly target: any options: ContainerOptions properties: Map constructor(target: any, options: ContainerOptions = {}, properties: Map = new Map()) { this.target = target this.options = options this.properties = properties } static from(target: any) { return new this(target) } getClassName(stage: Stage) { if (isString(this.options.rename)) { return this.options.rename } else if (stage === Stage.Serialize && isString(this.options.rename?.serialize)) { return this.options.rename.serialize } else if (stage === Stage.Deserialize && isString(this.options.rename?.deserialize)) { return this.options.rename.deserialize } else { return this.target.constructor.name } } private getPropertyRename(property: string, stage: Stage, options: PropertyOptions) { if (options != null) { if (isString(options.rename)) { return options.rename } else if (stage === Stage.Serialize && isString(options.rename?.serialize)) { return options.rename.serialize } else if (stage === Stage.Deserialize && isString(options.rename?.deserialize)) { return options.rename.deserialize } } return property } private getPropertyCase(name: string, stage: Stage) { if (isNumber(this.options.renameAll)) { return convertCase(name, this.options.renameAll) } else if (stage === Stage.Serialize && isNumber(this.options.renameAll?.serialize)) { return convertCase(name, this.options.renameAll.serialize) } else if (stage === Stage.Deserialize && isNumber(this.options.renameAll?.deserialize)) { return convertCase(name, this.options.renameAll.deserialize) } else { return name } } getPropertyName(property: string, stage: Stage) { const options = this.properties.get(property) const name = options != null ? this.getPropertyRename(property, stage, options) : property return this.getPropertyCase(name, stage) } }