2020-11-06 08:10:30 +00:00
|
|
|
/**
|
|
|
|
* @author Martin Karkowski
|
|
|
|
* @email m.karkowski@zema.de
|
|
|
|
* @create date 2020-11-06 08:54:00
|
2021-08-17 15:52:46 +00:00
|
|
|
* @modify date 2021-08-13 10:03:10
|
2020-11-06 08:10:30 +00:00
|
|
|
* @desc [description]
|
|
|
|
*/
|
|
|
|
|
2021-11-14 22:16:07 +00:00
|
|
|
export const SPLITCHAR = "/";
|
2022-02-01 11:59:27 +00:00
|
|
|
import { deepEqual as _deepEqual } from "assert";
|
2020-08-25 08:21:55 +00:00
|
|
|
|
|
|
|
const _sentinel = new Object();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function to recurvely get an Attribute of the Object.
|
|
|
|
*
|
|
|
|
* @export
|
|
|
|
* @param {*} _data
|
|
|
|
* @param {string} _path
|
|
|
|
* @param {*} [_default=_sentinel]
|
|
|
|
* @returns {*}
|
|
|
|
*/
|
2021-03-22 19:25:15 +00:00
|
|
|
export function rgetattr<T = any>(
|
|
|
|
_data: any,
|
|
|
|
_path: string,
|
|
|
|
_default: any = _sentinel,
|
|
|
|
_SPLITCHAR: string = SPLITCHAR
|
|
|
|
): T | null {
|
2020-08-25 08:21:55 +00:00
|
|
|
// Extract the Path
|
|
|
|
let _obj = _data;
|
|
|
|
|
|
|
|
if (_path.length > 0) {
|
|
|
|
/** Check if there is a Substring available perform the normal method */
|
|
|
|
if (_path.indexOf(_SPLITCHAR) !== -1) {
|
|
|
|
for (const attr of _path.split(_SPLITCHAR)) {
|
|
|
|
/** Access a Map */
|
|
|
|
if (_obj instanceof Map) {
|
|
|
|
_obj = _obj.get(attr);
|
|
|
|
} else {
|
|
|
|
/** Array or default Object */
|
|
|
|
_obj = _obj[attr];
|
|
|
|
}
|
|
|
|
|
2022-01-21 15:17:40 +00:00
|
|
|
if ((_obj == null || _obj == undefined) && _default === _sentinel) {
|
2020-08-25 08:21:55 +00:00
|
|
|
return null;
|
2022-01-21 15:17:40 +00:00
|
|
|
} else if (_obj == null || _obj == undefined) {
|
2020-08-25 08:21:55 +00:00
|
|
|
return _default;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/** Otherwise just return the Element */
|
2022-01-21 15:17:40 +00:00
|
|
|
if (_obj[_path] == null || _obj[_path] == undefined) {
|
|
|
|
return _default;
|
|
|
|
}
|
|
|
|
|
2020-08-25 08:21:55 +00:00
|
|
|
return _obj[_path];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return _obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function to Set recursely a Attribute of an Object
|
|
|
|
*
|
2021-08-17 15:52:46 +00:00
|
|
|
* @author M.Karkowski
|
2020-08-25 08:21:55 +00:00
|
|
|
* @export
|
|
|
|
* @param {*} _data The Object, where the data should be stored
|
2021-08-17 15:52:46 +00:00
|
|
|
* @param {string} _path The Path of the Attribute. All are seprated by a the splitchar. (Defaults to'.' => For Instance 'a.b.0.a.c')
|
2020-08-25 08:21:55 +00:00
|
|
|
* @param {*} _value The Value which should be Stored in the Attribute.
|
2021-08-17 15:52:46 +00:00
|
|
|
* @param {string} [_SPLITCHAR=SPLITCHAR] The Splitchar to use. Defaults to "."
|
2020-08-25 08:21:55 +00:00
|
|
|
*/
|
2021-03-22 19:25:15 +00:00
|
|
|
export function rsetattr(
|
|
|
|
_data: any,
|
|
|
|
_path: string,
|
|
|
|
_value: any,
|
|
|
|
_SPLITCHAR: string = SPLITCHAR
|
|
|
|
): void {
|
2020-08-25 08:21:55 +00:00
|
|
|
let _obj = _data;
|
|
|
|
|
|
|
|
const _ptrs = _path.split(_SPLITCHAR);
|
|
|
|
|
|
|
|
_ptrs.slice(0, -1).forEach(function (attr: string, idx: number) {
|
|
|
|
// Adapt the Object by going through a loop
|
|
|
|
let _sub = _obj[attr];
|
|
|
|
|
|
|
|
if (_sub === undefined || _sub === null) {
|
|
|
|
// _obj is an Array and it doesnt contain the index
|
|
|
|
|
|
|
|
// Extract the Next Element:
|
|
|
|
const _next = _ptrs[idx + 1];
|
|
|
|
|
|
|
|
const _next_is_int = isInt(_next);
|
|
|
|
|
|
|
|
if (Array.isArray(_obj)) {
|
|
|
|
if (_next_is_int) {
|
|
|
|
_obj[attr] = new Array<any>();
|
|
|
|
} else {
|
|
|
|
_obj[attr] = {};
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (_next_is_int) {
|
|
|
|
_obj[attr] = [];
|
|
|
|
} else {
|
|
|
|
_obj[attr] = {};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_sub = _obj[attr];
|
|
|
|
}
|
|
|
|
|
|
|
|
_obj = _sub;
|
|
|
|
});
|
|
|
|
_obj[_ptrs[_ptrs.length - 1]] = _value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks whether the Value is an Integer
|
|
|
|
*
|
|
|
|
* @export
|
|
|
|
* @param {*} value Value to be checked
|
|
|
|
* @returns {boolean} Result
|
|
|
|
*/
|
|
|
|
export function isInt(value: any): boolean {
|
2021-03-22 19:25:15 +00:00
|
|
|
return parseInt(value) === value;
|
2020-08-25 08:21:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks whether the Value is a Float
|
|
|
|
*
|
|
|
|
* @export
|
|
|
|
* @param {*} value Value to be checked
|
|
|
|
* @returns {boolean} Result
|
|
|
|
*/
|
|
|
|
export function isFloat(value: any): boolean {
|
2021-03-22 19:25:15 +00:00
|
|
|
return !isNaN(Number(value));
|
2020-08-25 08:21:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Copys the Object. Creates a Deep-Copy
|
|
|
|
* of the Function
|
|
|
|
*
|
|
|
|
* @export
|
|
|
|
* @param {*} value The value which should be copied
|
|
|
|
* @returns {*} A Copy of the Value
|
|
|
|
*/
|
2021-03-22 19:25:15 +00:00
|
|
|
export function copy<T>(value: T): T {
|
2020-08-25 08:21:55 +00:00
|
|
|
// TODO RING
|
|
|
|
// const _copy = {};
|
|
|
|
|
|
|
|
// /** Perform a Recursevly Foreach an Set an Attribute. */
|
|
|
|
// recursiveForEach(value, '', (path: string, _data: any) => {
|
|
|
|
// rsetattr(_copy, path, _data);
|
|
|
|
// });
|
|
|
|
|
|
|
|
// return _copy;
|
|
|
|
return JSON.parse(JSON.stringify(value));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function Converts a Object to a Map.
|
|
|
|
*
|
|
|
|
* @export
|
|
|
|
* @param {*} _obj The Object which should be converted.
|
|
|
|
* @returns {Map<string,any>}
|
|
|
|
*/
|
|
|
|
export function objectToMap(_obj: any): Map<string, any> {
|
|
|
|
/** Define the Returntype */
|
|
|
|
const _ret = new Map<string, any>();
|
|
|
|
|
|
|
|
/** Iterate through all properties of the Object */
|
|
|
|
for (const _prop of Object.getOwnPropertyNames(_obj)) {
|
|
|
|
/** If isnt a function it could be added */
|
2021-03-22 19:25:15 +00:00
|
|
|
if (typeof _obj !== "function") {
|
2020-08-25 08:21:55 +00:00
|
|
|
_ret.set(_prop, _obj[_prop]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Return the Result */
|
|
|
|
return _ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks whether the Value is an Object
|
|
|
|
*
|
|
|
|
* @export
|
|
|
|
* @param {*} value Data to Test
|
|
|
|
* @returns {boolean} Flag showing whether the Presented Data is an Object
|
|
|
|
*/
|
|
|
|
export function isObject(value: any): boolean {
|
|
|
|
/** Verify whether the value contains some data. */
|
|
|
|
if (value) {
|
2021-03-22 19:25:15 +00:00
|
|
|
if (typeof value === "object" && !Array.isArray(value)) {
|
2020-08-25 08:21:55 +00:00
|
|
|
return Object.keys(value).length > 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks whether the Value is an Object
|
|
|
|
*
|
|
|
|
* @export
|
|
|
|
* @param {*} value Data to Test
|
|
|
|
* @returns {boolean} Flag showing whether the Presented Data is an Object
|
|
|
|
*/
|
|
|
|
export function isObjectOrArray(value: any): boolean {
|
|
|
|
/** Verify whether the value contains some data. */
|
|
|
|
return isObject(value) || Array.isArray(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Flattens an Object to a Map.
|
|
|
|
*
|
|
|
|
* For Instance:
|
|
|
|
*
|
|
|
|
* data = {a : { b : { c : 1, d: "hallo"}}}
|
|
|
|
*
|
|
|
|
* // Normal Call
|
|
|
|
* res = flatteObject(data,'')
|
|
|
|
* => res = {"a.b.c":1,"a.b.d":"hallo"}
|
|
|
|
*
|
|
|
|
* // With a Selected prefix 'additional.name'
|
|
|
|
* res = flatteObject(data,'additional.name')
|
|
|
|
* => res = {"additional.name.a.b.c":1,"additional.name.a.b.d":"hallo"}
|
|
|
|
*
|
|
|
|
* @export
|
|
|
|
* @param {*} data The Data that should be converted
|
|
|
|
* @param {string} [prefix=''] An additional prefix.
|
|
|
|
* @returns {Map<string, any>} The flatten Object
|
|
|
|
*/
|
2021-03-22 19:25:15 +00:00
|
|
|
export function flattenObject(
|
|
|
|
data: any,
|
2021-08-17 15:52:46 +00:00
|
|
|
options: {
|
2021-12-04 07:25:26 +00:00
|
|
|
prefix?: string;
|
|
|
|
splitchar?: string;
|
|
|
|
maxDepth?: number;
|
|
|
|
onlyPathToSimpleValue?: boolean;
|
|
|
|
} = {}
|
2021-03-22 19:25:15 +00:00
|
|
|
): Map<string, any> {
|
2021-12-04 07:25:26 +00:00
|
|
|
const _options = Object.assign(
|
|
|
|
{
|
|
|
|
prefix: "",
|
|
|
|
splitchar: SPLITCHAR,
|
|
|
|
onlyPathToSimpleValue: false,
|
|
|
|
maxDepth: Infinity,
|
|
|
|
},
|
|
|
|
options
|
|
|
|
);
|
2021-08-17 15:52:46 +00:00
|
|
|
|
2020-08-25 08:21:55 +00:00
|
|
|
const _ret = new Map<string, any>();
|
|
|
|
|
|
|
|
if (isObject(data) || Array.isArray(data)) {
|
2021-03-22 19:25:15 +00:00
|
|
|
recursiveForEach(
|
|
|
|
data,
|
2021-08-17 15:52:46 +00:00
|
|
|
_options.prefix,
|
2021-03-22 19:25:15 +00:00
|
|
|
(path, _data) => {
|
|
|
|
_ret.set(path, _data);
|
|
|
|
},
|
2021-08-17 15:52:46 +00:00
|
|
|
_options.splitchar,
|
2021-11-14 22:16:07 +00:00
|
|
|
_options.onlyPathToSimpleValue,
|
2021-08-17 15:52:46 +00:00
|
|
|
_options.maxDepth
|
2021-03-22 19:25:15 +00:00
|
|
|
);
|
2020-08-25 08:21:55 +00:00
|
|
|
}
|
|
|
|
return _ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-12-04 07:25:26 +00:00
|
|
|
* Function, that will iterate over an object.
|
2021-08-17 15:52:46 +00:00
|
|
|
* It will call the callback on every element.
|
2021-12-04 07:25:26 +00:00
|
|
|
*
|
2020-08-25 08:21:55 +00:00
|
|
|
*
|
2021-08-17 15:52:46 +00:00
|
|
|
* @author M.Karkowski
|
2020-08-25 08:21:55 +00:00
|
|
|
* @export
|
2021-08-17 15:52:46 +00:00
|
|
|
* @param {*} obj The Object to iterate
|
|
|
|
* @param {string} [prefix=""] A prefix for the Path.
|
|
|
|
* @param {(
|
|
|
|
* path: string,
|
|
|
|
* data: any,
|
|
|
|
* parent?: string,
|
|
|
|
* level?: number
|
|
|
|
* ) => void} dataCallback Callback, that will be called.
|
|
|
|
* @param {string} [_SPLITCHAR=SPLITCHAR] The Splitchar to use, to generate the path
|
2021-12-04 07:25:26 +00:00
|
|
|
* @param {boolean} [_callOnlyOnValues=true] A Flag, to start the
|
2021-08-17 15:52:46 +00:00
|
|
|
* @param {*} [_maxDepth=Infinity] Determine the max Depth, after which the Iteration will be stopped.
|
|
|
|
* @param {string} [_parent=""] For Recursive call only
|
|
|
|
* @param {number} [_level=0] For Recursive call only
|
|
|
|
* @return {*} {*}
|
2020-08-25 08:21:55 +00:00
|
|
|
*/
|
2021-03-22 19:25:15 +00:00
|
|
|
export function recursiveForEach(
|
|
|
|
obj: any,
|
|
|
|
prefix = "",
|
|
|
|
dataCallback: (
|
|
|
|
path: string,
|
|
|
|
data: any,
|
|
|
|
parent?: string,
|
|
|
|
level?: number
|
|
|
|
) => void,
|
|
|
|
_SPLITCHAR: string = SPLITCHAR,
|
|
|
|
_callOnlyOnValues = true,
|
2021-08-17 15:52:46 +00:00
|
|
|
_maxDepth = Infinity,
|
2021-03-22 19:25:15 +00:00
|
|
|
_parent = "",
|
|
|
|
_level = 0
|
|
|
|
): any {
|
2021-11-14 22:16:07 +00:00
|
|
|
if (_level > _maxDepth) {
|
2021-08-17 15:52:46 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create an Array with the Keys.
|
2020-08-25 08:21:55 +00:00
|
|
|
let keys = Array<string>();
|
|
|
|
|
2021-12-04 07:25:26 +00:00
|
|
|
// Extract the keys of an object, but only if it isnt a
|
2021-08-17 15:52:46 +00:00
|
|
|
// string or function.
|
2021-03-22 19:25:15 +00:00
|
|
|
if (typeof obj !== "string" && typeof obj !== "function") {
|
2020-08-25 08:21:55 +00:00
|
|
|
keys = Object.getOwnPropertyNames(obj);
|
|
|
|
if (Array.isArray(obj)) {
|
2021-03-22 19:25:15 +00:00
|
|
|
keys.splice(keys.indexOf("length"), 1);
|
2020-08-25 08:21:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let called = false;
|
|
|
|
|
|
|
|
if (!_callOnlyOnValues) {
|
|
|
|
// Store the Element !
|
|
|
|
dataCallback(prefix, obj, _parent, _level);
|
|
|
|
called = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If there are Keys => It is a List or a Default Object
|
|
|
|
if (keys.length > 0) {
|
|
|
|
for (const _key of keys) {
|
2021-08-17 15:52:46 +00:00
|
|
|
// Define the variable, containing the path
|
2021-03-22 19:25:15 +00:00
|
|
|
const _str = prefix === "" ? _key : prefix + _SPLITCHAR + _key;
|
2020-08-25 08:21:55 +00:00
|
|
|
|
|
|
|
if (obj[_key] != null) {
|
2021-12-04 07:25:26 +00:00
|
|
|
// Test if there exist a specific function, which will convert the
|
2021-08-17 15:52:46 +00:00
|
|
|
// Object to JSON => if so, we use that function, otherwise we will
|
|
|
|
// just proceed.
|
2021-03-22 19:25:15 +00:00
|
|
|
if (typeof obj[_key].toJSON === "function") {
|
2020-08-25 08:21:55 +00:00
|
|
|
const data = obj[_key].toJSON();
|
2021-08-17 15:52:46 +00:00
|
|
|
// Recursive call this function.
|
2021-03-22 19:25:15 +00:00
|
|
|
recursiveForEach(
|
|
|
|
data,
|
|
|
|
_str,
|
|
|
|
dataCallback,
|
|
|
|
_SPLITCHAR,
|
|
|
|
_callOnlyOnValues,
|
2021-08-17 15:52:46 +00:00
|
|
|
_maxDepth,
|
2021-03-22 19:25:15 +00:00
|
|
|
prefix,
|
|
|
|
_level + 1
|
|
|
|
);
|
2020-08-25 08:21:55 +00:00
|
|
|
} else {
|
2021-08-17 15:52:46 +00:00
|
|
|
// Recursive call this function.
|
2021-03-22 19:25:15 +00:00
|
|
|
recursiveForEach(
|
|
|
|
obj[_key],
|
|
|
|
_str,
|
|
|
|
dataCallback,
|
|
|
|
_SPLITCHAR,
|
|
|
|
_callOnlyOnValues,
|
2021-08-17 15:52:46 +00:00
|
|
|
_maxDepth,
|
2021-03-22 19:25:15 +00:00
|
|
|
prefix,
|
|
|
|
_level + 1
|
|
|
|
);
|
2020-08-25 08:21:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (!called) {
|
|
|
|
// Store the Element !
|
|
|
|
dataCallback(prefix, obj, prefix, _level);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-12-04 07:25:26 +00:00
|
|
|
* Exports the used Types of an Object. The result is the
|
2021-08-17 15:52:46 +00:00
|
|
|
* a Map, where the key represents the path and the value
|
|
|
|
* represents the type of the element (stored in the path)
|
2021-12-04 07:25:26 +00:00
|
|
|
*
|
2021-08-17 15:52:46 +00:00
|
|
|
* @author M.Karkowski
|
2020-08-25 08:21:55 +00:00
|
|
|
* @export
|
2021-08-17 15:52:46 +00:00
|
|
|
* @param {*} data The Data to check
|
|
|
|
* @param {{
|
|
|
|
* prefix?: string,
|
|
|
|
* splitchar?: string,
|
|
|
|
* maxDepth?: number,
|
|
|
|
* }} [options={}]
|
|
|
|
* @return {*} {Map<string, string>} key = path; value = type of element;
|
2020-08-25 08:21:55 +00:00
|
|
|
*/
|
2021-12-04 07:25:26 +00:00
|
|
|
export function flattenObjectType(
|
|
|
|
data: any,
|
|
|
|
options: {
|
|
|
|
prefix?: string;
|
|
|
|
splitchar?: string;
|
|
|
|
onlyPathToSimpleValue?: boolean;
|
|
|
|
maxDepth?: number;
|
|
|
|
} = {}
|
|
|
|
): Map<string, string> {
|
2021-08-17 15:52:46 +00:00
|
|
|
// Options which will be used
|
2021-12-04 07:25:26 +00:00
|
|
|
const _options = Object.assign(
|
|
|
|
{
|
|
|
|
prefix: "",
|
|
|
|
onlyPathToSimpleValue: false,
|
|
|
|
splitchar: SPLITCHAR,
|
|
|
|
maxDepth: Infinity,
|
|
|
|
},
|
|
|
|
options
|
|
|
|
);
|
2021-08-17 15:52:46 +00:00
|
|
|
|
2020-08-25 08:21:55 +00:00
|
|
|
const _ret = new Map<string, string>();
|
|
|
|
|
|
|
|
if (isObject(data)) {
|
2021-12-04 07:25:26 +00:00
|
|
|
recursiveForEach(
|
|
|
|
data,
|
|
|
|
_options.prefix,
|
|
|
|
(path, _data) => {
|
|
|
|
_ret.set(path, typeof _data);
|
|
|
|
},
|
|
|
|
_options.splitchar,
|
|
|
|
_options.onlyPathToSimpleValue,
|
|
|
|
_options.maxDepth
|
|
|
|
);
|
2020-08-25 08:21:55 +00:00
|
|
|
}
|
|
|
|
return _ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-12-04 07:25:26 +00:00
|
|
|
* Deflattens an Dict Based Object. The Object it self is represented
|
2021-08-17 15:52:46 +00:00
|
|
|
* as Map, whereas the Key represents the path.
|
|
|
|
*
|
2020-08-25 08:21:55 +00:00
|
|
|
*
|
2021-08-17 15:52:46 +00:00
|
|
|
* @author M.Karkowski
|
2020-08-25 08:21:55 +00:00
|
|
|
* @export
|
|
|
|
* @param {Map<string, any>} _flattenObject
|
2021-08-17 15:52:46 +00:00
|
|
|
* @return {*} {*}
|
2020-08-25 08:21:55 +00:00
|
|
|
*/
|
2021-12-04 07:25:26 +00:00
|
|
|
export function deflattenObject(
|
|
|
|
_flattenObject: Map<string, any>,
|
|
|
|
options: {
|
|
|
|
prefix?: string;
|
|
|
|
splitchar?: string;
|
|
|
|
}
|
|
|
|
): any {
|
2021-08-17 15:52:46 +00:00
|
|
|
// Options which will be used
|
2021-12-04 07:25:26 +00:00
|
|
|
const _options = Object.assign(
|
|
|
|
{
|
|
|
|
prefix: "",
|
|
|
|
splitchar: SPLITCHAR,
|
|
|
|
},
|
|
|
|
options
|
|
|
|
);
|
2020-08-25 08:21:55 +00:00
|
|
|
const _ret = {};
|
|
|
|
|
|
|
|
_flattenObject.forEach((_val: any, _key: string) => {
|
2021-08-17 15:52:46 +00:00
|
|
|
// if there is a prefix, remove it:
|
|
|
|
if (_options.prefix !== "") {
|
|
|
|
_key = _key.slice(_options.prefix.length);
|
|
|
|
}
|
|
|
|
rsetattr(_ret, _key, _val, _options.splitchar);
|
2020-08-25 08:21:55 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
return _ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function for deeply assigning
|
|
|
|
*
|
|
|
|
* @export
|
|
|
|
* @param {*} target
|
|
|
|
* @param {*} source
|
|
|
|
* @returns
|
|
|
|
*/
|
|
|
|
export function deepAssign(target: any, source: any) {
|
|
|
|
const flattend = flattenObject(source);
|
|
|
|
|
|
|
|
for (const [path, value] of flattend.entries()) {
|
|
|
|
rsetattr(target, path, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
return target;
|
|
|
|
}
|
|
|
|
|
2021-08-17 15:52:46 +00:00
|
|
|
/**
|
|
|
|
* Function to deeply clone the given object.
|
|
|
|
*
|
|
|
|
* @author M.Karkowski
|
|
|
|
* @export
|
|
|
|
* @template T
|
|
|
|
* @param {T} obj
|
|
|
|
* @return {*} {T}
|
|
|
|
*/
|
|
|
|
export function deepClone<T>(obj: T): T {
|
2021-11-14 22:16:07 +00:00
|
|
|
switch (typeof obj) {
|
|
|
|
case "object": {
|
2022-01-25 19:43:17 +00:00
|
|
|
if (obj === null) {
|
|
|
|
return null;
|
|
|
|
}
|
2021-11-14 22:16:07 +00:00
|
|
|
const clone: any = Object.assign({}, obj);
|
|
|
|
Object.keys(clone).forEach(
|
|
|
|
(key) =>
|
2021-12-04 07:25:26 +00:00
|
|
|
(clone[key] =
|
|
|
|
typeof obj[key] === "object" ? deepClone(obj[key]) : obj[key])
|
2021-11-14 22:16:07 +00:00
|
|
|
);
|
2021-12-04 07:25:26 +00:00
|
|
|
return (
|
|
|
|
Array.isArray(obj) && obj.length
|
|
|
|
? (clone.length = obj.length) && Array.from(clone)
|
|
|
|
: Array.isArray(obj)
|
2021-11-14 22:16:07 +00:00
|
|
|
? Array.from(obj)
|
2021-12-04 07:25:26 +00:00
|
|
|
: clone
|
|
|
|
) as T;
|
2021-11-14 22:16:07 +00:00
|
|
|
}
|
|
|
|
default: {
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
}
|
2020-08-25 08:21:55 +00:00
|
|
|
}
|
|
|
|
|
2022-02-01 11:59:27 +00:00
|
|
|
/**
|
|
|
|
* Compares deep a and b (using assert)
|
|
|
|
* @param a Object A
|
|
|
|
* @param b Object B
|
|
|
|
* @returns The Result
|
|
|
|
*/
|
|
|
|
export function deepEqual<T>(a: T, b: T): boolean {
|
|
|
|
try {
|
|
|
|
_deepEqual(a, b);
|
|
|
|
return true;
|
|
|
|
} catch (e) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2020-08-25 08:21:55 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Function to adapt the Object and only return a specific amount of elements.
|
|
|
|
* @param obj The Object itself
|
|
|
|
* @param properties a list of properties/pathes to keep
|
|
|
|
*/
|
2021-03-22 19:25:15 +00:00
|
|
|
export function keepPropertiesOfObject(
|
|
|
|
obj: any,
|
|
|
|
properties: { [index: string]: () => any }
|
2021-08-17 15:52:46 +00:00
|
|
|
): any {
|
2020-08-25 08:21:55 +00:00
|
|
|
if (isObject(obj)) {
|
|
|
|
const ret: any = {};
|
|
|
|
|
|
|
|
const defaultObj = { error: true };
|
|
|
|
|
2021-03-22 19:25:15 +00:00
|
|
|
// Iterate over the Properties, get the content of the path, clone it an put it to the
|
2020-08-25 08:21:55 +00:00
|
|
|
// provided path
|
2021-03-22 19:25:15 +00:00
|
|
|
Object.getOwnPropertyNames(properties).map((path) => {
|
2020-08-25 08:21:55 +00:00
|
|
|
const value = rgetattr(obj, path, defaultObj);
|
2021-03-22 19:25:15 +00:00
|
|
|
rsetattr(
|
|
|
|
ret,
|
|
|
|
path,
|
|
|
|
value !== defaultObj
|
|
|
|
? typeof value === "object"
|
|
|
|
? deepClone(value)
|
|
|
|
: value
|
|
|
|
: properties[path]()
|
|
|
|
);
|
2020-08-25 08:21:55 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
// Return the Object
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wrong Datatype provided.
|
2021-03-22 19:25:15 +00:00
|
|
|
throw TypeError("Function can only create Objects");
|
|
|
|
}
|