-
Notifications
You must be signed in to change notification settings - Fork 0
/
apply.js
73 lines (64 loc) · 2.14 KB
/
apply.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
// Apply each update to the array.
// The original array is not mutated.
// This uses imperative logic for performance.
export const applyUpdates = function (array, updates, { merge }) {
const { array: arrayA, updates: updatesA } = applyAny(array, updates, merge)
const newArray = []
// eslint-disable-next-line fp/no-let
let previousIndex = -1
// eslint-disable-next-line fp/no-loops
for (const update of updatesA) {
// eslint-disable-next-line fp/no-mutation
previousIndex = applyUpdate({
update,
array: arrayA,
newArray,
previousIndex,
merge,
})
}
pushValues(arrayA, newArray, previousIndex + 1, arrayA.length)
return newArray
}
// When a '*' update is present, it modifies all value of the array
const applyAny = function (array, updates, merge) {
if (updates.length === 0 || !updates[0].any) {
return { array, updates }
}
const [{ items }, ...updatesA] = updates
const arrayA = array.flatMap((_, index) =>
applyMerge({ items, array, index, merge }),
)
return { array: arrayA, updates: updatesA }
}
const applyUpdate = function ({
update: { index, items },
array,
newArray,
previousIndex,
merge,
}) {
pushValues(array, newArray, previousIndex + 1, Math.ceil(index))
const itemsA = applyMerge({ items, array, index, merge })
pushValues(itemsA, newArray, 0, itemsA.length)
return Math.floor(index)
}
// The `merge()` option can be used to merge the new value with the current one.
// It is called even if the current value is `undefined`
// - Even if `ceiledIndex >= array.length`
// It is not called if the new value is being prepended.
const applyMerge = function ({ items, array, index, merge }) {
if (merge === undefined || !Number.isInteger(index)) {
return items
}
const oldValue = array[index]
return items.map((newValue) => merge(oldValue, newValue))
}
// eslint-disable-next-line max-params
const pushValues = function (array, newArray, from, to) {
// eslint-disable-next-line fp/no-loops, fp/no-mutation, fp/no-let
for (let index = from; index < to; index += 1) {
// eslint-disable-next-line fp/no-mutating-methods
newArray.push(array[index])
}
}