typescript-object-helper
Version:
A simple dependency to aid in mapping and instantiating typescript classes
159 lines • 5.98 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.copyObject = exports.copyArray = exports.instantiateFromJsonReverseParam = exports.instantiateFromJson = void 0;
const class_cast_1 = require("./class-cast");
/**
* Creates a class typed object from string input
*
* @param stringIn The json string we want to create a class object from
* @param classCast The class constructor we want to create
*/
function instantiateFromJson(json, classCast) {
if (json instanceof Array) {
return copyArray(json, classCast);
}
return copyObject(json, classCast);
}
exports.instantiateFromJson = instantiateFromJson;
// This should work better to do mass find and replace with regex on new myClass() instantiations.
function instantiateFromJsonReverseParam(classCast, json) {
return instantiateFromJson(json, classCast);
}
exports.instantiateFromJsonReverseParam = instantiateFromJsonReverseParam;
/**
*
* @param arrayIn The array of generic objects we want to create class objects from
* @param classCast The class constructor we want to create
*/
function copyArray(arrayIn, classCast) {
const arr = [];
arrayIn.forEach((val) => {
if (typeof val === 'object') {
arr.push(copyObject(val, classCast));
}
else {
arr.push(val);
}
});
return arr;
}
exports.copyArray = copyArray;
/**
* Does a full copy on an object including nested objects and arrays (deep copy)
* Removes attributes that are not in the destination class model
* Also support typing of attributes and arrays. If you want a nested attribute typed (for access
* to it's functions) then add the @ClassCast decorator to the attribute in your model. example:
*
* @ClassCast(Employee)
* public employee: Employee = undefined;
*
* @param objectIn The generic object we want to create a class object from
* @param classCast The class constructor we want to create
*/
function copyObject(objectIn, classCast, allowExtras = true) {
/* eslint-disable */
if (objectIn instanceof classCast) {
return objectIn;
}
const newInstance = new classCast();
const originalEntries = Object.entries(newInstance);
const descriptors = Object.getOwnPropertyDescriptors(classCast.prototype);
const settableDescriptors = Object.keys(descriptors).filter(key => {
const descriptor = descriptors[key];
return descriptor && (descriptor.set || (descriptor.writable && descriptor.enumerable));
}).sort((a, b) => {
const aHasSet = descriptors[a].set;
const bHasSet = descriptors[b].set;
if (aHasSet && !bHasSet) {
return 1;
}
if (!aHasSet && bHasSet) {
return -1;
}
return 0;
}).reduce((result, key) => {
result[key] = descriptors[key];
return result;
}, {});
const objectEntries = Object.entries(settableDescriptors);
let allEntries = originalEntries.concat(objectEntries);
// TODO: this is deprecated. This will place anything in the JSON into the instance, even if not in the model.
if (allowExtras) {
allEntries = Object.entries(objectIn).concat(allEntries);
}
const allNonPrivateEntries = allEntries.filter(entry => !entry[0].startsWith('_'));
allNonPrivateEntries.forEach((entry) => {
const propertyKey = entry[0];
const descriptor = entry[1];
const attributeValue = objectIn[propertyKey];
// check if the attribute is generic, custom object, or custom array
// @ts-ignore
if (attributeValue !== undefined) {
// @ts-ignore
if (!newInstance[class_cast_1.DNAME] || !newInstance[class_cast_1.DNAME][propertyKey]) {
assignGenericAttribute(newInstance, propertyKey, attributeValue);
}
else {
// @ts-ignore
if (newInstance[class_cast_1.DNAME][propertyKey] instanceof Array && attributeValue instanceof Array) {
assignArrayAttribute(newInstance, propertyKey, attributeValue);
}
else {
assignObjectAttribute(newInstance, propertyKey, attributeValue);
}
}
}
});
// @ts-ignore
if (!!newInstance['onInit'] && typeof newInstance['onInit'] === 'function') {
//@ts-ignore
newInstance.onInit();
}
return newInstance;
}
exports.copyObject = copyObject;
/**
* The model did not define a class type - assign as a generic
*
* @param parent
* @param attributeName
*/
function assignGenericAttribute(parent, attributeName, attributeValue) {
parent[attributeName] = attributeValue;
}
/**
* The model defined an class array. Create a full class object for each item in array
*
* @param parent
* @param attributeName
*/
function assignArrayAttribute(parent, attributeName, attributeValue) {
const arr = [];
// for (const obj of attributeValue as any) {
// arr.push(copyObject(obj, parent[DNAME][attributeName][0]));
// }
attributeValue.forEach((obj) => {
arr.push(copyObject(obj, parent[class_cast_1.DNAME][attributeName][0]));
});
parent[attributeName] = arr;
}
/**
* The model defined a class attribute. Create a full class object for this attribute
*
* @param parent
* @param attributeName
*/
function assignObjectAttribute(parent, attributeName, attributeValue) {
// value is null when we modeled an object that is not present in the json string - set to null
if (!attributeValue) {
parent[attributeName] = null;
}
else if (attributeValue instanceof Array) {
parent[attributeName] = copyArray(attributeValue, parent[class_cast_1.DNAME][attributeName]);
}
else {
parent[attributeName] = copyObject(attributeValue, parent[class_cast_1.DNAME][attributeName]);
}
}
// }
//# sourceMappingURL=object-helper-functions.js.map