"use strict";
const sortArray = require("./functions.js")().sort;
/**
* Add values of properties which are common between all objects, others remain as it is.
* @memberof AlterSet
* @instance
* @param {AlterSet[] | Object[]} arr - Array of objects to add properties of
* @returns {Object} - Values will be sum of individual values of passed object
*/
let addProps = function(...arr){
let f = Object.create(this);
return arr.reduce((flag, inst)=>{
if(inst instanceof Object){
Object.keys(inst).forEach((key)=>{
let unit = (typeof inst[key] === "number") ? 0 : "";
flag[key] = (flag[key] || unit) + inst[key];
});
return flag;
} else{
return flag;
}
}, f);
};
/**
* Subtract values of properties which are common between all objects, others remain as it is.
* @memberof AlterSet
* @instance
* @param {AlterSet[] | Object[]} arr - Array of objects to subtract properties of
* @returns {Object} - Values will be `Instance Value` - `Sum of passed object values` of individual values of passed object
*/
let subProps = function(...arr){
let f = Object.create(this);
return arr.reduce((flag, inst)=>{
if(inst instanceof Object){
Object.keys(inst).forEach((key)=>{
flag[key] = (flag[key] || 0) - inst[key];
});
return flag;
} else{
return flag;
}
}, f);
};
/**
* Create an object with values from existing object and properties specified in array.
* @memberof AlterSet
* @instance
* @param {Array} arr - Properties array.
* @param {Object} [options={unref:true, protoLookup:true}] - Object containing control params
* @param {Boolean} [options.unref=true] - `true` to reserve protochain
* @param {Boolean} [options.protoLookup=true] - `true` to look in protochain for value
* @return {Object} - An object with keys which are passed in array.
*/
let intersection = function(arr, options = {}){
if(typeof arr !== "object"){
let e = new Error(`arr should be 'object' got '${typeof options}'`);
e.code = "ERR_INVALID_ARG_TYPE";
throw e;
}
if(typeof options !== "object"){
let e = new Error(`options should be 'object' got '${typeof options}'`);
e.code = "ERR_INVALID_ARG_TYPE";
throw e;
}
let flag = new Object();
let flagObj = new (function(){});
//Specify default values;
options.unref = (typeof options.unref === "undefined") ? true : options.unref;
options.protoLookup = (typeof options.protoLookup === "undefined") ? true : options.protoLookup;
if(options.protoLookup === false){
flag = Object.assign({}, this);
} else if(options.protoLookup === true){
flag = Object.create(this);
} else{
let e = new Error(`options.protoLookup should be 'boolean' got '${typeof options.unref}'`);
e.code = "ERR_INVALID_ARG_TYPE";
throw e;
}
for(let i of arr){
if(typeof flag[i] !== "undefined"){
flagObj[i] = flag[i];
}
}
if(options.unref === true){
return Object.assign({}, flagObj);
} else if(options.unref === false){
flagObj.__proto__ = this.__proto__;
return flagObj;
} else{
let e = new Error(`options.unref should be 'boolean' got '${typeof options.unref}'`);
e.code = "ERR_INVALID_ARG_TYPE";
throw e;
}
};
/**
* Create an object with key, value pairs in both objects, overring with the pairs of passed object
* @memberof AlterSet
* @instance
* @param {AlterSet | Object} obj - Object to append key value paris of
* @param {Object} [options={unref:false}] - Object containing control params
* @param {Boolean} [options.unref=false] - `true` to create new object else modify `this`
* @returns {Object} - An concatinated object `Instance` U `Passed Object`
*/
let union = function(obj, options = {unref:false}){
if(typeof obj !== "object"){
let e = new Error(`obj should be 'object' got '${typeof options}'`);
e.code = "ERR_INVALID_ARG_TYPE";
throw e;
}
if(typeof options !== "object"){
let e = new Error(`options should be 'object' got '${typeof options}'`);
e.code = "ERR_INVALID_ARG_TYPE";
throw e;
}
let x;
if(options.unref === true){
let flag = Object.create(this);
x = Object.assign(flag, obj);
} else if(options.unref === false){
x = Object.assign(this, obj);
} else{
let e = new Error(`options.unref should be 'boolean' got '${typeof options.unref}'`);
e.code = "ERR_INVALID_ARG_TYPE";
throw e;
}
return x;
};
/**
* Return default value if property not found
* @memberof AlterSet
* @instance
* @param {String} key - Property to search for
* @param {*} [d] - Value to return in case of miss
* @returns {*} - Value against a Key in the object
*/
let get = function(key, d = null){
if(typeof key !== "string"){
let e = new Error(`key should be 'string' got '${typeof options.unref}'`);
e.code = "ERR_INVALID_ARG_TYPE";
throw e;
}
let flag = (this.hasOwnProperty(key)) ? this[key] : d;
return flag;
};
/**
* Get JSON representation of the object
* @memberof AlterSet
* @instance
* @returns {String} - Object to JSON
*/
let json = function(){
return JSON.stringify(this);
};
/**
* Intuitive way of checking key existence
* @memberof AlterSet
* @instance
* @param {String} key - Key to check existence of
* @returns {Boolean} - True/False
*/
let hasKey = function(key){
if(typeof key !== "string"){
let e = new Error(`key should be 'string' got ${typeof key}`);
e.code = "ERR_INVALID_ARG_TYPE";
throw e;
}
return this.hasOwnProperty(key);
};
/**
* Find keys having a certain value
* @memberof AlterSet
* @instance
* @param {String | Number} value - Value to search the keys for
* @param {Object} options - Object with control params
* @param {Boolean} options.strict - Flag to switch between strict/unstrict value matching
* @returns {Array} - Array of keys matching a certain value
*/
let withValue = function(value, options = {strict: false}){
if(typeof options !== "object"){
let e = new Error(`options should be'object' got ${typeof options}`);
e.code = "ERR_INVALID_ARG_TYPE";
throw e;
}
if(typeof options.strict !== "boolean"){
let e = new Error(`options.strict should be 'boolean' got ${typeof options.strict}`);
e.code = "ERR_INVALID_ARG_TYPE";
throw e;
}
if(typeof value !== "string" && typeof value !== "number" && typeof value !== "boolean"){
let e = new Error(`value should be 'string | number | boolean' got ${typeof value}`);
e.code = "ERR_INVALID_ARG_TYPE";
throw e;
}
return Object.entries(this).reduce((arr, [key, v])=>{
if((v === value) || (options.strict === false && v == value)){
arr.push(key);
}
return arr;
}, []);
};
/**
* Get array of keys, in Ascending or Descending order of values
* @param {Object} [options] - Object containing control params
* @param {String} [options.order=ASC] - Ascending `ASC` or Descending `DESC`
* @param {String} [options.returns=keys] - Array of Keys || Value
* @memberof AlterSet
* @instance
* @returns {Array} - Either array of `keys` or `values` based on value of returns
*/
let sort = function(options = {}){
if(!options || typeof options !== "object"){
let e = new Error(`options should be 'object' got ${typeof options}`);
e.code = "ERR_INVALID_ARG_TYPE";
throw e;
}
let order = options.order || "ASC";
let returns = options.returns || "keys";
if(typeof order !== "string"){
let e = new Error(`order shoule be 'string' got ${typeof order}`);
e.code = "ERR_INVALID_ARG_TYPE";
throw e;
}
if(typeof returns !== "string"){
let e = new Error(`returns should be 'string' got ${typeof order}`);
e.code = "ERR_INVALID_ARG_TYPE";
throw e;
}
if(returns !== "keys" && returns !== "values"){
let e = new Error(`value of return should be 'keys' or 'values' got ${order}`);
e.code = "ERR_INVALID_ARG_VALUE";
throw e;
}
let values = Object.values(this);
let finalArr = [];
let sortedArr = sortArray(values, order);
if(returns === "values"){
return sortedArr;
}
for(let i in sortedArr){
let v = sortedArr[i];
if((typeof v === "string" || typeof v === "number" || typeof v === "boolean") && v !== sortedArr[i - 1]){
finalArr = finalArr.concat(this.withValue(v));
} else{
continue;
}
}
return finalArr;
};
/**
* Get key of maximum value
* @memberof AlterSet
* @instance
* @returns {Array} - Array of keys with the maximum value
*/
let getMax = function(){
let arr = sortArray(Object.values(this));
let maxVal = arr[arr.length - 1];
let maxKey = this.withValue(maxVal);
return maxKey;
};
/**
* Get key of minimum value
* @memberof AlterSet
* @instance
* @returns {Array} - Array of keys with the maximum value
*/
let getMin = function(){
let arr = sortArray(Object.values(this));
let minKey = this.withValue(arr[0]);
return minKey;
};
//Export functions
module.exports = {
addProps,
subProps,
intersection,
union,
get,
json,
hasKey,
withValue,
sort,
getMax,
getMin
};