-
-
Notifications
You must be signed in to change notification settings - Fork 6
/
diff.ts
81 lines (60 loc) 路 2.12 KB
/
diff.ts
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
import { ReduceArguments, toReduceArguments } from "./reduceify.ts";
import { contains } from "./contains.ts";
import { removeDuplicates } from "./removeDuplicates.ts";
import { id } from "https://raw.githubusercontent.com/garronej/tsafe/v1.0.0/deno_dist/id.ts";
export type ArrDiff<T> = {
added: readonly T[];
removed: readonly T[];
}
const areStrictEqual = (e1: unknown, e2: unknown) => e1 === e2;
/** WARNING: Providing areEquals significantly impact performances */
export function arrDiff<ArrOf>(
arr: readonly ArrOf[],
newArr: readonly ArrOf[],
areEquals: (e1: ArrOf, e2: ArrOf) => boolean = areStrictEqual
): ArrDiff<ArrOf> {
const arrDiff = {
"added": id<ArrOf[]>([]),
"removed": id<ArrOf[]>([])
};
if (
arr.length === newArr.length &&
arr.every((elem, i) => areEquals(elem, newArr[i]))
) {
return arrDiff;
}
if (areEquals !== areStrictEqual) {
return {
"added": newArr
.reduce(...removeDuplicates<ArrOf>(areEquals))
.filter(newEntry => !arr.reduce(...contains<ArrOf>(entry => areEquals(entry, newEntry)))),
"removed": arr
.reduce(...removeDuplicates<ArrOf>(areEquals))
.filter(entry => !newArr.reduce(...contains<ArrOf>(newEntry => areEquals(newEntry, entry))))
};
}
const arrAsSet = new Set<ArrOf>(arr);
const newArrAsSet = new Set(newArr);
arrAsSet.forEach(elem => {
if (newArrAsSet.has(elem)) {
return;
}
arrDiff.removed.push(elem);
});
newArrAsSet.forEach(elem => {
if (arrAsSet.has(elem)) {
return;
}
arrDiff.added.push(elem);
});
return arrDiff;
}
export function diff<ArrOf>(
newArr: readonly ArrOf[],
areEquals?: (e1: ArrOf, e2: ArrOf) => boolean
): ReduceArguments<ArrOf, ArrDiff<ArrOf>> {
return toReduceArguments(arrDiff, newArr, areEquals);
}
export function diffFactory({ areEquals }: { areEquals: <T>(e1: T, e2: T) => boolean; }) {
return { "diff": <ArrOf>(newArr: readonly ArrOf[]) => diff<ArrOf>(newArr, areEquals) };
}