Repository navigation
Expand file tree
/
Copy pathindex.ts
More file actions
126 lines (113 loc) · 3.77 KB
/
Copy pathindex.ts
File metadata and controls
126 lines (113 loc) · 3.77 KB
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import * as Interface from '../interface'
import * as Utils from '../utils'
import { Writable } from './writable'
import { Readable } from './readable'
import { Recordable } from './recordable'
/**
* Create a `Writable` store that allows both updating and reading by subscription.
* @param {*=}value initial value
* @param {StartStopNotifier=}start start and stop notifications for subscriptions
*/
export const writable = <T>(value: T, start: Interface.StartStopNotifier<T> = Utils.noop) => {
return new Writable<T>(value, start)
}
/**
* Creates a `Readable` store that allows reading by subscription.
* @param value initial value
* @param {StartStopNotifier}start start and stop notifications for subscriptions
*/
export const readable = <T>(value?: T, start: Interface.StartStopNotifier<T> = Utils.noop): Interface.Readable<T> => {
return new Readable<T>(value, start)
}
/**
* Derived value store by synchronizing one or more readable stores and
* applying an aggregation function over its input values.
*
* @param stores - input stores
* @param fn - function callback that aggregates the values
* @param initialValue - when used asynchronously
*/
export function derived<S extends Interface.Stores, T>(
stores: S,
callback: (values: Interface.StoresValues<S>, set: (value: T) => void) => Interface.Unsubscriber | void,
initialValue?: T
): Interface.Readable<T>
export function derived<T>(stores: Interface.Stores, callback: Function, initialValue?: T): Interface.Readable<T> {
const single = !Array.isArray(stores)
const storesArray: Array<Interface.Readable<any>> = single
? [stores as Interface.Readable<any>]
: stores as Array<Interface.Readable<any>>
const auto = callback.length < 2
return readable<T>(initialValue, (set) => {
let inited = false
const values: T[] = []
let pending = 0
let cleanup = Utils.noop
const sync = () => {
if (pending) return
cleanup()
const result = callback(single ? values[0] : values, set)
if (auto) {
set(result as T)
} else {
cleanup = Utils.isFunction(result) ? result as Interface.Unsubscriber : Utils.noop
}
}
const unsubscribers = storesArray.map((store, i) => Utils.subscribe(
store,
(value) => {
values[i] = value
pending &= ~(1 << i)
if (inited) {
sync()
}
},
() => {
pending |= (1 << i)
}),
)
inited = true
sync()
return function stop() {
Utils.runAll(unsubscribers)
cleanup()
}
})
}
/**
* Creates a store where changes are recorded.
* @param {T}value initial value
* @param option
* @example
* // Normal Usage
* const store = Store.recordable<any>({})
*
* // Advanced Usage
* const storeOption = {
* load: (recordData) => {}, // (optional)
* save: (recordData) => {}, // (optional)
* autostart: true, // (optional)
* limit: 10 // (optional)
* }
* const store = Store.recordable<any>(
* {}, // initial value
* storeOption,
* )
*/
export const recordable = <T>(
value: T,
option?: {
load?: (recordData?: Interface.IRecordData<string>) => Promise<undefined | Interface.IRecordData<string>>,
save?: (recordData: Interface.IRecordData<string>) => Promise<boolean>,
autostart?: boolean,
limit?: number
}
) => {
return new Recordable<T>({
store: writable(value),
load: option?.load,
save: option?.save,
autostart: (option && option.autostart !== undefined) ? option.autostart : true,
limit: option?.limit,
})
}