UNPKG

3.66 kBJavaScriptView Raw
1import { safe_not_equal, noop, run_all, is_function } from '../internal';
2export { 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 */
9function readable(value, start) {
10 return {
11 subscribe: writable(value, start).subscribe,
12 };
13}
14/**
15 * Create a `Writable` store that allows both updating and reading by subscription.
16 * @param {*=}value initial value
17 * @param {StartStopNotifier=}start start and stop notifications for subscriptions
18 */
19function 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; // not ready
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 */
62function 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
119export { derived, readable, writable };