-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.js
100 lines (84 loc) · 2.6 KB
/
index.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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
var Immutable = require("immutable");
var Map = Immutable.Map;
var OrderedMap = Immutable.OrderedMap;
var is = Immutable.is;
// TODO: eventually replace these with Immutable.isImmutable, .isOrdered, and
// Map.isMap - see https://github.com/facebook/immutable-js/issues/1165#issuecomment-292650855
var isImmutable = function(maybeImmutable) {
return Immutable.Iterable.isIterable(maybeImmutable);
};
var isOrdered = function(maybeOrdered) {
return maybeOrdered instanceof OrderedMap;
};
var isMap = function(maybeMap) {
return maybeMap instanceof Map
};
var deepEqual = require("deep-equal");
//======================================================================
// generate (diff)
function generate(before, after) {
var ordered = isOrdered(before) && isOrdered(after);
var diff = ordered ? new OrderedMap() : new Map();
return diff.withMutations(function (mutableDiff) {
var remainingAfter = after.withMutations(function (mutableAfter) {
before.forEach(function(bVal, key) {
// Ignore non-string keys
if (typeof key !== "string") return;
// Detect deletion
if (!after.has(key)) {
mutableDiff.set(key, null);
return;
}
var aVal = after.get(key);
// Recursively compare maps:
if (Map.isMap(bVal) && Map.isMap(aVal)) {
var subdiff = generate(bVal, aVal);
if (!subdiff.isEmpty()) {
mutableDiff.set(key, subdiff);
}
// Not both maps, so just compare values deeply
} else if (!deepEquals(bVal, aVal)) {
mutableDiff.set(key, aVal);
}
// Track which keys in `after` we've already processed
mutableAfter.delete(key);
});
});
// Record any additions (the remaining entries in remainingAfter).
// (First make sure all the keys in remainingAfter are strings)
remainingAfter = remainingAfter.filter(keyIsAString);
mutableDiff.merge(remainingAfter);
});
}
function deepEquals(a, b) {
if (isImmutable(a)) {
return !isImmutable(b) || is(a, b);
} else {
return isImmutable(b) || deepEqual(a, b, {strict: true});
}
}
function keyIsAString(__val, key) {
return typeof key === "string";
}
//======================================================================
// apply (patch)
function apply(before, patch) {
patch = patch.filter(keyIsAString)
var keysToDelete = [];
return before.withMutations(function(mutable) {
patch.forEach(function(val, key) {
var oldVal = mutable.get(key);
if (val === null) {
mutable.delete(key);
} else if (isMap(val) && isMap(oldVal)) {
mutable.set(key, apply(oldVal, val));
} else {
mutable.set(key, val);
}
});
});
}
module.exports = {
generate: generate,
apply: apply,
}