@zeix/cause-effect 0.16.1 → 0.17.0
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 +71 -21
- package/.cursorrules +3 -2
- package/.github/copilot-instructions.md +59 -13
- package/CLAUDE.md +170 -24
- package/LICENSE +1 -1
- package/README.md +156 -52
- package/archive/benchmark.ts +688 -0
- package/archive/collection.ts +312 -0
- package/{src → archive}/computed.ts +19 -19
- package/archive/list.ts +551 -0
- package/archive/memo.ts +138 -0
- package/{src → archive}/state.ts +13 -11
- package/archive/store.ts +368 -0
- package/archive/task.ts +194 -0
- package/eslint.config.js +1 -0
- package/index.dev.js +899 -503
- package/index.js +1 -1
- package/index.ts +41 -22
- package/package.json +1 -1
- package/src/classes/collection.ts +272 -0
- package/src/classes/composite.ts +176 -0
- package/src/classes/computed.ts +333 -0
- package/src/classes/list.ts +304 -0
- package/src/classes/state.ts +98 -0
- package/src/classes/store.ts +210 -0
- package/src/diff.ts +26 -53
- package/src/effect.ts +9 -9
- package/src/errors.ts +50 -25
- package/src/signal.ts +58 -41
- package/src/system.ts +79 -42
- package/src/util.ts +16 -30
- package/test/batch.test.ts +15 -17
- package/test/benchmark.test.ts +4 -4
- package/test/collection.test.ts +796 -0
- package/test/computed.test.ts +138 -130
- package/test/diff.test.ts +2 -2
- package/test/effect.test.ts +36 -35
- package/test/list.test.ts +754 -0
- package/test/match.test.ts +25 -25
- package/test/resolve.test.ts +17 -19
- package/test/signal.test.ts +70 -119
- package/test/state.test.ts +44 -44
- package/test/store.test.ts +253 -929
- package/types/index.d.ts +10 -8
- package/types/src/classes/collection.d.ts +32 -0
- package/types/src/classes/composite.d.ts +15 -0
- package/types/src/classes/computed.d.ts +97 -0
- package/types/src/classes/list.d.ts +41 -0
- package/types/src/classes/state.d.ts +52 -0
- package/types/src/classes/store.d.ts +51 -0
- package/types/src/diff.d.ts +8 -12
- package/types/src/errors.d.ts +12 -11
- package/types/src/signal.d.ts +27 -14
- package/types/src/system.d.ts +41 -20
- package/types/src/util.d.ts +6 -3
- package/src/store.ts +0 -474
- package/types/src/collection.d.ts +0 -26
- package/types/src/computed.d.ts +0 -33
- package/types/src/scheduler.d.ts +0 -55
- package/types/src/state.d.ts +0 -24
- package/types/src/store.d.ts +0 -65
package/src/store.ts
DELETED
|
@@ -1,474 +0,0 @@
|
|
|
1
|
-
import { isComputed } from './computed'
|
|
2
|
-
import {
|
|
3
|
-
type ArrayToRecord,
|
|
4
|
-
diff,
|
|
5
|
-
type PartialRecord,
|
|
6
|
-
type UnknownArray,
|
|
7
|
-
type UnknownRecord,
|
|
8
|
-
} from './diff'
|
|
9
|
-
import {
|
|
10
|
-
InvalidSignalValueError,
|
|
11
|
-
NullishSignalValueError,
|
|
12
|
-
StoreKeyExistsError,
|
|
13
|
-
StoreKeyRangeError,
|
|
14
|
-
StoreKeyReadonlyError,
|
|
15
|
-
} from './errors'
|
|
16
|
-
import { isMutableSignal, type Signal } from './signal'
|
|
17
|
-
import { createState, isState, type State } from './state'
|
|
18
|
-
import {
|
|
19
|
-
batch,
|
|
20
|
-
type Cleanup,
|
|
21
|
-
createWatcher,
|
|
22
|
-
notify,
|
|
23
|
-
observe,
|
|
24
|
-
subscribe,
|
|
25
|
-
type Watcher,
|
|
26
|
-
} from './system'
|
|
27
|
-
import {
|
|
28
|
-
isFunction,
|
|
29
|
-
isObjectOfType,
|
|
30
|
-
isRecord,
|
|
31
|
-
isSymbol,
|
|
32
|
-
recordToArray,
|
|
33
|
-
UNSET,
|
|
34
|
-
valueString,
|
|
35
|
-
} from './util'
|
|
36
|
-
|
|
37
|
-
/* === Types === */
|
|
38
|
-
|
|
39
|
-
type ArrayItem<T> = T extends readonly (infer U extends {})[] ? U : never
|
|
40
|
-
|
|
41
|
-
type StoreChanges<T> = {
|
|
42
|
-
add: PartialRecord<T>
|
|
43
|
-
change: PartialRecord<T>
|
|
44
|
-
remove: PartialRecord<T>
|
|
45
|
-
sort: string[]
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
type StoreListeners<T> = {
|
|
49
|
-
[K in keyof StoreChanges<T>]: Set<(change: StoreChanges<T>[K]) => void>
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
interface BaseStore {
|
|
53
|
-
readonly [Symbol.toStringTag]: 'Store'
|
|
54
|
-
readonly length: number
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
type RecordStore<T extends UnknownRecord> = BaseStore & {
|
|
58
|
-
[K in keyof T]: T[K] extends readonly unknown[] | Record<string, unknown>
|
|
59
|
-
? Store<T[K]>
|
|
60
|
-
: State<T[K]>
|
|
61
|
-
} & {
|
|
62
|
-
[Symbol.iterator](): IterableIterator<
|
|
63
|
-
[
|
|
64
|
-
Extract<keyof T, string>,
|
|
65
|
-
T[Extract<keyof T, string>] extends
|
|
66
|
-
| readonly unknown[]
|
|
67
|
-
| Record<string, unknown>
|
|
68
|
-
? Store<T[Extract<keyof T, string>]>
|
|
69
|
-
: State<T[Extract<keyof T, string>]>,
|
|
70
|
-
]
|
|
71
|
-
>
|
|
72
|
-
add<K extends Extract<keyof T, string>>(key: K, value: T[K]): void
|
|
73
|
-
get(): T
|
|
74
|
-
set(value: T): void
|
|
75
|
-
update(fn: (value: T) => T): void
|
|
76
|
-
sort<U = T[Extract<keyof T, string>]>(
|
|
77
|
-
compareFn?: (a: U, b: U) => number,
|
|
78
|
-
): void
|
|
79
|
-
on<K extends keyof StoreChanges<T>>(
|
|
80
|
-
type: K,
|
|
81
|
-
listener: (change: StoreChanges<T>[K]) => void,
|
|
82
|
-
): Cleanup
|
|
83
|
-
remove<K extends Extract<keyof T, string>>(key: K): void
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
type ArrayStore<T extends UnknownArray> = BaseStore & {
|
|
87
|
-
[Symbol.iterator](): IterableIterator<
|
|
88
|
-
ArrayItem<T> extends readonly unknown[] | Record<string, unknown>
|
|
89
|
-
? Store<ArrayItem<T>>
|
|
90
|
-
: State<ArrayItem<T>>
|
|
91
|
-
>
|
|
92
|
-
readonly [Symbol.isConcatSpreadable]: boolean
|
|
93
|
-
[n: number]: ArrayItem<T> extends
|
|
94
|
-
| readonly unknown[]
|
|
95
|
-
| Record<string, unknown>
|
|
96
|
-
? Store<ArrayItem<T>>
|
|
97
|
-
: State<ArrayItem<T>>
|
|
98
|
-
add(value: ArrayItem<T>): void
|
|
99
|
-
get(): T
|
|
100
|
-
set(value: T): void
|
|
101
|
-
update(fn: (value: T) => T): void
|
|
102
|
-
sort<U = ArrayItem<T>>(compareFn?: (a: U, b: U) => number): void
|
|
103
|
-
on<K extends keyof StoreChanges<T>>(
|
|
104
|
-
type: K,
|
|
105
|
-
listener: (change: StoreChanges<T>[K]) => void,
|
|
106
|
-
): Cleanup
|
|
107
|
-
remove(index: number): void
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
type Store<T extends UnknownRecord | UnknownArray> = T extends UnknownRecord
|
|
111
|
-
? RecordStore<T>
|
|
112
|
-
: T extends UnknownArray
|
|
113
|
-
? ArrayStore<T>
|
|
114
|
-
: never
|
|
115
|
-
|
|
116
|
-
/* === Constants === */
|
|
117
|
-
|
|
118
|
-
const TYPE_STORE = 'Store'
|
|
119
|
-
|
|
120
|
-
/* === Functions === */
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Create a new store with deeply nested reactive properties
|
|
124
|
-
*
|
|
125
|
-
* Supports both objects and arrays as initial values. Arrays are converted
|
|
126
|
-
* to records internally for storage but maintain their array type through
|
|
127
|
-
* the .get() method, which automatically converts objects with consecutive
|
|
128
|
-
* numeric keys back to arrays.
|
|
129
|
-
*
|
|
130
|
-
* @since 0.15.0
|
|
131
|
-
* @param {T} initialValue - initial object or array value of the store
|
|
132
|
-
* @returns {Store<T>} - new store with reactive properties that preserves the original type T
|
|
133
|
-
*/
|
|
134
|
-
const createStore = <T extends UnknownRecord | UnknownArray>(
|
|
135
|
-
initialValue: T,
|
|
136
|
-
): Store<T> => {
|
|
137
|
-
if (initialValue == null) throw new NullishSignalValueError('store')
|
|
138
|
-
|
|
139
|
-
const watchers = new Set<Watcher>()
|
|
140
|
-
const listeners: StoreListeners<T> = {
|
|
141
|
-
add: new Set<(change: PartialRecord<T>) => void>(),
|
|
142
|
-
change: new Set<(change: PartialRecord<T>) => void>(),
|
|
143
|
-
remove: new Set<(change: PartialRecord<T>) => void>(),
|
|
144
|
-
sort: new Set<(change: string[]) => void>(),
|
|
145
|
-
}
|
|
146
|
-
const signals = new Map<string, Signal<T[Extract<keyof T, string>] & {}>>()
|
|
147
|
-
const signalWatchers = new Map<string, Watcher>()
|
|
148
|
-
|
|
149
|
-
// Determine if this is an array-like store at creation time
|
|
150
|
-
const isArrayLike = Array.isArray(initialValue)
|
|
151
|
-
|
|
152
|
-
// Get current record
|
|
153
|
-
const current = () => {
|
|
154
|
-
const record: Record<string, unknown> = {}
|
|
155
|
-
for (const [key, signal] of signals) record[key] = signal.get()
|
|
156
|
-
return record
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// Emit change notifications
|
|
160
|
-
const emit = <K extends keyof StoreChanges<T>>(
|
|
161
|
-
key: K,
|
|
162
|
-
changes: StoreChanges<T>[K],
|
|
163
|
-
) => {
|
|
164
|
-
Object.freeze(changes)
|
|
165
|
-
for (const listener of listeners[key]) listener(changes)
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Get sorted indexes
|
|
169
|
-
const getSortedIndexes = () =>
|
|
170
|
-
Array.from(signals.keys())
|
|
171
|
-
.map(k => Number(k))
|
|
172
|
-
.filter(n => Number.isInteger(n))
|
|
173
|
-
.sort((a, b) => a - b)
|
|
174
|
-
|
|
175
|
-
// Validate input
|
|
176
|
-
const isValidValue = <T>(
|
|
177
|
-
key: string,
|
|
178
|
-
value: T,
|
|
179
|
-
): value is NonNullable<T> => {
|
|
180
|
-
if (value == null)
|
|
181
|
-
throw new NullishSignalValueError(`store for key "${key}"`)
|
|
182
|
-
if (value === UNSET) return true
|
|
183
|
-
if (isSymbol(value) || isFunction(value) || isComputed(value))
|
|
184
|
-
throw new InvalidSignalValueError(
|
|
185
|
-
`store for key "${key}"`,
|
|
186
|
-
valueString(value),
|
|
187
|
-
)
|
|
188
|
-
return true
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// Add nested signal and effect
|
|
192
|
-
const addProperty = (
|
|
193
|
-
key: string,
|
|
194
|
-
value: ArrayItem<T> | T[keyof T],
|
|
195
|
-
single = false,
|
|
196
|
-
): boolean => {
|
|
197
|
-
if (!isValidValue(key, value)) return false
|
|
198
|
-
const signal =
|
|
199
|
-
isState(value) || isStore(value)
|
|
200
|
-
? value
|
|
201
|
-
: isRecord(value) || Array.isArray(value)
|
|
202
|
-
? createStore(value)
|
|
203
|
-
: createState(value)
|
|
204
|
-
// @ts-expect-error non-matching signal types
|
|
205
|
-
signals.set(key, signal)
|
|
206
|
-
const watcher = createWatcher(() =>
|
|
207
|
-
observe(() => {
|
|
208
|
-
emit('change', { [key]: signal.get() } as PartialRecord<T>)
|
|
209
|
-
}, watcher),
|
|
210
|
-
)
|
|
211
|
-
watcher()
|
|
212
|
-
signalWatchers.set(key, watcher)
|
|
213
|
-
|
|
214
|
-
if (single) {
|
|
215
|
-
notify(watchers)
|
|
216
|
-
emit('add', { [key]: value } as PartialRecord<T>)
|
|
217
|
-
}
|
|
218
|
-
return true
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
// Remove nested signal and effect
|
|
222
|
-
const removeProperty = (key: string, single = false) => {
|
|
223
|
-
const ok = signals.delete(key)
|
|
224
|
-
if (ok) {
|
|
225
|
-
const watcher = signalWatchers.get(key)
|
|
226
|
-
if (watcher) watcher.cleanup()
|
|
227
|
-
signalWatchers.delete(key)
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
if (single) {
|
|
231
|
-
notify(watchers)
|
|
232
|
-
emit('remove', { [key]: UNSET } as PartialRecord<T>)
|
|
233
|
-
}
|
|
234
|
-
return ok
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// Reconcile data and dispatch events
|
|
238
|
-
const reconcile = (
|
|
239
|
-
oldValue: T,
|
|
240
|
-
newValue: T,
|
|
241
|
-
initialRun?: boolean,
|
|
242
|
-
): boolean => {
|
|
243
|
-
const changes = diff(
|
|
244
|
-
oldValue as T extends UnknownArray ? ArrayToRecord<T> : T,
|
|
245
|
-
newValue as T extends UnknownArray ? ArrayToRecord<T> : T,
|
|
246
|
-
)
|
|
247
|
-
|
|
248
|
-
batch(() => {
|
|
249
|
-
// Additions
|
|
250
|
-
if (Object.keys(changes.add).length) {
|
|
251
|
-
for (const key in changes.add)
|
|
252
|
-
addProperty(key, changes.add[key] ?? UNSET)
|
|
253
|
-
|
|
254
|
-
// Queue initial additions event to allow listeners to be added first
|
|
255
|
-
if (initialRun) {
|
|
256
|
-
setTimeout(() => {
|
|
257
|
-
emit('add', changes.add)
|
|
258
|
-
}, 0)
|
|
259
|
-
} else {
|
|
260
|
-
emit('add', changes.add)
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// Changes
|
|
265
|
-
if (Object.keys(changes.change).length) {
|
|
266
|
-
for (const key in changes.change) {
|
|
267
|
-
const value = changes.change[key]
|
|
268
|
-
if (!isValidValue(key, value)) continue
|
|
269
|
-
const signal = signals.get(key as Extract<keyof T, string>)
|
|
270
|
-
if (isMutableSignal(signal)) signal.set(value)
|
|
271
|
-
else
|
|
272
|
-
throw new StoreKeyReadonlyError(key, valueString(value))
|
|
273
|
-
}
|
|
274
|
-
emit('change', changes.change)
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
// Removals
|
|
278
|
-
if (Object.keys(changes.remove).length) {
|
|
279
|
-
for (const key in changes.remove) removeProperty(key)
|
|
280
|
-
emit('remove', changes.remove)
|
|
281
|
-
}
|
|
282
|
-
})
|
|
283
|
-
|
|
284
|
-
return changes.changed
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
// Initialize data
|
|
288
|
-
reconcile({} as T, initialValue, true)
|
|
289
|
-
|
|
290
|
-
// Methods and Properties
|
|
291
|
-
const store: Record<PropertyKey, unknown> = {}
|
|
292
|
-
Object.defineProperties(store, {
|
|
293
|
-
[Symbol.toStringTag]: {
|
|
294
|
-
value: TYPE_STORE,
|
|
295
|
-
},
|
|
296
|
-
[Symbol.isConcatSpreadable]: {
|
|
297
|
-
value: isArrayLike,
|
|
298
|
-
},
|
|
299
|
-
[Symbol.iterator]: {
|
|
300
|
-
value: isArrayLike
|
|
301
|
-
? function* () {
|
|
302
|
-
const indexes = getSortedIndexes()
|
|
303
|
-
for (const index of indexes) {
|
|
304
|
-
const signal = signals.get(String(index))
|
|
305
|
-
if (signal) yield signal
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
: function* () {
|
|
309
|
-
for (const [key, signal] of signals) yield [key, signal]
|
|
310
|
-
},
|
|
311
|
-
},
|
|
312
|
-
add: {
|
|
313
|
-
value: isArrayLike
|
|
314
|
-
? (v: ArrayItem<T>): void => {
|
|
315
|
-
addProperty(String(signals.size), v, true)
|
|
316
|
-
}
|
|
317
|
-
: <K extends Extract<keyof T, string>>(k: K, v: T[K]): void => {
|
|
318
|
-
if (!signals.has(k)) addProperty(k, v, true)
|
|
319
|
-
else throw new StoreKeyExistsError(k, valueString(v))
|
|
320
|
-
},
|
|
321
|
-
},
|
|
322
|
-
get: {
|
|
323
|
-
value: (): T => {
|
|
324
|
-
subscribe(watchers)
|
|
325
|
-
return recordToArray(current()) as T
|
|
326
|
-
},
|
|
327
|
-
},
|
|
328
|
-
remove: {
|
|
329
|
-
value: isArrayLike
|
|
330
|
-
? (index: number): void => {
|
|
331
|
-
const currentArray = recordToArray(current()) as T
|
|
332
|
-
const currentLength = signals.size
|
|
333
|
-
if (
|
|
334
|
-
!Array.isArray(currentArray) ||
|
|
335
|
-
index <= -currentLength ||
|
|
336
|
-
index >= currentLength
|
|
337
|
-
)
|
|
338
|
-
throw new StoreKeyRangeError(index)
|
|
339
|
-
const newArray = [...currentArray]
|
|
340
|
-
newArray.splice(index, 1)
|
|
341
|
-
|
|
342
|
-
if (reconcile(currentArray, newArray as unknown as T))
|
|
343
|
-
notify(watchers)
|
|
344
|
-
}
|
|
345
|
-
: (k: string): void => {
|
|
346
|
-
if (signals.has(k)) removeProperty(k, true)
|
|
347
|
-
},
|
|
348
|
-
},
|
|
349
|
-
set: {
|
|
350
|
-
value: (v: T): void => {
|
|
351
|
-
if (reconcile(current() as T, v)) {
|
|
352
|
-
notify(watchers)
|
|
353
|
-
if (UNSET === v) watchers.clear()
|
|
354
|
-
}
|
|
355
|
-
},
|
|
356
|
-
},
|
|
357
|
-
update: {
|
|
358
|
-
value: (fn: (v: T) => T): void => {
|
|
359
|
-
const oldValue = current()
|
|
360
|
-
const newValue = fn(recordToArray(oldValue) as T)
|
|
361
|
-
if (reconcile(oldValue as T, newValue)) {
|
|
362
|
-
notify(watchers)
|
|
363
|
-
if (UNSET === newValue) watchers.clear()
|
|
364
|
-
}
|
|
365
|
-
},
|
|
366
|
-
},
|
|
367
|
-
sort: {
|
|
368
|
-
value: (
|
|
369
|
-
compareFn?: <
|
|
370
|
-
U = T extends UnknownArray
|
|
371
|
-
? ArrayItem<T>
|
|
372
|
-
: T[Extract<keyof T, string>],
|
|
373
|
-
>(
|
|
374
|
-
a: U,
|
|
375
|
-
b: U,
|
|
376
|
-
) => number,
|
|
377
|
-
): void => {
|
|
378
|
-
// Get all entries as [key, value] pairs
|
|
379
|
-
const entries = Array.from(signals.entries())
|
|
380
|
-
.map(([key, signal]) => [key, signal.get()])
|
|
381
|
-
.sort(
|
|
382
|
-
compareFn
|
|
383
|
-
? (a, b) => compareFn(a[1], b[1])
|
|
384
|
-
: (a, b) =>
|
|
385
|
-
String(a[1]).localeCompare(String(b[1])),
|
|
386
|
-
)
|
|
387
|
-
|
|
388
|
-
// Create array of original keys in their new sorted order
|
|
389
|
-
const newOrder: string[] = entries.map(([key]) => String(key))
|
|
390
|
-
const newSignals = new Map<
|
|
391
|
-
string,
|
|
392
|
-
Signal<T[Extract<keyof T, string>] & {}>
|
|
393
|
-
>()
|
|
394
|
-
|
|
395
|
-
entries.forEach(([key], newIndex) => {
|
|
396
|
-
const oldKey = String(key)
|
|
397
|
-
const newKey = isArrayLike ? String(newIndex) : String(key)
|
|
398
|
-
const signal = signals.get(oldKey)
|
|
399
|
-
if (signal) newSignals.set(newKey, signal)
|
|
400
|
-
})
|
|
401
|
-
|
|
402
|
-
// Replace signals map
|
|
403
|
-
signals.clear()
|
|
404
|
-
newSignals.forEach((signal, key) => signals.set(key, signal))
|
|
405
|
-
notify(watchers)
|
|
406
|
-
emit('sort', newOrder)
|
|
407
|
-
},
|
|
408
|
-
},
|
|
409
|
-
on: {
|
|
410
|
-
value: <K extends keyof StoreChanges<T>>(
|
|
411
|
-
type: K,
|
|
412
|
-
listener: (change: StoreChanges<T>[K]) => void,
|
|
413
|
-
): Cleanup => {
|
|
414
|
-
listeners[type].add(listener)
|
|
415
|
-
return () => listeners[type].delete(listener)
|
|
416
|
-
},
|
|
417
|
-
},
|
|
418
|
-
length: {
|
|
419
|
-
get(): number {
|
|
420
|
-
subscribe(watchers)
|
|
421
|
-
return signals.size
|
|
422
|
-
},
|
|
423
|
-
},
|
|
424
|
-
})
|
|
425
|
-
|
|
426
|
-
// Return proxy directly with integrated signal methods
|
|
427
|
-
return new Proxy(store as Store<T>, {
|
|
428
|
-
get(target, prop) {
|
|
429
|
-
if (prop in target) return Reflect.get(target, prop)
|
|
430
|
-
if (isSymbol(prop)) return undefined
|
|
431
|
-
return signals.get(prop)
|
|
432
|
-
},
|
|
433
|
-
has(target, prop) {
|
|
434
|
-
if (prop in target) return true
|
|
435
|
-
return signals.has(String(prop))
|
|
436
|
-
},
|
|
437
|
-
ownKeys(target) {
|
|
438
|
-
const staticKeys = Reflect.ownKeys(target)
|
|
439
|
-
const signalKeys = isArrayLike
|
|
440
|
-
? getSortedIndexes().map(key => String(key))
|
|
441
|
-
: Array.from(signals.keys())
|
|
442
|
-
return [...new Set([...signalKeys, ...staticKeys])]
|
|
443
|
-
},
|
|
444
|
-
getOwnPropertyDescriptor(target, prop) {
|
|
445
|
-
if (prop in target)
|
|
446
|
-
return Reflect.getOwnPropertyDescriptor(target, prop)
|
|
447
|
-
|
|
448
|
-
const signal = signals.get(String(prop))
|
|
449
|
-
return signal
|
|
450
|
-
? {
|
|
451
|
-
enumerable: true,
|
|
452
|
-
configurable: true,
|
|
453
|
-
writable: true,
|
|
454
|
-
value: signal,
|
|
455
|
-
}
|
|
456
|
-
: undefined
|
|
457
|
-
},
|
|
458
|
-
})
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
/**
|
|
462
|
-
* Check if the provided value is a Store instance
|
|
463
|
-
*
|
|
464
|
-
* @since 0.15.0
|
|
465
|
-
* @param {unknown} value - value to check
|
|
466
|
-
* @returns {boolean} - true if the value is a Store instance, false otherwise
|
|
467
|
-
*/
|
|
468
|
-
const isStore = <T extends UnknownRecord | UnknownArray>(
|
|
469
|
-
value: unknown,
|
|
470
|
-
): value is Store<T> => isObjectOfType(value, TYPE_STORE)
|
|
471
|
-
|
|
472
|
-
/* === Exports === */
|
|
473
|
-
|
|
474
|
-
export { TYPE_STORE, isStore, createStore, type Store, type StoreChanges }
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { UnknownArray } from './diff';
|
|
2
|
-
import { type Store, type StoreChanges } from './store';
|
|
3
|
-
import { type Cleanup } from './system';
|
|
4
|
-
type Collection<T extends UnknownArray> = {
|
|
5
|
-
readonly [Symbol.toStringTag]: 'Collection';
|
|
6
|
-
get(): T;
|
|
7
|
-
on<K extends keyof StoreChanges<T>>(type: K, listener: (change: StoreChanges<T>[K]) => void): Cleanup;
|
|
8
|
-
};
|
|
9
|
-
type CollectionCallback<T extends UnknownArray> = (store: Store<T>) => T;
|
|
10
|
-
declare const TYPE_COLLECTION = "Collection";
|
|
11
|
-
/**
|
|
12
|
-
* Create a collection signal
|
|
13
|
-
*
|
|
14
|
-
* @param {CollectionCallback<T>} fn - callback function to create the collection
|
|
15
|
-
* @returns {Collection<T>} - collection signal
|
|
16
|
-
*/
|
|
17
|
-
declare const createCollection: <T extends UnknownArray>(fn: CollectionCallback<T>) => Collection<T>;
|
|
18
|
-
/**
|
|
19
|
-
* Check if a value is a collection signal
|
|
20
|
-
*
|
|
21
|
-
* @since 0.16.0
|
|
22
|
-
* @param {unknown} value - value to check
|
|
23
|
-
* @returns {boolean} - true if value is a computed state, false otherwise
|
|
24
|
-
*/
|
|
25
|
-
declare const isCollection: <T extends UnknownArray>(value: unknown) => value is Collection<T>;
|
|
26
|
-
export { TYPE_COLLECTION, createCollection, isCollection, type Collection };
|
package/types/src/computed.d.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
type Computed<T extends {}> = {
|
|
2
|
-
readonly [Symbol.toStringTag]: 'Computed';
|
|
3
|
-
get(): T;
|
|
4
|
-
};
|
|
5
|
-
type ComputedCallback<T extends {} & {
|
|
6
|
-
then?: undefined;
|
|
7
|
-
}> = ((oldValue: T, abort: AbortSignal) => Promise<T>) | ((oldValue: T) => T);
|
|
8
|
-
declare const TYPE_COMPUTED = "Computed";
|
|
9
|
-
/**
|
|
10
|
-
* Create a derived signal from existing signals
|
|
11
|
-
*
|
|
12
|
-
* @since 0.9.0
|
|
13
|
-
* @param {ComputedCallback<T>} callback - Computation callback function
|
|
14
|
-
* @returns {Computed<T>} - Computed signal
|
|
15
|
-
*/
|
|
16
|
-
declare const createComputed: <T extends {}>(callback: ComputedCallback<T>, initialValue?: T) => Computed<T>;
|
|
17
|
-
/**
|
|
18
|
-
* Check if a value is a computed signal
|
|
19
|
-
*
|
|
20
|
-
* @since 0.9.0
|
|
21
|
-
* @param {unknown} value - Value to check
|
|
22
|
-
* @returns {boolean} - true if value is a computed signal, false otherwise
|
|
23
|
-
*/
|
|
24
|
-
declare const isComputed: <T extends {}>(value: unknown) => value is Computed<T>;
|
|
25
|
-
/**
|
|
26
|
-
* Check if the provided value is a callback that may be used as input for toSignal() to derive a computed state
|
|
27
|
-
*
|
|
28
|
-
* @since 0.12.0
|
|
29
|
-
* @param {unknown} value - Value to check
|
|
30
|
-
* @returns {boolean} - true if value is a callback or callbacks object, false otherwise
|
|
31
|
-
*/
|
|
32
|
-
declare const isComputedCallback: <T extends {}>(value: unknown) => value is ComputedCallback<T>;
|
|
33
|
-
export { TYPE_COMPUTED, createComputed, isComputed, isComputedCallback, type Computed, type ComputedCallback, };
|
package/types/src/scheduler.d.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
type Cleanup = () => void;
|
|
2
|
-
type Watcher = {
|
|
3
|
-
(): void;
|
|
4
|
-
off(cleanup: Cleanup): void;
|
|
5
|
-
cleanup(): void;
|
|
6
|
-
};
|
|
7
|
-
type Updater = <T>() => T | boolean | undefined;
|
|
8
|
-
/**
|
|
9
|
-
* Create a watcher that can be used to observe changes to a signal
|
|
10
|
-
*
|
|
11
|
-
* @since 0.14.1
|
|
12
|
-
* @param {() => void} notice - function to be called when the state changes
|
|
13
|
-
* @returns {Watcher} - watcher object with off and cleanup methods
|
|
14
|
-
*/
|
|
15
|
-
declare const watch: (notice: () => void) => Watcher;
|
|
16
|
-
/**
|
|
17
|
-
* Add active watcher to the Set of watchers
|
|
18
|
-
*
|
|
19
|
-
* @param {Set<Watcher>} watchers - watchers of the signal
|
|
20
|
-
*/
|
|
21
|
-
declare const subscribe: (watchers: Set<Watcher>) => void;
|
|
22
|
-
/**
|
|
23
|
-
* Add watchers to the pending set of change notifications
|
|
24
|
-
*
|
|
25
|
-
* @param {Set<Watcher>} watchers - watchers of the signal
|
|
26
|
-
*/
|
|
27
|
-
declare const notify: (watchers: Set<Watcher>) => void;
|
|
28
|
-
/**
|
|
29
|
-
* Flush all pending changes to notify watchers
|
|
30
|
-
*/
|
|
31
|
-
declare const flush: () => void;
|
|
32
|
-
/**
|
|
33
|
-
* Batch multiple changes in a single signal graph and DOM update cycle
|
|
34
|
-
*
|
|
35
|
-
* @param {() => void} fn - function with multiple signal writes to be batched
|
|
36
|
-
*/
|
|
37
|
-
declare const batch: (fn: () => void) => void;
|
|
38
|
-
/**
|
|
39
|
-
* Run a function in a reactive context
|
|
40
|
-
*
|
|
41
|
-
* @param {() => void} run - function to run the computation or effect
|
|
42
|
-
* @param {Watcher} watcher - function to be called when the state changes or undefined for temporary unwatching while inserting auto-hydrating DOM nodes that might read signals (e.g., web components)
|
|
43
|
-
*/
|
|
44
|
-
declare const observe: (run: () => void, watcher?: Watcher) => void;
|
|
45
|
-
/**
|
|
46
|
-
* Enqueue a function to be executed on the next animation frame
|
|
47
|
-
*
|
|
48
|
-
* If the same Symbol is provided for multiple calls before the next animation frame,
|
|
49
|
-
* only the latest call will be executed (deduplication).
|
|
50
|
-
*
|
|
51
|
-
* @param {Updater} fn - function to be executed on the next animation frame; can return updated value <T>, success <boolean> or void
|
|
52
|
-
* @param {symbol} dedupe - Symbol for deduplication; if not provided, a unique Symbol is created ensuring the update is always executed
|
|
53
|
-
*/
|
|
54
|
-
declare const enqueue: <T>(fn: Updater, dedupe?: symbol) => Promise<boolean | T | undefined>;
|
|
55
|
-
export { type Cleanup, type Watcher, type Updater, subscribe, notify, flush, batch, watch, observe, enqueue, };
|
package/types/src/state.d.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
type State<T extends {}> = {
|
|
2
|
-
readonly [Symbol.toStringTag]: 'State';
|
|
3
|
-
get(): T;
|
|
4
|
-
set(newValue: T): void;
|
|
5
|
-
update(updater: (oldValue: T) => T): void;
|
|
6
|
-
};
|
|
7
|
-
declare const TYPE_STATE = "State";
|
|
8
|
-
/**
|
|
9
|
-
* Create a new state signal
|
|
10
|
-
*
|
|
11
|
-
* @since 0.9.0
|
|
12
|
-
* @param {T} initialValue - initial value of the state
|
|
13
|
-
* @returns {State<T>} - new state signal
|
|
14
|
-
*/
|
|
15
|
-
declare const createState: <T extends {}>(initialValue: T) => State<T>;
|
|
16
|
-
/**
|
|
17
|
-
* Check if the provided value is a State instance
|
|
18
|
-
*
|
|
19
|
-
* @since 0.9.0
|
|
20
|
-
* @param {unknown} value - value to check
|
|
21
|
-
* @returns {boolean} - true if the value is a State instance, false otherwise
|
|
22
|
-
*/
|
|
23
|
-
declare const isState: <T extends {}>(value: unknown) => value is State<T>;
|
|
24
|
-
export { TYPE_STATE, isState, createState, type State };
|
package/types/src/store.d.ts
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { type PartialRecord, type UnknownArray, type UnknownRecord } from './diff';
|
|
2
|
-
import { type State } from './state';
|
|
3
|
-
import { type Cleanup } from './system';
|
|
4
|
-
type ArrayItem<T> = T extends readonly (infer U extends {})[] ? U : never;
|
|
5
|
-
type StoreChanges<T> = {
|
|
6
|
-
add: PartialRecord<T>;
|
|
7
|
-
change: PartialRecord<T>;
|
|
8
|
-
remove: PartialRecord<T>;
|
|
9
|
-
sort: string[];
|
|
10
|
-
};
|
|
11
|
-
interface BaseStore {
|
|
12
|
-
readonly [Symbol.toStringTag]: 'Store';
|
|
13
|
-
readonly length: number;
|
|
14
|
-
}
|
|
15
|
-
type RecordStore<T extends UnknownRecord> = BaseStore & {
|
|
16
|
-
[K in keyof T]: T[K] extends readonly unknown[] | Record<string, unknown> ? Store<T[K]> : State<T[K]>;
|
|
17
|
-
} & {
|
|
18
|
-
[Symbol.iterator](): IterableIterator<[
|
|
19
|
-
Extract<keyof T, string>,
|
|
20
|
-
T[Extract<keyof T, string>] extends readonly unknown[] | Record<string, unknown> ? Store<T[Extract<keyof T, string>]> : State<T[Extract<keyof T, string>]>
|
|
21
|
-
]>;
|
|
22
|
-
add<K extends Extract<keyof T, string>>(key: K, value: T[K]): void;
|
|
23
|
-
get(): T;
|
|
24
|
-
set(value: T): void;
|
|
25
|
-
update(fn: (value: T) => T): void;
|
|
26
|
-
sort<U = T[Extract<keyof T, string>]>(compareFn?: (a: U, b: U) => number): void;
|
|
27
|
-
on<K extends keyof StoreChanges<T>>(type: K, listener: (change: StoreChanges<T>[K]) => void): Cleanup;
|
|
28
|
-
remove<K extends Extract<keyof T, string>>(key: K): void;
|
|
29
|
-
};
|
|
30
|
-
type ArrayStore<T extends UnknownArray> = BaseStore & {
|
|
31
|
-
[Symbol.iterator](): IterableIterator<ArrayItem<T> extends readonly unknown[] | Record<string, unknown> ? Store<ArrayItem<T>> : State<ArrayItem<T>>>;
|
|
32
|
-
readonly [Symbol.isConcatSpreadable]: boolean;
|
|
33
|
-
[n: number]: ArrayItem<T> extends readonly unknown[] | Record<string, unknown> ? Store<ArrayItem<T>> : State<ArrayItem<T>>;
|
|
34
|
-
add(value: ArrayItem<T>): void;
|
|
35
|
-
get(): T;
|
|
36
|
-
set(value: T): void;
|
|
37
|
-
update(fn: (value: T) => T): void;
|
|
38
|
-
sort<U = ArrayItem<T>>(compareFn?: (a: U, b: U) => number): void;
|
|
39
|
-
on<K extends keyof StoreChanges<T>>(type: K, listener: (change: StoreChanges<T>[K]) => void): Cleanup;
|
|
40
|
-
remove(index: number): void;
|
|
41
|
-
};
|
|
42
|
-
type Store<T extends UnknownRecord | UnknownArray> = T extends UnknownRecord ? RecordStore<T> : T extends UnknownArray ? ArrayStore<T> : never;
|
|
43
|
-
declare const TYPE_STORE = "Store";
|
|
44
|
-
/**
|
|
45
|
-
* Create a new store with deeply nested reactive properties
|
|
46
|
-
*
|
|
47
|
-
* Supports both objects and arrays as initial values. Arrays are converted
|
|
48
|
-
* to records internally for storage but maintain their array type through
|
|
49
|
-
* the .get() method, which automatically converts objects with consecutive
|
|
50
|
-
* numeric keys back to arrays.
|
|
51
|
-
*
|
|
52
|
-
* @since 0.15.0
|
|
53
|
-
* @param {T} initialValue - initial object or array value of the store
|
|
54
|
-
* @returns {Store<T>} - new store with reactive properties that preserves the original type T
|
|
55
|
-
*/
|
|
56
|
-
declare const createStore: <T extends UnknownRecord | UnknownArray>(initialValue: T) => Store<T>;
|
|
57
|
-
/**
|
|
58
|
-
* Check if the provided value is a Store instance
|
|
59
|
-
*
|
|
60
|
-
* @since 0.15.0
|
|
61
|
-
* @param {unknown} value - value to check
|
|
62
|
-
* @returns {boolean} - true if the value is a Store instance, false otherwise
|
|
63
|
-
*/
|
|
64
|
-
declare const isStore: <T extends UnknownRecord | UnknownArray>(value: unknown) => value is Store<T>;
|
|
65
|
-
export { TYPE_STORE, isStore, createStore, type Store, type StoreChanges };
|