111 lines
3.1 KiB
TypeScript
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)
|
|
}
|
|
}
|