UNPKG

@roit/roit-model-mapper

Version:

ROIT model mapper makes it easy to convert any object or JSON to the model

122 lines (105 loc) 4.55 kB
import { ObjectMapperOptions } from "./ObjectMapperOptions"; import { IJsonMetaData } from "./JsonProperty"; import * as normalizeWhitespace from "normalize-html-whitespace" export class MapperHandle { static deserialize<T>(clazz: { new(): T }, jsonObject: any, optionsMapper?: ObjectMapperOptions) { if ((clazz === undefined) || (jsonObject === undefined)) return undefined; if(Array.isArray(jsonObject)) { const result = jsonObject.map(j => this.deserialize(clazz, j, optionsMapper)) if(optionsMapper && optionsMapper.singleResult) { return result[0] } return result } if(this.isPrimitive(jsonObject)) { if(this.IsValidJSONString(jsonObject)) { jsonObject = JSON.parse(jsonObject) } else { return undefined } } let obj = new clazz(); if(optionsMapper && optionsMapper.compareWithAttributesLowerCase) { jsonObject = this.toLowerCaseAllAttributes(jsonObject) } Object.keys(obj).forEach((key) => { let propertyMetadataFn: (IJsonMetaData) => any = (propertyMetadata: IJsonMetaData<T>) => { let propertyName = optionsMapper && optionsMapper.ignoreJsonPropertyName ? key : propertyMetadata.name || key; let innerJson = undefined; innerJson = jsonObject ? jsonObject[this.getKey(propertyName, optionsMapper)] : undefined; let clazz = this.getClazz(obj, key); if(propertyMetadata.clazz) { let objectTarget = propertyMetadata.linear && !optionsMapper.ignoreLinear ? jsonObject : innerJson if(propertyMetadata.alwaysArray) { if(objectTarget) { objectTarget = Array.isArray(objectTarget) ? objectTarget : [ objectTarget ] } else { objectTarget = [] } } return this.deserialize(propertyMetadata.clazz, objectTarget , optionsMapper); } else if (!this.isPrimitive(clazz) && !propertyMetadata.name) { return this.deserialize(clazz, innerJson, optionsMapper); } else { return jsonObject ? jsonObject[this.getKey(propertyName, optionsMapper)] : undefined; } }; let propertyMetadata: IJsonMetaData<T> = this.getJsonProperty(obj, key); if (propertyMetadata) { obj[key] = this.getValue(propertyMetadataFn(propertyMetadata), optionsMapper) } else { if (jsonObject && jsonObject[key.toLowerCase()] !== undefined) { obj[key] = this.getValue(jsonObject[this.getKey(key, optionsMapper)], optionsMapper) } } }); return obj; } private static isPrimitive(obj) { switch (typeof obj) { case "string": case "number": case "boolean": return true; } return !!(obj instanceof String || obj === String || obj instanceof Number || obj === Number || obj instanceof Boolean || obj === Boolean); } private static getClazz(target: any, propertyKey: string): any { return Reflect.getMetadata("design:type", target, propertyKey) } private static getJsonProperty<T>(target: any, propertyKey: string): IJsonMetaData<T> { return Reflect.getMetadata("jsonProperty", target, propertyKey); } private static toLowerCaseAllAttributes(obj: any) { var key, keys = Object.keys(obj); var n = keys.length; var newobj = {} while (n--) { key = keys[n]; newobj[key.toLowerCase()] = obj[key]; } return newobj } private static getValue(value: any, options: ObjectMapperOptions) { if(options && options.normalizeString && typeof value == "string") { return normalizeWhitespace(value) } return value } private static getKey(key, options: ObjectMapperOptions) { if(options && options.compareWithAttributesLowerCase) { return key.toLowerCase() } return key; } private static IsValidJSONString(str) { try { JSON.parse(str); } catch (e) { return false; } return true; } }