UNPKG

@catbee/utils

Version:

A modular, production-grade utility toolkit for Node.js and TypeScript, designed for robust, scalable applications (including Express-based services). All utilities are tree-shakable and can be imported independently.

361 lines (357 loc) 12.1 kB
/* * The MIT License * * Copyright (c) 2026 Catbee Technologies. https://catbee.in/license * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ var __defProp = Object.defineProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); // src/object/object.utils.ts function isObject(value) { return value !== null && typeof value === "object" && !Array.isArray(value); } __name(isObject, "isObject"); function isObjEmpty(obj) { return isObject(obj) && Object.keys(obj).length === 0; } __name(isObjEmpty, "isObjEmpty"); function pick(obj, keys) { return Object.fromEntries(keys.map((key) => [ key, obj[key] ])); } __name(pick, "pick"); function omit(obj, keys) { return Object.fromEntries(Object.entries(obj).filter(([key]) => !keys.includes(key))); } __name(omit, "omit"); function deepObjMerge(target, ...sources) { const seen = /* @__PURE__ */ new WeakMap(); for (const s of sources) { target = mergeInto(target, s, seen); } return target; } __name(deepObjMerge, "deepObjMerge"); function mergeInto(t, s, seen) { if (s === void 0) return t; if (typeof s === "function" || typeof s === "symbol") return s; if (Array.isArray(s)) { const cloned = deepClone(s); seen.set(s, cloned); return cloned; } if (s && typeof s === "object") { if (seen.has(s)) return seen.get(s); if (s instanceof Date || s instanceof Map || s instanceof Set || s instanceof RegExp || s instanceof ArrayBuffer || ArrayBuffer.isView(s)) { const cloned = deepClone(s); seen.set(s, cloned); return cloned; } if (!t || typeof t !== "object") { t = Object.create(Object.getPrototypeOf(s)); } seen.set(s, t); for (const key of Reflect.ownKeys(s)) { if (key === "__proto__") continue; const sv = s[key]; if (sv === void 0) continue; t[key] = mergeInto(t[key], sv, seen); } return t; } return s; } __name(mergeInto, "mergeInto"); function isPlainObject(value) { if (typeof value !== "object" || value === null) return false; if (Array.isArray(value)) return false; const proto = Object.getPrototypeOf(value); return proto === Object.prototype || proto === null; } __name(isPlainObject, "isPlainObject"); function flattenObject(obj, prefix = "") { return Object.entries(obj).reduce((acc, [key, value]) => { const newKey = prefix ? `${prefix}.${key}` : key; if (key === "__proto__") return acc; if (value && typeof value === "object" && !Array.isArray(value)) { Object.assign(acc, flattenObject(value, newKey)); } else { acc[newKey] = value; } return acc; }, {}); } __name(flattenObject, "flattenObject"); function getValueByPath(obj, path) { if (!obj || typeof obj !== "object") return void 0; const parts = path.replace(/\[(\d+)\]/g, ".$1").split(".").filter(Boolean); return parts.reduce((acc, key) => acc?.[key], obj); } __name(getValueByPath, "getValueByPath"); function ensureNextContainer(curr, nextIsIndex) { if (curr === void 0 || typeof curr !== "object" || curr === null) { return nextIsIndex ? [] : /* @__PURE__ */ Object.create(null); } return curr; } __name(ensureNextContainer, "ensureNextContainer"); function setValueByPath(obj, path, value) { if (!obj || typeof obj !== "object") return obj; const clone = deepClone(obj); const parts = path.replace(/\[(\d+)\]/g, ".$1").split(".").filter(Boolean); if (parts.length === 0) return clone; const forbiddenKeys = /* @__PURE__ */ new Set([ "__proto__", "prototype", "constructor" ]); let current = clone; for (let i = 0; i < parts.length - 1; i++) { const key = parts[i]; if (forbiddenKeys.has(key)) return clone; const nextKey = parts[i + 1]; const nextIsIndex = !Number.isNaN(Number(nextKey)); current[key] = ensureNextContainer(current[key], nextIsIndex); current = current[key]; } const finalKey = parts.at(-1); if (forbiddenKeys.has(finalKey)) return clone; current[finalKey] = value; return clone; } __name(setValueByPath, "setValueByPath"); function isEqual(a, b) { if (a === b) return true; if (a == null || b == null || typeof a !== "object" || typeof b !== "object") return false; if (a instanceof Date && b instanceof Date) return equalDates(a, b); if (a instanceof RegExp && b instanceof RegExp) return equalRegExp(a, b); if (a instanceof Set && b instanceof Set) return equalSet(a, b); if (a instanceof Map && b instanceof Map) return equalMap(a, b); if (a instanceof ArrayBuffer && b instanceof ArrayBuffer) return equalArrayBuffer(a, b); if (Array.isArray(a) && Array.isArray(b)) return equalArray(a, b); return equalPlainObjects(a, b); } __name(isEqual, "isEqual"); function equalDates(a, b) { return a.getTime() === b.getTime(); } __name(equalDates, "equalDates"); function equalRegExp(a, b) { return a.source === b.source && a.flags === b.flags; } __name(equalRegExp, "equalRegExp"); function equalSet(a, b) { if (a.size !== b.size) return false; for (const v of a) if (!b.has(v)) return false; return true; } __name(equalSet, "equalSet"); function equalMap(a, b) { if (a.size !== b.size) return false; for (const [k, v] of a) { if (!b.has(k)) return false; if (!isEqual(v, b.get(k))) return false; } return true; } __name(equalMap, "equalMap"); function equalArrayBuffer(a, b) { return isEqual(new Uint8Array(a), new Uint8Array(b)); } __name(equalArrayBuffer, "equalArrayBuffer"); function equalArray(a, b) { if (a.length !== b.length) return false; for (let i = 0; i < a.length; i++) if (!isEqual(a[i], b[i])) return false; return true; } __name(equalArray, "equalArray"); function equalPlainObjects(a, b) { const aKeys = Object.keys(a); const bKeys = Object.keys(b); if (aKeys.length !== bKeys.length) return false; for (const key of aKeys) { if (!Object.hasOwn(b, key)) return false; if (!isEqual(a[key], b[key])) return false; } return true; } __name(equalPlainObjects, "equalPlainObjects"); function filterObject(obj, predicate) { return Object.fromEntries(Object.entries(obj).filter(([key, value]) => predicate(value, key, obj))); } __name(filterObject, "filterObject"); function mapObject(obj, mapFn) { return Object.fromEntries(Object.entries(obj).map(([key, value]) => [ key, mapFn(value, key, obj) ])); } __name(mapObject, "mapObject"); function _deepClone(value, seen) { if (typeof value === "function" || typeof value === "symbol") return value; if (value === null || typeof value !== "object") return value; if (seen.has(value)) return seen.get(value); if (Array.isArray(value)) return cloneArray(value, seen); if (value instanceof Date) return cloneDate(value); if (value instanceof Map) return cloneMap(value, seen); if (value instanceof Set) return cloneSet(value, seen); if (value instanceof RegExp) return cloneRegExp(value); if (ArrayBuffer.isView(value)) return cloneArrayBufferView(value, seen); if (value instanceof ArrayBuffer) return cloneArrayBuffer(value, seen); return cloneObject(value, seen); } __name(_deepClone, "_deepClone"); function cloneArray(arr, seen) { const result = []; seen.set(arr, result); for (const item of arr) result.push(_deepClone(item, seen)); return result; } __name(cloneArray, "cloneArray"); function cloneDate(d) { const r = new Date(d.getTime()); return r; } __name(cloneDate, "cloneDate"); function cloneMap(m, seen) { const result = /* @__PURE__ */ new Map(); seen.set(m, result); for (const [k, v] of m) result.set(_deepClone(k, seen), _deepClone(v, seen)); return result; } __name(cloneMap, "cloneMap"); function cloneSet(s, seen) { const result = /* @__PURE__ */ new Set(); seen.set(s, result); for (const v of s) result.add(_deepClone(v, seen)); return result; } __name(cloneSet, "cloneSet"); function cloneRegExp(r) { const result = new RegExp(r.source, r.flags); return result; } __name(cloneRegExp, "cloneRegExp"); function cloneArrayBufferView(view, seen) { if (view instanceof DataView) { const buf2 = _deepClone(view.buffer, seen); const clone2 = new DataView(buf2, view.byteOffset, view.byteLength); seen.set(view, clone2); return clone2; } const typed = view; const buf = _deepClone(typed.buffer, seen); const clone = new typed.constructor(buf, typed.byteOffset, typed.length); seen.set(view, clone); return clone; } __name(cloneArrayBufferView, "cloneArrayBufferView"); function cloneArrayBuffer(buf, seen) { const result = buf.slice(0); seen.set(buf, result); return result; } __name(cloneArrayBuffer, "cloneArrayBuffer"); function cloneObject(obj, seen) { const result = Object.create(Object.getPrototypeOf(obj)); seen.set(obj, result); for (const key of Reflect.ownKeys(obj)) { const desc = Object.getOwnPropertyDescriptor(obj, key); if (desc?.get || desc?.set) { Object.defineProperty(result, key, { get: desc.get, set: desc.set, enumerable: desc.enumerable, configurable: desc.configurable }); } else { Object.defineProperty(result, key, { value: _deepClone(obj[key], seen), writable: desc?.writable ?? true, enumerable: desc?.enumerable ?? true, configurable: desc?.configurable ?? true }); } } return result; } __name(cloneObject, "cloneObject"); function deepClone(value) { const seen = /* @__PURE__ */ new WeakMap(); return _deepClone(value, seen); } __name(deepClone, "deepClone"); function deepFreeze(obj) { Object.freeze(obj); for (const key of Reflect.ownKeys(obj)) { const val = obj[key]; if (isObject(val) && !Object.isFrozen(val)) { deepFreeze(val); } } return obj; } __name(deepFreeze, "deepFreeze"); function getAllPaths(obj, parentPath = "") { if (!isObject(obj)) return []; return Object.entries(obj).flatMap(([key, value]) => { const currentPath = parentPath ? `${parentPath}.${key}` : key; if (isObject(value)) { return [ currentPath, ...getAllPaths(value, currentPath) ]; } return [ currentPath ]; }); } __name(getAllPaths, "getAllPaths"); function invert(obj) { if (!isObject(obj)) return {}; return Object.fromEntries(Object.entries(obj).map(([k, v]) => [ String(v), k ])); } __name(invert, "invert"); function invertBy(obj, keyFn) { if (!isObject(obj)) return {}; const result = {}; for (const [key, value] of Object.entries(obj)) { const newKey = keyFn(value); if (!result[newKey]) result[newKey] = []; result[newKey].push(key); } return result; } __name(invertBy, "invertBy"); function transform(obj, fn) { if (!isObject(obj)) return {}; return Object.fromEntries(Object.entries(obj).map(([k, v]) => [ k, fn(v, k) ])); } __name(transform, "transform"); export { deepClone, deepFreeze, deepObjMerge, filterObject, flattenObject, getAllPaths, getValueByPath, invert, invertBy, isEqual, isObjEmpty, isObject, isPlainObject, mapObject, omit, pick, setValueByPath, transform };