ts-prime
Version:
A utility library for JavaScript and Typescript.
112 lines (111 loc) • 4.04 kB
JavaScript
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __spreadArrays = (this && this.__spreadArrays) || function () {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
};
import { isDefined, isArray, isObject } from './guards';
import { uniq } from './uniq';
import { clone } from './clone';
function isCyclic(object) {
var seenObjects = new WeakMap(); // use to keep track of which objects have been seen.
function detectCycle(obj) {
// If 'obj' is an actual object (i.e., has the form of '{}'), check
// if it's been seen already.
if (isObject(obj) &&
Object.prototype.toString.call(obj) == '[object Object]') {
if (seenObjects.has(obj)) {
return true;
}
// If 'obj' hasn't been seen, add it to 'seenObjects'.
// Since 'obj' is used as a key, the value of 'seenObjects[obj]'
// is irrelevant and can be set as literally anything you want. I
// just went with 'undefined'.
seenObjects.set(obj, undefined);
// Recurse through the object, looking for more circular references.
for (var key in obj) {
if (detectCycle(obj[key])) {
return true;
}
}
// If 'obj' is an array, check if any of it's elements are
// an object that has been seen already.
}
else if (Array.isArray(obj)) {
for (var i in obj) {
if (detectCycle(obj[i])) {
return true;
}
}
}
return false;
}
return detectCycle(object);
}
/**
* Merging @param a and @param b recursively @param a is most important
*/
function recursiveMerge(a, b) {
if (isObject(a) && isObject(b)) {
var output = __assign({}, a);
var keys = uniq(__spreadArrays(Object.keys(a), Object.keys(b)));
for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
var k = keys_1[_i];
// If object cyclic I will not try to merge objects
if (isCyclic(a[k])) {
output[k] = a[k];
continue;
}
output[k] = recursiveMerge(a[k], b[k]);
}
return output;
}
if (isArray(a) && isArray(b)) {
// This step will nicely merge primitive values but will leave objects as duplicates
return uniq(a.concat(b));
}
// If we here we know that a is primitive value if it's defined we chose a over b
// Unless this value is empty string
if (isDefined(a)) {
return a;
}
return b;
}
export function deepMergeLeft(target) {
var sources = [];
for (var _i = 1; _i < arguments.length; _i++) {
sources[_i - 1] = arguments[_i];
}
var output = __assign({}, target);
for (var _a = 0, sources_1 = sources; _a < sources_1.length; _a++) {
var source = sources_1[_a];
output = recursiveMerge(output, source);
}
return output;
}
export function deepMergeRight(target) {
var sources = [];
for (var _i = 1; _i < arguments.length; _i++) {
sources[_i - 1] = arguments[_i];
}
var output = clone(target);
for (var _a = 0, sources_2 = sources; _a < sources_2.length; _a++) {
var source = sources_2[_a];
// Only difference from mergeDeepLeft
// That source go first and output last
output = recursiveMerge(source, output);
}
return output;
}