UNPKG

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
"use strict"; 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;