1 | import { isSome } from './helpers.js';
|
2 | export 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 | }
|
69 | function isObject(item) {
|
70 | return item && typeof item === 'object' && !Array.isArray(item);
|
71 | }
|