-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathdedupe.js
123 lines (92 loc) · 2.6 KB
/
dedupe.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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/**
* The ranges are first ordered by ascending `startOffset` and then by descending `endOffset`.
* This corresponds to a pre-order tree traversal.
*/
const sortRanges = (ranges) => {
ranges.sort((a, b) => {
if (a.start === b.start) {
return b.end - a.end;
}
return a.start - b.start;
});
};
const filterRanges = (ranges) => {
// remove start = end
return ranges.filter((range) => range.start < range.end);
};
// apply directly to css ranges
const dedupeFlatRanges = (ranges) => {
ranges = filterRanges(ranges);
if (ranges.length < 2) {
return ranges;
}
sortRanges(ranges);
ranges.reduce((prevRange, range) => {
// same start
if (range.start === prevRange.start) {
range.dedupe = true;
// equal prev
if (range.end === prevRange.end) {
return prevRange;
}
// less than prev end after new sort
return prevRange;
}
// already in the range
if (range.end <= prevRange.end) {
range.dedupe = true;
return prevRange;
}
// collected, update the end
if (range.start <= prevRange.end) {
range.dedupe = true;
prevRange.end = range.end;
return prevRange;
}
return range;
});
ranges = ranges.filter((it) => !it.dedupe);
return ranges;
};
const mergeRangesWith = (ranges, comparer, handler) => {
// ranges format
// { start: 0, end: 6, ... }
ranges = filterRanges(ranges);
if (ranges.length < 2) {
return ranges;
}
sortRanges(ranges);
let hasDedupe = false;
// merge count for same range
ranges.reduce((lastRange, range) => {
if (comparer(lastRange, range)) {
range.dedupe = true;
handler(lastRange, range);
hasDedupe = true;
return lastRange;
}
return range;
});
if (hasDedupe) {
// console.log(ranges);
ranges = ranges.filter((it) => !it.dedupe);
}
// console.log('ranges length after', ranges.length);
return ranges;
};
// apply to js count ranges
const dedupeCountRanges = (ranges) => {
const comparer = (lastRange, range) => {
return lastRange.start === range.start && lastRange.end === range.end;
};
const handler = (lastRange, range) => {
lastRange.count += range.count;
};
return mergeRangesWith(ranges, comparer, handler);
};
module.exports = {
sortRanges,
dedupeFlatRanges,
mergeRangesWith,
dedupeCountRanges
};