@tmlmobilidade/utils
Version:
A collection of utility functions and helpers for the TML Mobilidade Go monorepo, providing common functionality for batching operations, caching, HTTP requests, object manipulation, permissions, and more.
82 lines (81 loc) • 2.53 kB
JavaScript
/* eslint-disable @typescript-eslint/no-explicit-any */
/**
* Merges two objects or arrays.
* @param target - The target object or array.
* @param source - The source object or array.
* @returns The merged object or array.
*
* @example
* const target = { a: 1, b: 2 };
* const source = { b: 3, c: 4 };
* const merged = mergeObjects(target, source);
* // merged will be:
* // { a: 1, b: 3, c: 4 }
*
* @example
* const target = [1, 2, 3];
* const source = [4, 5, 6];
* const merged = mergeObjects(target, source);
* // merged will be:
* // [1, 2, 3, 4, 5, 6]
*/
export function mergeObjects(target, source) {
if (Array.isArray(target) && Array.isArray(source)) {
// If arrays of primitives → unique values
if (target.every(x => !isObject(x)) && source.every(x => !isObject(x))) {
return Array.from(new Set([...source, ...target]));
}
// If arrays of objects → deduplicate by deep equality
const merged = [];
const all = [...target, ...source];
for (const obj of all) {
if (!merged.some(existing => deepEqual(existing, obj))) {
merged.push(mergeObjectsObject(existingDefaults(obj), obj));
}
}
return merged;
}
if (isObject(target) && isObject(source)) {
return mergeObjectsObject(target, source);
}
// default: override
return source;
}
function mergeObjectsObject(target, source) {
const result = { ...target };
for (const key of Object.keys(source)) {
if (key in target) {
result[key] = mergeObjects(target[key], source[key]);
}
else {
result[key] = source[key];
}
}
return result;
}
function isObject(item) {
return item !== null && typeof item === 'object' && !Array.isArray(item);
}
function deepEqual(a, b) {
if (a === b)
return true;
if (typeof a !== typeof b)
return false;
if (Array.isArray(a) && Array.isArray(b)) {
if (a.length !== b.length)
return false;
return a.every((val, i) => deepEqual(val, b[i]));
}
if (isObject(a) && isObject(b)) {
const keysA = Object.keys(a);
const keysB = Object.keys(b);
if (keysA.length !== keysB.length)
return false;
return keysA.every(k => deepEqual(a[k], b[k]));
}
return false;
}
// Helper: ensures merging empty object structure if needed
function existingDefaults(obj) {
return isObject(obj) ? {} : obj;
}