1 | import { safe_not_equal, noop, run_all, is_function } from '../internal';
|
2 | export { get_store_value as get } from '../internal';
|
3 |
|
4 | /**
|
5 | * Creates a `Readable` store that allows reading by subscription.
|
6 | * @param value initial value
|
7 | * @param {StartStopNotifier}start start and stop notifications for subscriptions
|
8 | */
|
9 | function readable(value, start) {
|
10 | return {
|
11 | subscribe: writable(value, start).subscribe,
|
12 | };
|
13 | }
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 | function writable(value, start = noop) {
|
20 | let stop;
|
21 | const subscribers = [];
|
22 | function set(new_value) {
|
23 | if (safe_not_equal(value, new_value)) {
|
24 | value = new_value;
|
25 | if (!stop) {
|
26 | return;
|
27 | }
|
28 | subscribers.forEach((s) => s[1]());
|
29 | subscribers.forEach((s) => s[0](value));
|
30 | }
|
31 | }
|
32 | function update(fn) {
|
33 | set(fn(value));
|
34 | }
|
35 | function subscribe(run, invalidate = noop) {
|
36 | const subscriber = [run, invalidate];
|
37 | subscribers.push(subscriber);
|
38 | if (subscribers.length === 1) {
|
39 | stop = start(set) || noop;
|
40 | }
|
41 | run(value);
|
42 | return () => {
|
43 | const index = subscribers.indexOf(subscriber);
|
44 | if (index !== -1) {
|
45 | subscribers.splice(index, 1);
|
46 | }
|
47 | if (subscribers.length === 0) {
|
48 | stop();
|
49 | stop = null;
|
50 | }
|
51 | };
|
52 | }
|
53 | return { set, update, subscribe };
|
54 | }
|
55 | /**
|
56 | * Derived value store by synchronizing one or more readable stores and
|
57 | * applying an aggregation function over its input values.
|
58 | * @param {Stores} stores input stores
|
59 | * @param {function(Stores=, function(*)=):*}fn function callback that aggregates the values
|
60 | * @param {*=}initial_value when used asynchronously
|
61 | */
|
62 | function derived(stores, fn, initial_value) {
|
63 | const single = !Array.isArray(stores);
|
64 | const stores_array = single
|
65 | ? [stores]
|
66 | : stores;
|
67 | const auto = fn.length < 2;
|
68 | const invalidators = [];
|
69 | const store = readable(initial_value, (set) => {
|
70 | let inited = false;
|
71 | const values = [];
|
72 | let pending = 0;
|
73 | let cleanup = noop;
|
74 | const sync = () => {
|
75 | if (pending) {
|
76 | return;
|
77 | }
|
78 | cleanup();
|
79 | const result = fn(single ? values[0] : values, set);
|
80 | if (auto) {
|
81 | set(result);
|
82 | }
|
83 | else {
|
84 | cleanup = is_function(result) ? result : noop;
|
85 | }
|
86 | };
|
87 | const unsubscribers = stores_array.map((store, i) => store.subscribe((value) => {
|
88 | values[i] = value;
|
89 | pending &= ~(1 << i);
|
90 | if (inited) {
|
91 | sync();
|
92 | }
|
93 | }, () => {
|
94 | run_all(invalidators);
|
95 | pending |= (1 << i);
|
96 | }));
|
97 | inited = true;
|
98 | sync();
|
99 | return function stop() {
|
100 | run_all(unsubscribers);
|
101 | cleanup();
|
102 | };
|
103 | });
|
104 | return {
|
105 | subscribe(run, invalidate = noop) {
|
106 | invalidators.push(invalidate);
|
107 | const unsubscribe = store.subscribe(run, invalidate);
|
108 | return () => {
|
109 | const index = invalidators.indexOf(invalidate);
|
110 | if (index !== -1) {
|
111 | invalidators.splice(index, 1);
|
112 | }
|
113 | unsubscribe();
|
114 | };
|
115 | }
|
116 | };
|
117 | }
|
118 |
|
119 | export { derived, readable, writable };
|