UNPKG

3.04 kBJavaScriptView Raw
1import { isSome } from './helpers.js';
2export function mergeDeep(sources, respectPrototype = false, respectArrays = false, respectArrayLength = false) {
3 if (respectArrays && respectArrayLength) {
4 let expectedLength;
5 const areArraysInTheSameLength = sources.every(source => {
6 if (Array.isArray(source)) {
7 if (expectedLength === undefined) {
8 expectedLength = source.length;
9 return true;
10 }
11 else if (expectedLength === source.length) {
12 return true;
13 }
14 }
15 return false;
16 });
17 if (areArraysInTheSameLength) {
18 return new Array(expectedLength).fill(null).map((_, index) => mergeDeep(sources.map(source => source[index]), respectPrototype, respectArrays, respectArrayLength));
19 }
20 }
21 const output = {};
22 if (respectPrototype) {
23 Object.setPrototypeOf(output, Object.create(Object.getPrototypeOf(sources[0])));
24 }
25 for (const source of sources) {
26 if (isObject(source)) {
27 if (respectPrototype) {
28 const outputPrototype = Object.getPrototypeOf(output);
29 const sourcePrototype = Object.getPrototypeOf(source);
30 if (sourcePrototype) {
31 for (const key of Object.getOwnPropertyNames(sourcePrototype)) {
32 const descriptor = Object.getOwnPropertyDescriptor(sourcePrototype, key);
33 if (isSome(descriptor)) {
34 Object.defineProperty(outputPrototype, key, descriptor);
35 }
36 }
37 }
38 }
39 for (const key in source) {
40 if (isObject(source[key])) {
41 if (!(key in output)) {
42 Object.assign(output, { [key]: source[key] });
43 }
44 else {
45 output[key] = mergeDeep([output[key], source[key]], respectPrototype, respectArrays, respectArrayLength);
46 }
47 }
48 else if (respectArrays && Array.isArray(output[key])) {
49 if (Array.isArray(source[key])) {
50 if (respectArrayLength && output[key].length === source[key].length) {
51 output[key] = mergeDeep([output[key], source[key]], respectPrototype, respectArrays, respectArrayLength);
52 }
53 else {
54 output[key].push(...source[key]);
55 }
56 }
57 else {
58 output[key].push(source[key]);
59 }
60 }
61 else {
62 Object.assign(output, { [key]: source[key] });
63 }
64 }
65 }
66 }
67 return output;
68}
69function isObject(item) {
70 return item && typeof item === 'object' && !Array.isArray(item);
71}