1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
// source: https://github.com/typeorm/typeorm/blob/master/src/util/OrmUtils.ts
// Copyright (c) 2015-2022 TypeORM. http://typeorm.github.io
/* eslint-disable @typescript-eslint/no-explicit-any */
// @fc-license-skip
export class OrmUtils {
// Checks if it's an object made by Object.create(null), {} or new Object()
private static isPlainObject(item: unknown) {
if (item === null || item === undefined) {
return false;
}
return !item.constructor || item.constructor === Object;
}
private static mergeArrayKey(
target: any,
key: number,
value: any,
memo: Map<any, any>,
) {
// Have we seen this before? Prevent infinite recursion.
if (memo.has(value)) {
target[key] = memo.get(value);
return;
}
if (value instanceof Promise) {
// Skip promises entirely.
// This is a hold-over from the old code & is because we don't want to pull in
// the lazy fields. Ideally we'd remove these promises via another function first
// but for now we have to do it here.
return;
}
if (!this.isPlainObject(value) && !Array.isArray(value)) {
target[key] = value;
return;
}
if (!target[key]) {
target[key] = Array.isArray(value) ? [] : {};
}
memo.set(value, target[key]);
this.merge(target[key], value, memo);
memo.delete(value);
}
private static mergeObjectKey(
target: any,
key: string,
value: any,
memo: Map<any, any>,
) {
// Have we seen this before? Prevent infinite recursion.
if (memo.has(value)) {
Object.assign(target, { [key]: memo.get(value) });
return;
}
if (value instanceof Promise) {
// Skip promises entirely.
// This is a hold-over from the old code & is because we don't want to pull in
// the lazy fields. Ideally we'd remove these promises via another function first
// but for now we have to do it here.
return;
}
if (!this.isPlainObject(value) && !Array.isArray(value)) {
Object.assign(target, { [key]: value });
return;
}
if (!target[key]) {
Object.assign(target, { [key]: value });
}
memo.set(value, target[key]);
this.merge(target[key], value, memo);
memo.delete(value);
}
private static merge(
target: any,
source: any,
memo: Map<any, any> = new Map(),
): any {
if (Array.isArray(target) && Array.isArray(source)) {
for (let key = 0; key < source.length; key++) {
this.mergeArrayKey(target, key, source[key], memo);
}
} else {
for (const key of Object.keys(source)) {
this.mergeObjectKey(target, key, source[key], memo);
}
}
}
/**
* Deep Object.assign.
*/
static mergeDeep(target: any, ...sources: any[]): any {
if (!sources.length) {
return target;
}
for (const source of sources) {
OrmUtils.merge(target, source);
}
return target;
}
}
|