@zeix/cause-effect 0.16.0 → 0.16.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/README.md +1 -1
- package/index.dev.js +167 -162
- package/index.js +1 -1
- package/index.ts +3 -2
- package/package.json +1 -1
- package/src/computed.ts +15 -16
- package/src/diff.ts +24 -21
- package/src/state.ts +34 -45
- package/src/store.ts +170 -221
- package/src/util.ts +2 -6
- package/test/batch.test.ts +1 -1
- package/test/benchmark.test.ts +1 -1
- package/test/computed.test.ts +1 -1
- package/test/effect.test.ts +1 -1
- package/test/match.test.ts +1 -1
- package/test/resolve.test.ts +1 -1
- package/test/signal.test.ts +2 -2
- package/test/state.test.ts +1 -1
- package/test/store.test.ts +859 -1502
- package/types/index.d.ts +3 -3
- package/types/src/diff.d.ts +7 -7
- package/types/src/store.d.ts +6 -7
package/src/store.ts
CHANGED
|
@@ -2,11 +2,10 @@ import { isComputed } from './computed'
|
|
|
2
2
|
import {
|
|
3
3
|
type ArrayToRecord,
|
|
4
4
|
diff,
|
|
5
|
+
type PartialRecord,
|
|
5
6
|
type UnknownArray,
|
|
6
7
|
type UnknownRecord,
|
|
7
|
-
type UnknownRecordOrArray,
|
|
8
8
|
} from './diff'
|
|
9
|
-
|
|
10
9
|
import {
|
|
11
10
|
InvalidSignalValueError,
|
|
12
11
|
NullishSignalValueError,
|
|
@@ -40,9 +39,9 @@ import {
|
|
|
40
39
|
type ArrayItem<T> = T extends readonly (infer U extends {})[] ? U : never
|
|
41
40
|
|
|
42
41
|
type StoreChanges<T> = {
|
|
43
|
-
add:
|
|
44
|
-
change:
|
|
45
|
-
remove:
|
|
42
|
+
add: PartialRecord<T>
|
|
43
|
+
change: PartialRecord<T>
|
|
44
|
+
remove: PartialRecord<T>
|
|
46
45
|
sort: string[]
|
|
47
46
|
}
|
|
48
47
|
|
|
@@ -52,7 +51,7 @@ type StoreListeners<T> = {
|
|
|
52
51
|
|
|
53
52
|
interface BaseStore {
|
|
54
53
|
readonly [Symbol.toStringTag]: 'Store'
|
|
55
|
-
readonly
|
|
54
|
+
readonly length: number
|
|
56
55
|
}
|
|
57
56
|
|
|
58
57
|
type RecordStore<T extends UnknownRecord> = BaseStore & {
|
|
@@ -106,7 +105,6 @@ type ArrayStore<T extends UnknownArray> = BaseStore & {
|
|
|
106
105
|
listener: (change: StoreChanges<T>[K]) => void,
|
|
107
106
|
): Cleanup
|
|
108
107
|
remove(index: number): void
|
|
109
|
-
readonly length: number
|
|
110
108
|
}
|
|
111
109
|
|
|
112
110
|
type Store<T extends UnknownRecord | UnknownArray> = T extends UnknownRecord
|
|
@@ -140,9 +138,9 @@ const createStore = <T extends UnknownRecord | UnknownArray>(
|
|
|
140
138
|
|
|
141
139
|
const watchers = new Set<Watcher>()
|
|
142
140
|
const listeners: StoreListeners<T> = {
|
|
143
|
-
add: new Set<(change:
|
|
144
|
-
change: new Set<(change:
|
|
145
|
-
remove: new Set<(change:
|
|
141
|
+
add: new Set<(change: PartialRecord<T>) => void>(),
|
|
142
|
+
change: new Set<(change: PartialRecord<T>) => void>(),
|
|
143
|
+
remove: new Set<(change: PartialRecord<T>) => void>(),
|
|
146
144
|
sort: new Set<(change: string[]) => void>(),
|
|
147
145
|
}
|
|
148
146
|
const signals = new Map<string, Signal<T[Extract<keyof T, string>] & {}>>()
|
|
@@ -151,15 +149,10 @@ const createStore = <T extends UnknownRecord | UnknownArray>(
|
|
|
151
149
|
// Determine if this is an array-like store at creation time
|
|
152
150
|
const isArrayLike = Array.isArray(initialValue)
|
|
153
151
|
|
|
154
|
-
// Internal state
|
|
155
|
-
const size = createState(0)
|
|
156
|
-
|
|
157
152
|
// Get current record
|
|
158
153
|
const current = () => {
|
|
159
154
|
const record: Record<string, unknown> = {}
|
|
160
|
-
for (const [key, signal] of signals)
|
|
161
|
-
record[key] = signal.get()
|
|
162
|
-
}
|
|
155
|
+
for (const [key, signal] of signals) record[key] = signal.get()
|
|
163
156
|
return record
|
|
164
157
|
}
|
|
165
158
|
|
|
@@ -169,9 +162,7 @@ const createStore = <T extends UnknownRecord | UnknownArray>(
|
|
|
169
162
|
changes: StoreChanges<T>[K],
|
|
170
163
|
) => {
|
|
171
164
|
Object.freeze(changes)
|
|
172
|
-
for (const listener of listeners[key])
|
|
173
|
-
listener(changes)
|
|
174
|
-
}
|
|
165
|
+
for (const listener of listeners[key]) listener(changes)
|
|
175
166
|
}
|
|
176
167
|
|
|
177
168
|
// Get sorted indexes
|
|
@@ -198,9 +189,9 @@ const createStore = <T extends UnknownRecord | UnknownArray>(
|
|
|
198
189
|
}
|
|
199
190
|
|
|
200
191
|
// Add nested signal and effect
|
|
201
|
-
const addProperty =
|
|
202
|
-
key:
|
|
203
|
-
value: T
|
|
192
|
+
const addProperty = (
|
|
193
|
+
key: string,
|
|
194
|
+
value: ArrayItem<T> | T[keyof T],
|
|
204
195
|
single = false,
|
|
205
196
|
): boolean => {
|
|
206
197
|
if (!isValidValue(key, value)) return false
|
|
@@ -214,29 +205,21 @@ const createStore = <T extends UnknownRecord | UnknownArray>(
|
|
|
214
205
|
signals.set(key, signal)
|
|
215
206
|
const watcher = createWatcher(() =>
|
|
216
207
|
observe(() => {
|
|
217
|
-
emit('change', {
|
|
218
|
-
[key]: signal.get(),
|
|
219
|
-
} as unknown as Partial<T>)
|
|
208
|
+
emit('change', { [key]: signal.get() } as PartialRecord<T>)
|
|
220
209
|
}, watcher),
|
|
221
210
|
)
|
|
222
211
|
watcher()
|
|
223
212
|
signalWatchers.set(key, watcher)
|
|
224
213
|
|
|
225
214
|
if (single) {
|
|
226
|
-
size.set(signals.size)
|
|
227
215
|
notify(watchers)
|
|
228
|
-
emit('add', {
|
|
229
|
-
[key]: value,
|
|
230
|
-
} as unknown as Partial<T>)
|
|
216
|
+
emit('add', { [key]: value } as PartialRecord<T>)
|
|
231
217
|
}
|
|
232
218
|
return true
|
|
233
219
|
}
|
|
234
220
|
|
|
235
221
|
// Remove nested signal and effect
|
|
236
|
-
const removeProperty =
|
|
237
|
-
key: K,
|
|
238
|
-
single = false,
|
|
239
|
-
) => {
|
|
222
|
+
const removeProperty = (key: string, single = false) => {
|
|
240
223
|
const ok = signals.delete(key)
|
|
241
224
|
if (ok) {
|
|
242
225
|
const watcher = signalWatchers.get(key)
|
|
@@ -245,11 +228,8 @@ const createStore = <T extends UnknownRecord | UnknownArray>(
|
|
|
245
228
|
}
|
|
246
229
|
|
|
247
230
|
if (single) {
|
|
248
|
-
size.set(signals.size)
|
|
249
231
|
notify(watchers)
|
|
250
|
-
emit('remove', {
|
|
251
|
-
[key]: UNSET,
|
|
252
|
-
} as unknown as Partial<T>)
|
|
232
|
+
emit('remove', { [key]: UNSET } as PartialRecord<T>)
|
|
253
233
|
}
|
|
254
234
|
return ok
|
|
255
235
|
}
|
|
@@ -268,21 +248,16 @@ const createStore = <T extends UnknownRecord | UnknownArray>(
|
|
|
268
248
|
batch(() => {
|
|
269
249
|
// Additions
|
|
270
250
|
if (Object.keys(changes.add).length) {
|
|
271
|
-
for (const key in changes.add)
|
|
272
|
-
|
|
273
|
-
addProperty(
|
|
274
|
-
key as Extract<keyof T, string>,
|
|
275
|
-
value as T[Extract<keyof T, string>] & {},
|
|
276
|
-
)
|
|
277
|
-
}
|
|
251
|
+
for (const key in changes.add)
|
|
252
|
+
addProperty(key, changes.add[key] ?? UNSET)
|
|
278
253
|
|
|
279
254
|
// Queue initial additions event to allow listeners to be added first
|
|
280
255
|
if (initialRun) {
|
|
281
256
|
setTimeout(() => {
|
|
282
|
-
emit('add', changes.add
|
|
257
|
+
emit('add', changes.add)
|
|
283
258
|
}, 0)
|
|
284
259
|
} else {
|
|
285
|
-
emit('add', changes.add
|
|
260
|
+
emit('add', changes.add)
|
|
286
261
|
}
|
|
287
262
|
}
|
|
288
263
|
|
|
@@ -292,211 +267,185 @@ const createStore = <T extends UnknownRecord | UnknownArray>(
|
|
|
292
267
|
const value = changes.change[key]
|
|
293
268
|
if (!isValidValue(key, value)) continue
|
|
294
269
|
const signal = signals.get(key as Extract<keyof T, string>)
|
|
295
|
-
if (isMutableSignal(signal))
|
|
296
|
-
signal.set(value as T[Extract<keyof T, string>] & {})
|
|
270
|
+
if (isMutableSignal(signal)) signal.set(value)
|
|
297
271
|
else
|
|
298
272
|
throw new StoreKeyReadonlyError(key, valueString(value))
|
|
299
273
|
}
|
|
300
|
-
emit('change', changes.change
|
|
274
|
+
emit('change', changes.change)
|
|
301
275
|
}
|
|
302
276
|
|
|
303
277
|
// Removals
|
|
304
278
|
if (Object.keys(changes.remove).length) {
|
|
305
|
-
for (const key in changes.remove)
|
|
306
|
-
|
|
307
|
-
emit('remove', changes.remove as Partial<T>)
|
|
279
|
+
for (const key in changes.remove) removeProperty(key)
|
|
280
|
+
emit('remove', changes.remove)
|
|
308
281
|
}
|
|
309
|
-
|
|
310
|
-
size.set(signals.size)
|
|
311
282
|
})
|
|
312
283
|
|
|
313
284
|
return changes.changed
|
|
314
285
|
}
|
|
315
286
|
|
|
316
|
-
// Initialize data
|
|
287
|
+
// Initialize data
|
|
317
288
|
reconcile({} as T, initialValue, true)
|
|
318
289
|
|
|
319
290
|
// Methods and Properties
|
|
320
|
-
const store: Record<
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
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()
|
|
326
354
|
}
|
|
327
|
-
|
|
328
|
-
if (!signals.has(k)) addProperty(k, v, true)
|
|
329
|
-
else throw new StoreKeyExistsError(k, valueString(v))
|
|
330
|
-
},
|
|
331
|
-
get: (): T => {
|
|
332
|
-
subscribe(watchers)
|
|
333
|
-
return recordToArray(current()) as T
|
|
355
|
+
},
|
|
334
356
|
},
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
index >= currentLength
|
|
343
|
-
)
|
|
344
|
-
throw new StoreKeyRangeError(index)
|
|
345
|
-
const newArray = [...currentArray]
|
|
346
|
-
newArray.splice(index, 1)
|
|
347
|
-
|
|
348
|
-
if (reconcile(currentArray, newArray as unknown as T))
|
|
349
|
-
notify(watchers)
|
|
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()
|
|
350
364
|
}
|
|
351
|
-
|
|
352
|
-
if (signals.has(k)) removeProperty(k, true)
|
|
353
|
-
},
|
|
354
|
-
set: (v: T): void => {
|
|
355
|
-
if (reconcile(current() as T, v)) {
|
|
356
|
-
notify(watchers)
|
|
357
|
-
if (UNSET === v) watchers.clear()
|
|
358
|
-
}
|
|
365
|
+
},
|
|
359
366
|
},
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
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))
|
|
364
405
|
notify(watchers)
|
|
365
|
-
|
|
366
|
-
}
|
|
406
|
+
emit('sort', newOrder)
|
|
407
|
+
},
|
|
367
408
|
},
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
) => number,
|
|
377
|
-
): void => {
|
|
378
|
-
// Get all entries as [key, value] pairs
|
|
379
|
-
const entries = Array.from(signals.entries())
|
|
380
|
-
.map(
|
|
381
|
-
([key, signal]) =>
|
|
382
|
-
[key, signal.get()] as [
|
|
383
|
-
string,
|
|
384
|
-
T[Extract<keyof T, string>],
|
|
385
|
-
],
|
|
386
|
-
)
|
|
387
|
-
.sort(
|
|
388
|
-
compareFn
|
|
389
|
-
? (a, b) => compareFn(a[1], b[1])
|
|
390
|
-
: (a, b) => String(a[1]).localeCompare(String(b[1])),
|
|
391
|
-
)
|
|
392
|
-
|
|
393
|
-
// Create array of original keys in their new sorted order
|
|
394
|
-
const newOrder: string[] = entries.map(([key]) => String(key))
|
|
395
|
-
const newSignals = new Map<
|
|
396
|
-
string,
|
|
397
|
-
Signal<T[Extract<keyof T, string>] & {}>
|
|
398
|
-
>()
|
|
399
|
-
|
|
400
|
-
entries.forEach(([key], newIndex) => {
|
|
401
|
-
const oldKey = String(key)
|
|
402
|
-
const newKey = isArrayLike ? String(newIndex) : String(key)
|
|
403
|
-
|
|
404
|
-
const signal = signals.get(oldKey)
|
|
405
|
-
if (signal) newSignals.set(newKey, signal)
|
|
406
|
-
})
|
|
407
|
-
|
|
408
|
-
// Replace signals map
|
|
409
|
-
signals.clear()
|
|
410
|
-
newSignals.forEach((signal, key) => signals.set(key, signal))
|
|
411
|
-
notify(watchers)
|
|
412
|
-
emit('sort', newOrder)
|
|
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
|
+
},
|
|
413
417
|
},
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
return () => listeners[type].delete(listener)
|
|
418
|
+
length: {
|
|
419
|
+
get(): number {
|
|
420
|
+
subscribe(watchers)
|
|
421
|
+
return signals.size
|
|
422
|
+
},
|
|
420
423
|
},
|
|
421
|
-
|
|
422
|
-
}
|
|
424
|
+
})
|
|
423
425
|
|
|
424
426
|
// Return proxy directly with integrated signal methods
|
|
425
|
-
return new Proxy(
|
|
426
|
-
get(
|
|
427
|
-
|
|
428
|
-
if (prop === Symbol.toStringTag) return TYPE_STORE
|
|
429
|
-
if (prop === Symbol.isConcatSpreadable) return isArrayLike
|
|
430
|
-
if (prop === Symbol.iterator)
|
|
431
|
-
return isArrayLike
|
|
432
|
-
? function* () {
|
|
433
|
-
const indexes = getSortedIndexes()
|
|
434
|
-
for (const index of indexes) {
|
|
435
|
-
const signal = signals.get(
|
|
436
|
-
String(index) as Extract<keyof T, string>,
|
|
437
|
-
)
|
|
438
|
-
if (signal) yield signal
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
: function* () {
|
|
442
|
-
for (const [key, signal] of signals)
|
|
443
|
-
yield [key, signal]
|
|
444
|
-
}
|
|
427
|
+
return new Proxy(store as Store<T>, {
|
|
428
|
+
get(target, prop) {
|
|
429
|
+
if (prop in target) return Reflect.get(target, prop)
|
|
445
430
|
if (isSymbol(prop)) return undefined
|
|
446
|
-
|
|
447
|
-
// Methods and Properties
|
|
448
|
-
if (prop in store) return store[prop]
|
|
449
|
-
if (prop === 'length' && isArrayLike) {
|
|
450
|
-
subscribe(watchers)
|
|
451
|
-
return size.get()
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
// Signals
|
|
455
|
-
return signals.get(prop as Extract<keyof T, string>)
|
|
431
|
+
return signals.get(prop)
|
|
456
432
|
},
|
|
457
|
-
has(
|
|
458
|
-
|
|
459
|
-
return (
|
|
460
|
-
(stringProp &&
|
|
461
|
-
signals.has(stringProp as Extract<keyof T, string>)) ||
|
|
462
|
-
Object.keys(store).includes(stringProp) ||
|
|
463
|
-
prop === Symbol.toStringTag ||
|
|
464
|
-
prop === Symbol.iterator ||
|
|
465
|
-
prop === Symbol.isConcatSpreadable ||
|
|
466
|
-
(prop === 'length' && isArrayLike)
|
|
467
|
-
)
|
|
433
|
+
has(target, prop) {
|
|
434
|
+
if (prop in target) return true
|
|
435
|
+
return signals.has(String(prop))
|
|
468
436
|
},
|
|
469
|
-
ownKeys() {
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
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])]
|
|
475
443
|
},
|
|
476
|
-
getOwnPropertyDescriptor(
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
configurable: true,
|
|
480
|
-
writable: false,
|
|
481
|
-
value,
|
|
482
|
-
})
|
|
483
|
-
|
|
484
|
-
if (prop === 'length' && isArrayLike)
|
|
485
|
-
return {
|
|
486
|
-
enumerable: true,
|
|
487
|
-
configurable: true,
|
|
488
|
-
writable: false,
|
|
489
|
-
value: size.get(),
|
|
490
|
-
}
|
|
491
|
-
if (prop === Symbol.isConcatSpreadable)
|
|
492
|
-
return nonEnumerable(isArrayLike)
|
|
493
|
-
if (prop === Symbol.toStringTag) return nonEnumerable(TYPE_STORE)
|
|
494
|
-
if (isSymbol(prop)) return undefined
|
|
495
|
-
|
|
496
|
-
if (Object.keys(store).includes(prop))
|
|
497
|
-
return nonEnumerable(store[prop])
|
|
444
|
+
getOwnPropertyDescriptor(target, prop) {
|
|
445
|
+
if (prop in target)
|
|
446
|
+
return Reflect.getOwnPropertyDescriptor(target, prop)
|
|
498
447
|
|
|
499
|
-
const signal = signals.get(prop
|
|
448
|
+
const signal = signals.get(String(prop))
|
|
500
449
|
return signal
|
|
501
450
|
? {
|
|
502
451
|
enumerable: true,
|
|
@@ -516,7 +465,7 @@ const createStore = <T extends UnknownRecord | UnknownArray>(
|
|
|
516
465
|
* @param {unknown} value - value to check
|
|
517
466
|
* @returns {boolean} - true if the value is a Store instance, false otherwise
|
|
518
467
|
*/
|
|
519
|
-
const isStore = <T extends
|
|
468
|
+
const isStore = <T extends UnknownRecord | UnknownArray>(
|
|
520
469
|
value: unknown,
|
|
521
470
|
): value is Store<T> => isObjectOfType(value, TYPE_STORE)
|
|
522
471
|
|
package/src/util.ts
CHANGED
|
@@ -66,9 +66,7 @@ const toError = /*#__PURE__*/ (reason: unknown): Error =>
|
|
|
66
66
|
|
|
67
67
|
const arrayToRecord = /*#__PURE__*/ <T>(array: T[]): Record<string, T> => {
|
|
68
68
|
const record: Record<string, T> = {}
|
|
69
|
-
for (let i = 0; i < array.length; i++)
|
|
70
|
-
record[String(i)] = array[i]
|
|
71
|
-
}
|
|
69
|
+
for (let i = 0; i < array.length; i++) record[String(i)] = array[i]
|
|
72
70
|
return record
|
|
73
71
|
}
|
|
74
72
|
|
|
@@ -79,9 +77,7 @@ const recordToArray = /*#__PURE__*/ <T>(
|
|
|
79
77
|
if (indexes === null) return record
|
|
80
78
|
|
|
81
79
|
const array: T[] = []
|
|
82
|
-
for (const index of indexes)
|
|
83
|
-
array.push(record[String(index)])
|
|
84
|
-
}
|
|
80
|
+
for (const index of indexes) array.push(record[String(index)])
|
|
85
81
|
return array
|
|
86
82
|
}
|
|
87
83
|
|
package/test/batch.test.ts
CHANGED
package/test/benchmark.test.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, mock, test } from 'bun:test'
|
|
2
|
-
import { batch, createComputed, createEffect, createState } from '
|
|
2
|
+
import { batch, createComputed, createEffect, createState } from '..'
|
|
3
3
|
import { Counter, makeGraph, runGraph } from './util/dependency-graph'
|
|
4
4
|
import type { Computed, ReactiveFramework } from './util/reactive-framework'
|
|
5
5
|
|
package/test/computed.test.ts
CHANGED
package/test/effect.test.ts
CHANGED
package/test/match.test.ts
CHANGED
package/test/resolve.test.ts
CHANGED
package/test/signal.test.ts
CHANGED
|
@@ -34,13 +34,13 @@ describe('toSignal', () => {
|
|
|
34
34
|
expect(typedResult).toBeDefined()
|
|
35
35
|
})
|
|
36
36
|
|
|
37
|
-
test('converts empty array to
|
|
37
|
+
test('converts empty array to ArrayStore<never[]>', () => {
|
|
38
38
|
const result = toSignal([])
|
|
39
39
|
|
|
40
40
|
// Runtime behavior
|
|
41
41
|
expect(isStore(result)).toBe(true)
|
|
42
42
|
expect(result.length).toBe(0)
|
|
43
|
-
expect(Object.keys(result).length).toBe(
|
|
43
|
+
expect(Object.keys(result).length).toBe(0)
|
|
44
44
|
})
|
|
45
45
|
|
|
46
46
|
test('converts record to Store<T>', () => {
|
package/test/state.test.ts
CHANGED