forked from rsms/js-object-merge
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathobject-merge.js
82 lines (77 loc) · 1.79 KB
/
object-merge.js
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
Object.merge = function(o, a, b, objOrShallow) {
var r, k, v, ov, bv, inR,
isArray = Array.isArray(a),
hasConflicts, conflicts = {},
newInA = {}, newInB = {},
updatedInA = {}, updatedInB = {},
keyUnion = {},
deep = true;
if (typeof objOrShallow !== 'object') {
r = isArray ? [] : {};
deep = !objOrShallow;
} else {
r = objOrShallow;
}
for (k in b) {
if (isArray && isNaN((k = parseInt(k)))) continue;
v = b[k];
r[k] = v;
if (!(k in o)) {
newInB[k] = v;
} else if (v !== o[k]) {
updatedInB[k] = v;
}
}
for (k in a) {
if (isArray && isNaN((k = parseInt(k)))) continue;
v = a[k];
ov = o[k];
inR = (k in r);
if (!inR) {
r[k] = v;
} else if (r[k] !== v) {
bv = b[k];
if (deep && typeof v === 'object' && typeof bv === 'object') {
bv = Object.merge((k in o && typeof ov === 'object') ? ov : {}, v, bv);
r[k] = bv.merged;
if (bv.conflicts) {
conflicts[k] = {conflicts:bv.conflicts};
hasConflicts = true;
}
} else {
// if
if (bv === ov) {
// Pick A as B has not changed from O
r[k] = v;
} else if (v !== ov) {
// A, O and B are different
if (k in o)
conflicts[k] = {a:v, o:ov, b:bv};
else
conflicts[k] = {a:v, b:bv};
hasConflicts = true;
} // else Pick B (already done) as A has not changed from O
}
}
if (k in o) {
if (v !== ov)
updatedInA[k] = v;
} else {
newInA[k] = v;
}
}
r = {
merged:r,
added: {
a: newInA,
b: newInB
},
updated: {
a: updatedInA,
b: updatedInB
}
};
if (hasConflicts)
r.conflicts = conflicts;
return r;
}