UNPKG

protoobject

Version:

A universal class for creating any JSON objects and simple manipulations with them.

268 lines 9.42 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ProtoObject = void 0; /** * A universal class for creating any JSON objects and simple manipulations with them. */ class ProtoObject { /** * * @param data - ProtoObject or its heir properties * @returns - the ProtoObject or its heir */ constructor(data) { return ProtoObject.deepAssign(this, data ?? {}); } /** * Get all properties of an object and its prototypes * * @param data - any non-null object, such as an instance of the ProtoObject class or its heir * @returns - an array of the properties information */ static getProperties(data) { const props = []; // eslint-disable-next-line guard-for-in for (const key in data) { const prop = Object.getOwnPropertyDescriptor(data, key); if (prop) props.push({ key, value: prop?.value, descriptor: prop }); } return props; } /** * Get all enumerable properties of an object and its prototypes * * @param data - any non-null object, such as an instance of the ProtoObject class or its heir * @param options - options for the returned array of properties * @param options.onlyWritable - return only writable properties * @returns - an array of the properties information */ static getEnumerableProperties(data, options = { onlyWritable: false }) { const classNode = this; return classNode .getProperties(data) .filter((prop) => !prop.descriptor.get && !prop.descriptor.set && prop.descriptor.enumerable) .filter((prop) => options?.onlyWritable ? prop.descriptor.writable : true); } /** * A recursive function for assigning properties to an object or returning a property * if it is not interchangeable * * WARN: The first transferred object will be changed. * * @param obj - an object such as a ProtoObject or its heir or an object property * @param data - an object such as a ProtoObject or its heir or an object property * @returns - an object such as a ProtoObject or its heir or an object property */ static recursiveAssign(obj, data) { const classNode = this; if (typeof obj === "undefined" || obj === null || (typeof data !== "undefined" && typeof obj !== typeof data)) return data; if (data === null) return data; switch (typeof data) { case "undefined": return obj; case "bigint": case "boolean": case "function": case "number": case "string": case "symbol": return data; case "object": { if (Array.isArray(data)) { return data; } if (data instanceof ProtoObject && data?.constructor?.name !== obj?.constructor?.name) { return data.copy(); } if (!(data instanceof ProtoObject) && typeof data.constructor === "function" && data.constructor?.name !== "Object") { return data; } for (const prop of classNode.getEnumerableProperties(data)) { if (typeof prop.key !== "string") continue; const origProp = Object.getOwnPropertyDescriptor(obj, prop.key); if (!origProp || (!origProp.get && !origProp.set && origProp.enumerable && origProp.writable)) { obj[prop.key] = classNode.recursiveAssign(obj[prop.key], data[prop.key]); } else { continue; } } return obj; } } return obj; } /** * Deep assign data to an instance of the ProtoObject class or its heir * * @param obj - a ProtoObject class or its heir * @param data - a ProtoObject class or its heir or any other object * @returns - a assigned ProtoObject class or its heir */ static deepAssign(obj, data) { const classNode = this; return classNode.recursiveAssign(obj, data ?? {}); } /** * The converter of values into simple types * * @param data - a value to convert to a simple type * @returns - a simple type */ static valueToJSON(data) { switch (typeof data) { case "boolean": case "number": case "string": return data; default: return undefined; } } /** * The converter of simple types into values * * @param data - a simple type to convert to a value * @returns - a value */ static valueFromJSON(data) { switch (typeof data) { case "boolean": case "number": case "string": return data; default: return undefined; } } /** * A method for converting a simple json to ProtoObject class or its heir * * @param data - a simple json data * @returns - a ProtoObject class or its heir */ static fromJSON(data) { const classNode = this; const json = {}; // eslint-disable-next-line guard-for-in for (const key in data) { const value = classNode.valueFromJSON(data[key]); if (value) json[key] = value; } return new classNode(json); } /** * A method for converting a ProtoObject class or its heir to simple json * * @returns - a simple json */ toJSON() { const classNode = this .constructor; const json = {}; const props = ProtoObject.getEnumerableProperties(this); for (const prop of props) { const value = classNode.valueToJSON(prop.value); if (value) json[prop.key] = value; } return json; } /** * A method for converting a ProtoObject class or its heir to a string * * @returns - string */ toString() { return JSON.stringify(this.toJSON()); } /** * Copying a ProtoObject class or its heirs * * @returns - a deep copy of the ProtoObject object or its heir */ copy() { const classNode = this.constructor; return classNode.fromJSON(this.toJSON()); } /** * Deep assign data to an instance of the ProtoObject class or its heir * * @param data - a ProtoObject class or its heir or any other object * @returns - a assigned ProtoObject class or its heir */ assign(data) { const classNode = this.constructor; return classNode.deepAssign(this, data); } /** * Factory for creating a data transformer for the ProtoObject class or its heir * * @param param0 - data validators * @param param0.validatorTo - data validator when converting to a simple JSON object * @param param0.validatorFrom - data validator when converting to a class * @returns data transformer for the ProtoObject class or its heir */ static recordTransformer({ validatorTo, validatorFrom, }) { const classNode = this; return { to(obj) { if (!obj || (typeof validatorTo === "function" && !validatorTo(obj))) return undefined; return obj.toJSON(); }, from(json) { if (!json || (typeof validatorFrom === "function" && !validatorFrom(json))) return undefined; return classNode.fromJSON(json); }, }; } /** * Factory for creating a data transformer for the array of ProtoObject classes or its heirs * * @param param0 - data validators * @param param0.validatorTo - data validator when converting to a simple JSON object * @param param0.validatorFrom - data validator when converting to a class * @returns data transformer for the array of the ProtoObject classes or its heirs */ static collectionTransformer({ validatorTo, validatorFrom, }) { const classNode = this; return { to(objArr) { if (!Array.isArray(objArr)) return undefined; return objArr .filter((obj) => !!obj && (typeof validatorTo !== "function" || !!validatorTo(obj))) .map((obj) => obj.toJSON()); }, from(jsonArr) { if (!Array.isArray(jsonArr)) return undefined; return jsonArr .filter((json) => !!json && (typeof validatorFrom !== "function" || !!validatorFrom(json))) .map((json) => classNode.fromJSON(json)); }, }; } } exports.ProtoObject = ProtoObject; //# sourceMappingURL=proto-object.js.map