UNPKG

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