serde-ts/src/options.ts

111 lines
3.1 KiB
TypeScript

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>() => 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<string, PropertyOptions>
constructor(target: any, options: ContainerOptions = {}, properties: Map<string, PropertyOptions> = 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)
}
}