/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable no-prototype-builtins */
/* eslint-disable @typescript-eslint/triple-slash-reference */
const __global = (typeof window != 'undefined' ? window : global) /* node */ as any;
interface Object {
length: number;
/**
* Dynamic Key
*/
[str: string]: any;
/**
* Merge this object with another object
*/
merge: (...other: Record<any, unknown>[]) => Record<any, unknown>;
/**
* Iterate Object
* @param callback function each element
* @example
* var a = {'a','n'};
* a.each(function(el){
* console.log(el); //a, n each iteration
* })
*/
each(callback: (arg0: any) => any): any;
/**
* Check is empty
*/
isEmpty(): boolean;
replaceKeyFrom(anotherObj: any): any;
}
interface ObjectConstructor {
/**
* Dynamic Key
*/
[str: string]: any;
/**
* Count size length of object
*/
size: (obj: any) => number;
//[pair: string|number]: any;
/**
* Is Object Has Property of key ?
* @param key
*/
hasOwnProperty(key: any): boolean;
/**
* check if has child and go for callback
* @param str match child property
* @param callback function callback
* @author Dimas Lanjaka <dimaslanjaka@gmail.com>
*/
child(str: string | number, callback: (arg: any) => any): any;
/**
* check object has child, if not exist return alternative value
* @param str match child property
* @param alternative default value callback
* @author Dimas Lanjaka <dimaslanjaka@gmail.com>
*/
alt(str: any, alternative: string | number | boolean): any;
/**
* Check object has child
* @param str
*/
has(str: string | number): any;
}
Object.size = function (obj) {
let size = 0,
key: any;
for (key in obj) {
if (obj.hasOwnProperty(key)) size++;
}
return size;
};
Object.child = function (str, callback) {
const self: object = this;
if (self.hasOwnProperty(str)) {
if (typeof callback == 'function') {
return callback(self[str]);
} else {
return true;
}
} else {
return undefined;
}
};
Object.alt = function (str, alternative) {
const self: any = this;
if (self.hasOwnProperty(str)) {
return self[str];
} else {
return alternative;
}
};
Object.has = function (str: string | number) {
return this.hasOwnProperty(str);
};
Object.each = function (callback) {
for (const key in this) {
//callback.call(scope, key, this[key]);
callback.call(this[key]);
}
};
Object.isEmpty = function () {
return this.length === 0;
};
Object.replaceKeyFrom = function (anotherObj) {
return Object.entries(this).reduce((op, [key, value]) => {
const newKey = anotherObj[key];
op[newKey || key] = value;
return op;
}, {});
/*if (typeof anotherObj == 'object') {
for (const key in anotherObj) {
if (Object.prototype.hasOwnProperty.call(anotherObj, key)) {
const element = anotherObj[key];
def[key] = element;
}
}
}*/
};
Object.prototype.merge = function (this: Record<any, unknown>, ...others) {
const hasReadOnlyProp = Object.keys(this).some((property) => {
return isObjectWritable(this, property);
});
if (!hasReadOnlyProp) return mergeDeep(this, ...others);
return Object.assign({ ...this }, ...others);
};
/**
* is Object Writable?
* @param obj
* @param key
* @returns
*/
function isObjectWritable<T extends Record<any, unknown>>(obj: T, key: keyof T) {
const desc = Object.getOwnPropertyDescriptor(obj, key) || {};
return Boolean(desc.writable);
}
__global.isObjectWritable = isObjectWritable;
/**
* Join object to separated string
* * [].join() equivalent
* @param obj Object
* @param separator default comma(,)
* @returns Joined string
*/
function object_join(obj: Record<any, unknown>, separator = ',') {
return Object.keys(obj)
.map(function (k) {
return obj[k];
})
.join(separator);
}
__global.object_join = object_join;
/**
* Simple object check.
* @param item
* @returns
* @example
* ```js
* console.log(isObject({a:'a'})); // true
* console.log(isObject(['a','b'])); // false
* ```
*/
function isObject(item: any): boolean {
return item && typeof item === 'object' && !Array.isArray(item);
}
__global.isObject = isObject;
/**
* Deep merge two objects.
* @param target
* @param ...sources
* @see {@link https://bit.ly/3v1vlXu}
*/
function mergeDeep(target: Record<any, any>, ...sources: Record<any, any>[]) {
if (!sources.length) return target;
const source = sources.shift();
if (isObject(target) && isObject(source)) {
for (const key in source) {
if (isObject(source[key])) {
if (!target[key]) Object.assign(target, { [key]: {} });
mergeDeep(target[key], <any>source[key]);
} else {
// @fixme writable property
Object.assign(target, { [key]: source[key] });
// @fixme readonly property
//target = { ...target, [key]: source[key] };
}
}
}
return mergeDeep(target, ...sources);
}
__global.mergeDeep = mergeDeep;