@zeix/cause-effect 0.17.3 → 0.18.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.ai-context.md +169 -227
- package/.cursorrules +41 -35
- package/.github/copilot-instructions.md +176 -116
- package/ARCHITECTURE.md +276 -0
- package/CHANGELOG.md +29 -0
- package/CLAUDE.md +201 -143
- package/GUIDE.md +298 -0
- package/README.md +246 -193
- package/REQUIREMENTS.md +100 -0
- package/bench/reactivity.bench.ts +577 -0
- package/context7.json +4 -0
- package/examples/events-sensor.ts +187 -0
- package/examples/selector-sensor.ts +173 -0
- package/index.dev.js +1390 -1008
- package/index.js +1 -1
- package/index.ts +60 -74
- package/package.json +5 -2
- package/skills/changelog-keeper/SKILL.md +59 -0
- package/skills/changelog-keeper/agents/openai.yaml +4 -0
- package/src/errors.ts +118 -74
- package/src/graph.ts +612 -0
- package/src/nodes/collection.ts +512 -0
- package/src/nodes/effect.ts +149 -0
- package/src/nodes/list.ts +589 -0
- package/src/nodes/memo.ts +148 -0
- package/src/nodes/sensor.ts +149 -0
- package/src/nodes/state.ts +135 -0
- package/src/nodes/store.ts +378 -0
- package/src/nodes/task.ts +174 -0
- package/src/signal.ts +112 -66
- package/src/util.ts +26 -57
- package/test/batch.test.ts +96 -62
- package/test/benchmark.test.ts +473 -487
- package/test/collection.test.ts +456 -707
- package/test/effect.test.ts +293 -696
- package/test/list.test.ts +335 -592
- package/test/memo.test.ts +574 -0
- package/test/regression.test.ts +156 -0
- package/test/scope.test.ts +191 -0
- package/test/sensor.test.ts +454 -0
- package/test/signal.test.ts +220 -213
- package/test/state.test.ts +217 -265
- package/test/store.test.ts +346 -446
- package/test/task.test.ts +529 -0
- package/test/untrack.test.ts +167 -0
- package/types/index.d.ts +13 -15
- package/types/src/errors.d.ts +73 -17
- package/types/src/graph.d.ts +218 -0
- package/types/src/nodes/collection.d.ts +69 -0
- package/types/src/nodes/effect.d.ts +48 -0
- package/types/src/nodes/list.d.ts +66 -0
- package/types/src/nodes/memo.d.ts +63 -0
- package/types/src/nodes/sensor.d.ts +81 -0
- package/types/src/nodes/state.d.ts +78 -0
- package/types/src/nodes/store.d.ts +51 -0
- package/types/src/nodes/task.d.ts +79 -0
- package/types/src/signal.d.ts +43 -29
- package/types/src/util.d.ts +9 -16
- package/archive/benchmark.ts +0 -683
- package/archive/collection.ts +0 -253
- package/archive/composite.ts +0 -85
- package/archive/computed.ts +0 -195
- package/archive/list.ts +0 -483
- package/archive/memo.ts +0 -139
- package/archive/state.ts +0 -90
- package/archive/store.ts +0 -298
- package/archive/task.ts +0 -189
- package/src/classes/collection.ts +0 -245
- package/src/classes/computed.ts +0 -349
- package/src/classes/list.ts +0 -343
- package/src/classes/ref.ts +0 -70
- package/src/classes/state.ts +0 -102
- package/src/classes/store.ts +0 -262
- package/src/diff.ts +0 -138
- package/src/effect.ts +0 -93
- package/src/match.ts +0 -45
- package/src/resolve.ts +0 -49
- package/src/system.ts +0 -257
- package/test/computed.test.ts +0 -1108
- package/test/diff.test.ts +0 -955
- package/test/match.test.ts +0 -388
- package/test/ref.test.ts +0 -353
- package/test/resolve.test.ts +0 -154
- package/types/src/classes/collection.d.ts +0 -45
- package/types/src/classes/computed.d.ts +0 -94
- package/types/src/classes/list.d.ts +0 -43
- package/types/src/classes/ref.d.ts +0 -35
- package/types/src/classes/state.d.ts +0 -49
- package/types/src/classes/store.d.ts +0 -52
- package/types/src/diff.d.ts +0 -28
- package/types/src/effect.d.ts +0 -15
- package/types/src/match.d.ts +0 -21
- package/types/src/resolve.d.ts +0 -29
- package/types/src/system.d.ts +0 -78
package/archive/store.ts
DELETED
|
@@ -1,298 +0,0 @@
|
|
|
1
|
-
import { type DiffResult, diff, type UnknownRecord } from '../src/diff'
|
|
2
|
-
import {
|
|
3
|
-
DuplicateKeyError,
|
|
4
|
-
InvalidSignalValueError,
|
|
5
|
-
NullishSignalValueError,
|
|
6
|
-
ReadonlySignalError,
|
|
7
|
-
} from '../src/errors'
|
|
8
|
-
import { isMutableSignal, type MutableSignal } from '../src/signal'
|
|
9
|
-
import {
|
|
10
|
-
batch,
|
|
11
|
-
notifyWatchers,
|
|
12
|
-
subscribeActiveWatcher,
|
|
13
|
-
UNSET,
|
|
14
|
-
type Watcher,
|
|
15
|
-
} from '../src/system'
|
|
16
|
-
import { isFunction, isObjectOfType, isRecord, isSymbol } from '../src/util'
|
|
17
|
-
import { isComputed } from './computed'
|
|
18
|
-
import { createList, isList, type List } from './list'
|
|
19
|
-
import { createState, isState, type State } from './state'
|
|
20
|
-
|
|
21
|
-
/* === Types === */
|
|
22
|
-
|
|
23
|
-
type StoreKeySignal<T extends {}> = T extends readonly (infer U extends {})[]
|
|
24
|
-
? List<U>
|
|
25
|
-
: T extends UnknownRecord
|
|
26
|
-
? Store<T>
|
|
27
|
-
: State<T>
|
|
28
|
-
|
|
29
|
-
type Store<T extends UnknownRecord> = {
|
|
30
|
-
[K in keyof T]: T[K] extends readonly (infer U extends {})[]
|
|
31
|
-
? List<U>
|
|
32
|
-
: T extends Record<string, unknown>
|
|
33
|
-
? Store<T[K] & {}>
|
|
34
|
-
: State<T[K] & {}>
|
|
35
|
-
} & {
|
|
36
|
-
readonly [Symbol.toStringTag]: 'Store'
|
|
37
|
-
[Symbol.iterator](): IterableIterator<
|
|
38
|
-
[
|
|
39
|
-
Extract<keyof T, string>,
|
|
40
|
-
StoreKeySignal<T[Extract<keyof T, string>] & {}>,
|
|
41
|
-
]
|
|
42
|
-
>
|
|
43
|
-
add<K extends Extract<keyof T, string>>(key: K, value: T[K]): K
|
|
44
|
-
byKey<K extends Extract<keyof T, string>>(key: K): StoreKeySignal<T[K] & {}>
|
|
45
|
-
get(): T
|
|
46
|
-
keyAt(index: number): string | undefined
|
|
47
|
-
indexOfKey(key: string): number
|
|
48
|
-
set(value: T): void
|
|
49
|
-
update(fn: (value: T) => T): void
|
|
50
|
-
sort<U = T[Extract<keyof T, string>]>(
|
|
51
|
-
compareFn?: (a: U, b: U) => number,
|
|
52
|
-
): void
|
|
53
|
-
remove<K extends Extract<keyof T, string>>(key: K): void
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/* === Constants === */
|
|
57
|
-
|
|
58
|
-
const TYPE_STORE = 'Store' as const
|
|
59
|
-
|
|
60
|
-
/* === Functions === */
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Create a new store with deeply nested reactive properties
|
|
64
|
-
*
|
|
65
|
-
* Supports both objects and arrays as initial values. Arrays are converted
|
|
66
|
-
* to records internally for storage but maintain their array type through
|
|
67
|
-
* the .get() method, which automatically converts objects with consecutive
|
|
68
|
-
* numeric keys back to arrays.
|
|
69
|
-
*
|
|
70
|
-
* For array-like stores, an optional keyConfig parameter can be provided to
|
|
71
|
-
* generate stable keys for array items. This creates persistent references
|
|
72
|
-
* that remain stable across sort and compact operations.
|
|
73
|
-
*
|
|
74
|
-
* @since 0.15.0
|
|
75
|
-
* @param {T} initialValue - initial object or array value of the store
|
|
76
|
-
* @returns {Store<T>} - new store with reactive properties that preserves the original type T
|
|
77
|
-
*/
|
|
78
|
-
const createStore = <T extends UnknownRecord>(initialValue: T): Store<T> => {
|
|
79
|
-
if (initialValue == null) throw new NullishSignalValueError('store')
|
|
80
|
-
|
|
81
|
-
const watchers = new Set<Watcher>()
|
|
82
|
-
const signals = new Map<
|
|
83
|
-
string,
|
|
84
|
-
MutableSignal<T[Extract<keyof T, string>] & {}>
|
|
85
|
-
>()
|
|
86
|
-
const ownWatchers = new Map<string, Watcher>()
|
|
87
|
-
|
|
88
|
-
// Get current record
|
|
89
|
-
const current = (): T => {
|
|
90
|
-
const record = {} as Record<string, unknown>
|
|
91
|
-
for (const [key, signal] of signals) record[key] = signal.get()
|
|
92
|
-
return record as T
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Validate input
|
|
96
|
-
const isValidValue = <T>(
|
|
97
|
-
key: string,
|
|
98
|
-
value: T,
|
|
99
|
-
): value is NonNullable<T> => {
|
|
100
|
-
if (value == null)
|
|
101
|
-
throw new NullishSignalValueError(`store for key "${key}"`)
|
|
102
|
-
if (value === UNSET) return true
|
|
103
|
-
if (isSymbol(value) || isFunction(value) || isComputed(value))
|
|
104
|
-
throw new InvalidSignalValueError(`store for key "${key}"`, value)
|
|
105
|
-
return true
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Add nested signal and effect
|
|
109
|
-
const addProperty = <K extends keyof T & string>(
|
|
110
|
-
key: K,
|
|
111
|
-
value: T[K],
|
|
112
|
-
single = false,
|
|
113
|
-
): boolean => {
|
|
114
|
-
if (!isValidValue(key, value)) return false
|
|
115
|
-
|
|
116
|
-
// Create signal for key
|
|
117
|
-
// @ts-expect-error non-matching signal types
|
|
118
|
-
const signal: MutableSignal<T[K] & {}> =
|
|
119
|
-
isState(value) || isStore(value) || isList(value)
|
|
120
|
-
? (value as unknown as MutableSignal<T[K] & {}>)
|
|
121
|
-
: isRecord(value)
|
|
122
|
-
? createStore(value)
|
|
123
|
-
: Array.isArray(value)
|
|
124
|
-
? createList(value)
|
|
125
|
-
: createState(value)
|
|
126
|
-
|
|
127
|
-
// Set internal states
|
|
128
|
-
// @ts-expect-error non-matching signal types
|
|
129
|
-
signals.set(key, signal)
|
|
130
|
-
|
|
131
|
-
if (single) {
|
|
132
|
-
notifyWatchers(watchers)
|
|
133
|
-
}
|
|
134
|
-
return true
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Remove nested signal and effect
|
|
138
|
-
const removeProperty = (key: string, single = false) => {
|
|
139
|
-
// Remove signal for key
|
|
140
|
-
const ok = signals.delete(key)
|
|
141
|
-
if (!ok) return
|
|
142
|
-
|
|
143
|
-
// Clean up internal states
|
|
144
|
-
const watcher = ownWatchers.get(key)
|
|
145
|
-
if (watcher) {
|
|
146
|
-
watcher.stop()
|
|
147
|
-
ownWatchers.delete(key)
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
if (single) {
|
|
151
|
-
notifyWatchers(watchers)
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Commit batched changes and emit notifications
|
|
156
|
-
const batchChanges = (changes: DiffResult) => {
|
|
157
|
-
// Additions
|
|
158
|
-
if (Object.keys(changes.add).length) {
|
|
159
|
-
for (const key in changes.add)
|
|
160
|
-
addProperty(
|
|
161
|
-
key,
|
|
162
|
-
changes.add[key] as T[Extract<keyof T, string>] & {},
|
|
163
|
-
false,
|
|
164
|
-
)
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// Changes
|
|
168
|
-
if (Object.keys(changes.change).length) {
|
|
169
|
-
batch(() => {
|
|
170
|
-
for (const key in changes.change) {
|
|
171
|
-
const value = changes.change[key] as T[Extract<
|
|
172
|
-
keyof T,
|
|
173
|
-
string
|
|
174
|
-
>]
|
|
175
|
-
if (!isValidValue(key, value)) continue
|
|
176
|
-
|
|
177
|
-
const signal = signals.get(key)
|
|
178
|
-
if (isMutableSignal(signal)) signal.set(value)
|
|
179
|
-
else throw new ReadonlySignalError(key, value)
|
|
180
|
-
}
|
|
181
|
-
})
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// Removals
|
|
185
|
-
if (Object.keys(changes.remove).length) {
|
|
186
|
-
for (const key in changes.remove) removeProperty(key)
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
return changes.changed
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
// Reconcile data and dispatch events
|
|
193
|
-
const reconcile = (oldValue: T, newValue: T): boolean =>
|
|
194
|
-
batchChanges(diff(oldValue, newValue))
|
|
195
|
-
|
|
196
|
-
// Initialize data
|
|
197
|
-
reconcile({} as T, initialValue)
|
|
198
|
-
|
|
199
|
-
// Methods and Properties
|
|
200
|
-
const prototype: Record<PropertyKey, unknown> = {}
|
|
201
|
-
Object.defineProperties(prototype, {
|
|
202
|
-
[Symbol.toStringTag]: {
|
|
203
|
-
value: TYPE_STORE,
|
|
204
|
-
},
|
|
205
|
-
[Symbol.iterator]: {
|
|
206
|
-
value: function* () {
|
|
207
|
-
for (const [key, signal] of signals) yield [key, signal]
|
|
208
|
-
},
|
|
209
|
-
},
|
|
210
|
-
add: {
|
|
211
|
-
value: <K extends Extract<keyof T, string>>(
|
|
212
|
-
key: K,
|
|
213
|
-
value: T[K],
|
|
214
|
-
): K => {
|
|
215
|
-
if (signals.has(key))
|
|
216
|
-
throw new DuplicateKeyError('store', key, value)
|
|
217
|
-
|
|
218
|
-
addProperty(key, value, true)
|
|
219
|
-
return key
|
|
220
|
-
},
|
|
221
|
-
},
|
|
222
|
-
byKey: {
|
|
223
|
-
value: (key: string) => {
|
|
224
|
-
return signals.get(key)
|
|
225
|
-
},
|
|
226
|
-
},
|
|
227
|
-
get: {
|
|
228
|
-
value: (): T => {
|
|
229
|
-
subscribeActiveWatcher(watchers)
|
|
230
|
-
return current()
|
|
231
|
-
},
|
|
232
|
-
},
|
|
233
|
-
remove: {
|
|
234
|
-
value: (key: string): void => {
|
|
235
|
-
if (signals.has(key)) removeProperty(key, true)
|
|
236
|
-
},
|
|
237
|
-
},
|
|
238
|
-
set: {
|
|
239
|
-
value: (newValue: T): void => {
|
|
240
|
-
if (reconcile(current(), newValue)) {
|
|
241
|
-
notifyWatchers(watchers)
|
|
242
|
-
if (UNSET === newValue) watchers.clear()
|
|
243
|
-
}
|
|
244
|
-
},
|
|
245
|
-
},
|
|
246
|
-
update: {
|
|
247
|
-
value: (fn: (oldValue: T) => T): void => {
|
|
248
|
-
store.set(fn(current()))
|
|
249
|
-
},
|
|
250
|
-
},
|
|
251
|
-
})
|
|
252
|
-
|
|
253
|
-
// Return proxy directly with integrated signal methods
|
|
254
|
-
const store = new Proxy(prototype as Store<T>, {
|
|
255
|
-
get(target, prop) {
|
|
256
|
-
if (prop in target) return Reflect.get(target, prop)
|
|
257
|
-
if (!isSymbol(prop)) return signals.get(prop)
|
|
258
|
-
},
|
|
259
|
-
has(target, prop) {
|
|
260
|
-
if (prop in target) return true
|
|
261
|
-
return signals.has(String(prop))
|
|
262
|
-
},
|
|
263
|
-
ownKeys(target) {
|
|
264
|
-
const staticKeys = Reflect.ownKeys(target)
|
|
265
|
-
return [...new Set([...signals.keys(), ...staticKeys])]
|
|
266
|
-
},
|
|
267
|
-
getOwnPropertyDescriptor(target, prop) {
|
|
268
|
-
if (prop in target)
|
|
269
|
-
return Reflect.getOwnPropertyDescriptor(target, prop)
|
|
270
|
-
if (isSymbol(prop)) return undefined
|
|
271
|
-
|
|
272
|
-
const signal = signals.get(prop)
|
|
273
|
-
return signal
|
|
274
|
-
? {
|
|
275
|
-
enumerable: true,
|
|
276
|
-
configurable: true,
|
|
277
|
-
writable: true,
|
|
278
|
-
value: signal,
|
|
279
|
-
}
|
|
280
|
-
: undefined
|
|
281
|
-
},
|
|
282
|
-
})
|
|
283
|
-
return store
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* Check if the provided value is a Store instance
|
|
288
|
-
*
|
|
289
|
-
* @since 0.15.0
|
|
290
|
-
* @param {unknown} value - Value to check
|
|
291
|
-
* @returns {boolean} - True if the value is a Store instance, false otherwise
|
|
292
|
-
*/
|
|
293
|
-
const isStore = <T extends UnknownRecord>(value: unknown): value is Store<T> =>
|
|
294
|
-
isObjectOfType(value, TYPE_STORE)
|
|
295
|
-
|
|
296
|
-
/* === Exports === */
|
|
297
|
-
|
|
298
|
-
export { TYPE_STORE, isStore, createStore, type Store }
|
package/archive/task.ts
DELETED
|
@@ -1,189 +0,0 @@
|
|
|
1
|
-
import { isEqual } from '../src/diff'
|
|
2
|
-
import {
|
|
3
|
-
CircularDependencyError,
|
|
4
|
-
createError,
|
|
5
|
-
InvalidCallbackError,
|
|
6
|
-
NullishSignalValueError,
|
|
7
|
-
} from '../src/errors'
|
|
8
|
-
import {
|
|
9
|
-
createWatcher,
|
|
10
|
-
flush,
|
|
11
|
-
notifyWatchers,
|
|
12
|
-
subscribeActiveWatcher,
|
|
13
|
-
UNSET,
|
|
14
|
-
type Watcher,
|
|
15
|
-
} from '../src/system'
|
|
16
|
-
import { isAbortError, isAsyncFunction, isObjectOfType } from '../src/util'
|
|
17
|
-
|
|
18
|
-
/* === Types === */
|
|
19
|
-
|
|
20
|
-
type Task<T extends {}> = {
|
|
21
|
-
readonly [Symbol.toStringTag]: 'Task'
|
|
22
|
-
get(): T
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
type TaskCallback<T extends {} & { then?: undefined }> = (
|
|
26
|
-
oldValue: T,
|
|
27
|
-
abort: AbortSignal,
|
|
28
|
-
) => Promise<T>
|
|
29
|
-
|
|
30
|
-
/* === Constants === */
|
|
31
|
-
|
|
32
|
-
const TYPE_TASK = 'Task' as const
|
|
33
|
-
|
|
34
|
-
/* === Functions === */
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Create a derived signal from existing signals
|
|
38
|
-
*
|
|
39
|
-
* @since 0.9.0
|
|
40
|
-
* @param {TaskCallback<T>} callback - Computation callback function
|
|
41
|
-
* @returns {Task<T>} - Computed signal
|
|
42
|
-
*/
|
|
43
|
-
const createTask = <T extends {}>(
|
|
44
|
-
callback: TaskCallback<T>,
|
|
45
|
-
initialValue: T = UNSET,
|
|
46
|
-
): Task<T> => {
|
|
47
|
-
if (!isTaskCallback(callback))
|
|
48
|
-
throw new InvalidCallbackError('task', callback)
|
|
49
|
-
if (initialValue == null) throw new NullishSignalValueError('task')
|
|
50
|
-
|
|
51
|
-
const watchers: Set<Watcher> = new Set()
|
|
52
|
-
|
|
53
|
-
// Internal state
|
|
54
|
-
let value: T = initialValue
|
|
55
|
-
let error: Error | undefined
|
|
56
|
-
let controller: AbortController | undefined
|
|
57
|
-
let dirty = true
|
|
58
|
-
let changed = false
|
|
59
|
-
let computing = false
|
|
60
|
-
|
|
61
|
-
// Functions to update internal state
|
|
62
|
-
const ok = (v: T): undefined => {
|
|
63
|
-
if (!isEqual(v, value)) {
|
|
64
|
-
value = v
|
|
65
|
-
changed = true
|
|
66
|
-
}
|
|
67
|
-
error = undefined
|
|
68
|
-
dirty = false
|
|
69
|
-
}
|
|
70
|
-
const nil = (): undefined => {
|
|
71
|
-
changed = UNSET !== value
|
|
72
|
-
value = UNSET
|
|
73
|
-
error = undefined
|
|
74
|
-
}
|
|
75
|
-
const err = (e: unknown): undefined => {
|
|
76
|
-
const newError = createError(e)
|
|
77
|
-
changed =
|
|
78
|
-
!error ||
|
|
79
|
-
newError.name !== error.name ||
|
|
80
|
-
newError.message !== error.message
|
|
81
|
-
value = UNSET
|
|
82
|
-
error = newError
|
|
83
|
-
}
|
|
84
|
-
const settle =
|
|
85
|
-
<T>(fn: (arg: T) => void) =>
|
|
86
|
-
(arg: T) => {
|
|
87
|
-
computing = false
|
|
88
|
-
controller = undefined
|
|
89
|
-
fn(arg)
|
|
90
|
-
if (changed) notifyWatchers(watchers)
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Own watcher: called when notified from sources (push)
|
|
94
|
-
const watcher = createWatcher(
|
|
95
|
-
() => {
|
|
96
|
-
dirty = true
|
|
97
|
-
controller?.abort()
|
|
98
|
-
if (watchers.size) notifyWatchers(watchers)
|
|
99
|
-
else watcher.stop()
|
|
100
|
-
},
|
|
101
|
-
() => {
|
|
102
|
-
if (computing) throw new CircularDependencyError('computed')
|
|
103
|
-
changed = false
|
|
104
|
-
// Return current value until promise resolves
|
|
105
|
-
if (controller) return value
|
|
106
|
-
|
|
107
|
-
controller = new AbortController()
|
|
108
|
-
controller.signal.addEventListener(
|
|
109
|
-
'abort',
|
|
110
|
-
() => {
|
|
111
|
-
computing = false
|
|
112
|
-
controller = undefined
|
|
113
|
-
watcher.run() // Retry computation with updated state
|
|
114
|
-
},
|
|
115
|
-
{
|
|
116
|
-
once: true,
|
|
117
|
-
},
|
|
118
|
-
)
|
|
119
|
-
let result: T | Promise<T>
|
|
120
|
-
computing = true
|
|
121
|
-
try {
|
|
122
|
-
result = callback(value, controller.signal)
|
|
123
|
-
} catch (e) {
|
|
124
|
-
if (isAbortError(e)) nil()
|
|
125
|
-
else err(e)
|
|
126
|
-
computing = false
|
|
127
|
-
return
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if (result instanceof Promise) result.then(settle(ok), settle(err))
|
|
131
|
-
else if (null == result || UNSET === result) nil()
|
|
132
|
-
else ok(result)
|
|
133
|
-
computing = false
|
|
134
|
-
},
|
|
135
|
-
)
|
|
136
|
-
watcher.onCleanup(() => {
|
|
137
|
-
controller?.abort()
|
|
138
|
-
})
|
|
139
|
-
|
|
140
|
-
const task: Record<PropertyKey, unknown> = {}
|
|
141
|
-
Object.defineProperties(task, {
|
|
142
|
-
[Symbol.toStringTag]: {
|
|
143
|
-
value: TYPE_TASK,
|
|
144
|
-
},
|
|
145
|
-
get: {
|
|
146
|
-
value: (): T => {
|
|
147
|
-
subscribeActiveWatcher(watchers)
|
|
148
|
-
flush()
|
|
149
|
-
|
|
150
|
-
if (dirty) watcher.run()
|
|
151
|
-
if (error) throw error
|
|
152
|
-
return value
|
|
153
|
-
},
|
|
154
|
-
},
|
|
155
|
-
})
|
|
156
|
-
return task as Task<T>
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Check if a value is a task signal
|
|
161
|
-
*
|
|
162
|
-
* @since 0.9.0
|
|
163
|
-
* @param {unknown} value - Value to check
|
|
164
|
-
* @returns {boolean} - True if value is a task signal, false otherwise
|
|
165
|
-
*/
|
|
166
|
-
const isTask = /*#__PURE__*/ <T extends {}>(value: unknown): value is Task<T> =>
|
|
167
|
-
isObjectOfType(value, TYPE_TASK)
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Check if the provided value is a callback that may be used as input for toSignal() to derive a computed state
|
|
171
|
-
*
|
|
172
|
-
* @since 0.12.0
|
|
173
|
-
* @param {unknown} value - Value to check
|
|
174
|
-
* @returns {boolean} - True if value is an async callback, false otherwise
|
|
175
|
-
*/
|
|
176
|
-
const isTaskCallback = /*#__PURE__*/ <T extends {}>(
|
|
177
|
-
value: unknown,
|
|
178
|
-
): value is TaskCallback<T> => isAsyncFunction(value) && value.length < 3
|
|
179
|
-
|
|
180
|
-
/* === Exports === */
|
|
181
|
-
|
|
182
|
-
export {
|
|
183
|
-
TYPE_TASK,
|
|
184
|
-
createTask,
|
|
185
|
-
isTask,
|
|
186
|
-
isTaskCallback,
|
|
187
|
-
type Task,
|
|
188
|
-
type TaskCallback,
|
|
189
|
-
}
|