sikits
Version:
A powerful and comprehensive utility library for JavaScript and TypeScript with 100+ functions for strings, numbers, arrays, and objects
323 lines (322 loc) • 9.64 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.createCachingProxy = exports.createValidationProxy = exports.createLoggingProxy = exports.minBy = exports.maxBy = exports.averageBy = exports.sumBy = exports.countBy = exports.indexBy = exports.groupByKey = exports.createWithDefaults = exports.invert = exports.toEntries = exports.fromEntries = exports.transformValues = exports.transformKeys = exports.objectDiff = exports.deepEqual = exports.deepMerge = exports.deepCloneCircular = exports.deepCloneStructured = void 0;
/**
* Creates a deep clone of an object using structured clone (if available) or JSON
*/
const deepCloneStructured = (obj) => {
if (typeof structuredClone !== 'undefined') {
return structuredClone(obj);
}
return JSON.parse(JSON.stringify(obj));
};
exports.deepCloneStructured = deepCloneStructured;
/**
* Creates a deep clone of an object with circular reference support
*/
const deepCloneCircular = (obj, hash = new WeakMap()) => {
if (obj === null || typeof obj !== 'object') {
return obj;
}
if (obj instanceof Date) {
return new Date(obj.getTime());
}
if (obj instanceof Array) {
return obj.map(item => (0, exports.deepCloneCircular)(item, hash));
}
if (hash.has(obj)) {
return hash.get(obj);
}
const cloned = {};
hash.set(obj, cloned);
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
cloned[key] = (0, exports.deepCloneCircular)(obj[key], hash);
}
}
return cloned;
};
exports.deepCloneCircular = deepCloneCircular;
/**
* Merges multiple objects deeply
*/
const deepMerge = (...objects) => {
return objects.reduce((result, obj) => {
if (!obj || typeof obj !== 'object')
return result;
Object.keys(obj).forEach(key => {
if (obj[key] && typeof obj[key] === 'object' && !Array.isArray(obj[key])) {
result[key] = (0, exports.deepMerge)(result[key] || {}, obj[key]);
}
else {
result[key] = obj[key];
}
});
return result;
}, {});
};
exports.deepMerge = deepMerge;
/**
* Compares two objects deeply
*/
const deepEqual = (obj1, obj2) => {
if (obj1 === obj2)
return true;
if (obj1 == null || obj2 == null)
return obj1 === obj2;
if (typeof obj1 !== 'object' || typeof obj2 !== 'object')
return obj1 === obj2;
if (obj1.constructor !== obj2.constructor)
return false;
if (Array.isArray(obj1)) {
if (obj1.length !== obj2.length)
return false;
for (let i = 0; i < obj1.length; i++) {
if (!(0, exports.deepEqual)(obj1[i], obj2[i]))
return false;
}
return true;
}
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
if (keys1.length !== keys2.length)
return false;
for (const key of keys1) {
if (!keys2.includes(key))
return false;
if (!(0, exports.deepEqual)(obj1[key], obj2[key]))
return false;
}
return true;
};
exports.deepEqual = deepEqual;
/**
* Gets the difference between two objects
*/
const objectDiff = (obj1, obj2) => {
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
const added = keys2.filter(key => !keys1.includes(key));
const removed = keys1.filter(key => !keys2.includes(key));
const changed = keys1.filter(key => keys2.includes(key) && !(0, exports.deepEqual)(obj1[key], obj2[key]));
return { added, removed, changed };
};
exports.objectDiff = objectDiff;
/**
* Transforms object keys using a function
*/
const transformKeys = (obj, transformer) => {
return Object.keys(obj).reduce((result, key) => {
result[transformer(key)] = obj[key];
return result;
}, {});
};
exports.transformKeys = transformKeys;
/**
* Transforms object values using a function
*/
const transformValues = (obj, transformer) => {
return Object.keys(obj).reduce((result, key) => {
result[key] = transformer(obj[key], key);
return result;
}, {});
};
exports.transformValues = transformValues;
/**
* Creates an object from an array of key-value pairs
*/
const fromEntries = (entries) => {
return entries.reduce((obj, [key, value]) => {
obj[key] = value;
return obj;
}, {});
};
exports.fromEntries = fromEntries;
/**
* Creates an array of key-value pairs from an object
*/
const toEntries = (obj) => {
return Object.keys(obj).map(key => [key, obj[key]]);
};
exports.toEntries = toEntries;
/**
* Inverts an object (swaps keys and values)
*/
const invert = (obj) => {
return Object.keys(obj).reduce((result, key) => {
result[String(obj[key])] = key;
return result;
}, {});
};
exports.invert = invert;
/**
* Creates an object with default values
*/
const createWithDefaults = (keys, defaultValue) => {
return keys.reduce((obj, key) => {
obj[key] = defaultValue;
return obj;
}, {});
};
exports.createWithDefaults = createWithDefaults;
/**
* Creates an object from an array using a key function
*/
const groupByKey = (array, keyFn) => {
return array.reduce((groups, item) => {
const key = keyFn(item);
if (!groups[key]) {
groups[key] = [];
}
groups[key].push(item);
return groups;
}, {});
};
exports.groupByKey = groupByKey;
/**
* Creates an object from an array using a value function
*/
const indexBy = (array, keyFn) => {
return array.reduce((index, item) => {
index[keyFn(item)] = item;
return index;
}, {});
};
exports.indexBy = indexBy;
/**
* Counts occurrences of values in an array
*/
const countBy = (array, keyFn) => {
return array.reduce((counts, item) => {
const key = keyFn(item);
counts[key] = (counts[key] || 0) + 1;
return counts;
}, {});
};
exports.countBy = countBy;
/**
* Sums values in an array grouped by key
*/
const sumBy = (array, keyFn, valueFn) => {
return array.reduce((sums, item) => {
const key = keyFn(item);
sums[key] = (sums[key] || 0) + valueFn(item);
return sums;
}, {});
};
exports.sumBy = sumBy;
/**
* Averages values in an array grouped by key
*/
const averageBy = (array, keyFn, valueFn) => {
const groups = (0, exports.groupByKey)(array, keyFn);
const sums = (0, exports.sumBy)(array, keyFn, valueFn);
return Object.keys(sums).reduce((averages, key) => {
averages[key] = sums[key] / groups[key].length;
return averages;
}, {});
};
exports.averageBy = averageBy;
/**
* Finds the maximum value in an array grouped by key
*/
const maxBy = (array, keyFn, valueFn) => {
return array.reduce((maxs, item) => {
const key = keyFn(item);
const value = valueFn(item);
if (!(key in maxs) || value > maxs[key]) {
maxs[key] = value;
}
return maxs;
}, {});
};
exports.maxBy = maxBy;
/**
* Finds the minimum value in an array grouped by key
*/
const minBy = (array, keyFn, valueFn) => {
return array.reduce((mins, item) => {
const key = keyFn(item);
const value = valueFn(item);
if (!(key in mins) || value < mins[key]) {
mins[key] = value;
}
return mins;
}, {});
};
exports.minBy = minBy;
/**
* Creates a proxy object that logs all property access
*/
const createLoggingProxy = (obj, logger = console.log) => {
return new Proxy(obj, {
get(target, key) {
if (typeof key === 'string') {
logger('GET', key, target[key]);
return target[key];
}
return undefined;
},
set(target, key, value) {
if (typeof key === 'string') {
logger('SET', key, value);
target[key] = value;
return true;
}
return false;
},
deleteProperty(target, key) {
if (typeof key === 'string') {
logger('DELETE', key);
delete target[key];
return true;
}
return false;
}
});
};
exports.createLoggingProxy = createLoggingProxy;
/**
* Creates a proxy object that validates property values
*/
const createValidationProxy = (obj, validators) => {
return new Proxy(obj, {
set(target, key, value) {
if (typeof key === 'string') {
const validator = validators[key];
if (validator && !validator(value)) {
throw new Error(`Invalid value for property ${key}`);
}
target[key] = value;
return true;
}
return false;
}
});
};
exports.createValidationProxy = createValidationProxy;
/**
* Creates a proxy object that caches computed properties
*/
const createCachingProxy = (obj, computedProps) => {
const cache = new Map();
return new Proxy(obj, {
get(target, key) {
if (typeof key === 'string') {
if (computedProps[key]) {
if (!cache.has(key)) {
cache.set(key, computedProps[key]());
}
return cache.get(key);
}
return target[key];
}
return undefined;
},
set(target, key) {
cache.clear();
return true;
}
});
};
exports.createCachingProxy = createCachingProxy;