/
external-source.spec.ts
74 lines (62 loc) · 1.59 KB
/
external-source.spec.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
import { createRoot, createMemo, enableExternalSource } from "../src";
import "./MessageChannel";
global.queueMicrotask = (fn) => Promise.resolve().then(fn);
class ExternalSource<T = any> {
listeners: Set<() => void> = new Set();
constructor(private value: T) {}
update(x: T) {
this.value = x;
this.listeners.forEach(x => x());
}
get() {
if (listener) {
this.listeners.add(listener!);
sources.get(listener!)!.add(this);
}
return this.value;
}
removeListener(listener: () => void) {
this.listeners.delete(listener);
}
}
let listener: (() => void) | null = null;
let sources: Map<() => void, Set<ExternalSource>> = new Map();
enableExternalSource((fn, trigger) => {
sources.set(trigger, new Set());
return {
track: x => {
const tmp = listener;
// trigger could play the role of listener,as it has stable reference
listener = trigger;
try {
return fn(x);
} finally {
listener = tmp;
}
},
dispose: () => {
sources.get(trigger)!.forEach(x => x.removeListener(trigger));
sources.delete(trigger);
}
};
});
enableExternalSource(fn => {
return {
track: fn,
dispose: () => {}
};
}); // do nothing, make sure multiple factories be piped.
describe("external source", () => {
it("should trigger solid primitive update", () => {
createRoot(fn => {
const e = new ExternalSource(0);
const memo = createMemo(() => {
return e.get();
});
expect(memo()).toBe(0);
e.update(1);
expect(memo()).toBe(1);
fn();
});
});
});