Skip to content

Commit d223628

Browse files
committed
utils: add handleDiffArray
1 parent f5b0cc9 commit d223628

File tree

3 files changed

+129
-2
lines changed

3 files changed

+129
-2
lines changed

packages/utils/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@solid-primitives/utils",
3-
"version": "2.0.3",
3+
"version": "2.1.0",
44
"description": "A bunch of reactive utility types and functions, for building primitives with Solid.js",
55
"author": "Damian Tarnawski @thetarnav <gthetarnav@gmail.com>",
66
"license": "MIT",

packages/utils/src/index.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,3 +378,48 @@ export function createStaticStore<T extends Readonly<AnyStatic>>(
378378

379379
return [store, setter];
380380
}
381+
382+
/**
383+
* Handle items removed and added to the array by diffing it by refference.
384+
*
385+
* @param current new array instance
386+
* @param prev previous array copy
387+
* @param handleAdded called once for every added item to array
388+
* @param handleRemoved called once for every removed from array
389+
*/
390+
export function handleDiffArray<T>(
391+
current: T[],
392+
prev: T[],
393+
handleAdded: (item: T) => void,
394+
handleRemoved: (item: T) => void
395+
): void {
396+
const currLength = current.length;
397+
const prevLength = prev.length;
398+
let i = 0;
399+
400+
if (!prevLength) {
401+
for (; i < currLength; i++) handleAdded(current[i]);
402+
return;
403+
}
404+
405+
if (!currLength) {
406+
for (; i < prevLength; i++) handleRemoved(prev[i]);
407+
return;
408+
}
409+
410+
for (; i < prevLength; i++) {
411+
if (prev[i] !== current[i]) break;
412+
}
413+
414+
let prevEl: T;
415+
let currEl: T;
416+
prev = prev.slice(i);
417+
current = current.slice(i);
418+
419+
for (prevEl of prev) {
420+
if (!current.includes(prevEl)) handleRemoved(prevEl);
421+
}
422+
for (currEl of current) {
423+
if (!prev.includes(currEl)) handleAdded(currEl);
424+
}
425+
}

packages/utils/test/index.test.ts

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { createComputed, createRoot } from "solid-js";
2-
import { createStaticStore } from "../src";
2+
import { createStaticStore, handleDiffArray } from "../src";
33
import { suite } from "uvu";
44
import * as assert from "uvu/assert";
55

@@ -63,3 +63,85 @@ tss("individual keys only update when changed", () =>
6363
// );
6464

6565
tss.run();
66+
67+
const da = suite("handleDiffArray");
68+
69+
da("handleAdded called for new array", () => {
70+
const a: string[] = [];
71+
const b = ["foo", "bar", "baz", "hello", "world"];
72+
const captured: any[] = [];
73+
handleDiffArray(
74+
b,
75+
a,
76+
item => {
77+
captured.push(item);
78+
},
79+
() => {
80+
throw "Should never run";
81+
}
82+
);
83+
assert.is(captured.length, 5);
84+
assert.ok(captured.includes("foo"));
85+
assert.ok(captured.includes("bar"));
86+
assert.ok(captured.includes("baz"));
87+
assert.ok(captured.includes("hello"));
88+
assert.ok(captured.includes("world"));
89+
});
90+
91+
da("handleRemoved for cleared array", () => {
92+
const a = ["foo", "bar", "baz", "hello", "world"];
93+
const b: string[] = [];
94+
const captured: any[] = [];
95+
handleDiffArray(
96+
b,
97+
a,
98+
() => {
99+
throw "Should never run";
100+
},
101+
item => {
102+
captured.push(item);
103+
}
104+
);
105+
assert.is(captured.length, 5);
106+
assert.ok(captured.includes("foo"));
107+
assert.ok(captured.includes("bar"));
108+
assert.ok(captured.includes("baz"));
109+
assert.ok(captured.includes("hello"));
110+
assert.ok(captured.includes("world"));
111+
});
112+
113+
da("callbacks shouldn't run for same array", () => {
114+
const a = ["foo", "bar", "baz", "hello", "world"];
115+
const b = ["foo", "bar", "baz", "hello", "world"];
116+
handleDiffArray(
117+
b,
118+
a,
119+
() => {
120+
throw "Should never run";
121+
},
122+
() => {
123+
throw "Should never run";
124+
}
125+
);
126+
});
127+
128+
da("calls callbacks for added and removed items", () => {
129+
const a = ["foo", "baz", "hello"];
130+
const b = ["foo", "bar", "hello", "world"];
131+
const capturedAdded: any[] = [];
132+
const capturedRemoved: any[] = [];
133+
handleDiffArray(
134+
b,
135+
a,
136+
item => capturedAdded.push(item),
137+
item => capturedRemoved.push(item)
138+
);
139+
assert.is(capturedAdded.length, 2);
140+
assert.ok(capturedAdded.includes("bar"));
141+
assert.ok(capturedAdded.includes("world"));
142+
143+
assert.is(capturedRemoved.length, 1);
144+
assert.ok(capturedRemoved.includes("baz"));
145+
});
146+
147+
da.run();

0 commit comments

Comments
 (0)