@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
JavaScript
/*
* 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 };