@oscarpalmer/mora 0.30.0 → 0.32.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.
Files changed (55) hide show
  1. package/dist/batch.d.mts +4 -5
  2. package/dist/batch.mjs +4 -2
  3. package/dist/constants.d.mts +29 -18
  4. package/dist/constants.mjs +19 -2
  5. package/dist/effect.d.mts +4 -5
  6. package/dist/effect.mjs +2 -2
  7. package/dist/helpers/is.d.mts +21 -15
  8. package/dist/helpers/is.mjs +21 -12
  9. package/dist/helpers/proxy.d.mts +12 -10
  10. package/dist/helpers/proxy.mjs +32 -14
  11. package/dist/helpers/subscription.d.mts +8 -0
  12. package/dist/helpers/subscription.mjs +27 -0
  13. package/dist/helpers/value.d.mts +8 -6
  14. package/dist/helpers/value.mjs +30 -4
  15. package/dist/index.d.mts +4 -3
  16. package/dist/index.mjs +2 -2
  17. package/dist/models.d.mts +108 -84
  18. package/dist/mora.full.mjs +504 -247
  19. package/dist/value/array.d.mts +4 -5
  20. package/dist/value/array.mjs +25 -56
  21. package/dist/value/computed.d.mts +3 -4
  22. package/dist/value/computed.mjs +14 -14
  23. package/dist/value/reactive.d.mts +2 -3
  24. package/dist/value/reactive.mjs +0 -1
  25. package/dist/value/readonly.d.mts +5 -0
  26. package/dist/value/readonly.mjs +33 -0
  27. package/dist/value/signal.d.mts +4 -5
  28. package/dist/value/signal.mjs +10 -17
  29. package/dist/value/store.d.mts +4 -5
  30. package/dist/value/store.mjs +17 -41
  31. package/package.json +6 -6
  32. package/src/batch.ts +15 -5
  33. package/src/constants.ts +41 -3
  34. package/src/effect.ts +6 -2
  35. package/src/helpers/is.ts +37 -12
  36. package/src/helpers/proxy.ts +99 -49
  37. package/src/helpers/subscription.ts +78 -0
  38. package/src/helpers/value.ts +69 -4
  39. package/src/index.ts +18 -2
  40. package/src/models.ts +131 -86
  41. package/src/value/array.ts +67 -120
  42. package/src/value/computed.ts +36 -13
  43. package/src/value/reactive.ts +8 -5
  44. package/src/value/readonly.ts +72 -0
  45. package/src/value/signal.ts +22 -16
  46. package/src/value/store.ts +37 -70
  47. package/types/constants.d.ts +1 -1
  48. package/types/index.d.ts +1 -1
  49. package/types/value/array.d.ts +1 -1
  50. package/types/value/computed.d.ts +0 -3
  51. package/types/value/signal.d.ts +1 -1
  52. package/types/value/store.d.ts +1 -1
  53. package/dist/subscription.d.mts +0 -7
  54. package/dist/subscription.mjs +0 -27
  55. package/src/subscription.ts +0 -45
package/src/models.ts CHANGED
@@ -1,6 +1,9 @@
1
- import type {GenericCallback, Key} from '@oscarpalmer/atoms/models';
1
+ import type {GenericCallback, Key, PlainObject} from '@oscarpalmer/atoms/models';
2
+ import type {Subscription, Subscriptions} from '@oscarpalmer/atoms/subscription';
2
3
  import type {PROPERTY_LENGTH} from './constants';
3
4
 
5
+ // #region Types
6
+
4
7
  export type Active = {
5
8
  computed?: ComputedEffect;
6
9
  effect?: EffectState;
@@ -9,7 +12,7 @@ export type Active = {
9
12
  export type Batch = {
10
13
  depth: number;
11
14
  flushing: boolean;
12
- handlers: Set<EffectState | Subscription>;
15
+ handlers: Map<EffectState | Subscription, EffectState | StoredSubscription>;
13
16
  };
14
17
 
15
18
  export type Computed<Value> = Reactive<Value> & SimpleReactive<Value>;
@@ -52,6 +55,24 @@ export type ReactiveArray<Item> = {
52
55
  */
53
56
  set length(value: number);
54
57
 
58
+ /**
59
+ * Get a readonly version of the reactive array
60
+ *
61
+ * @param frozen Freeze the array? _(defaults to `false`)_
62
+ * @returns Readonly reactive array
63
+ */
64
+ asReadonly(frozen: true): ReadonlyFrozenSignal<Item[]>;
65
+
66
+ /**
67
+ * Get a readonly version of the reactive array
68
+ *
69
+ * @param frozen Freeze the array? _(defaults to `false`)_
70
+ * @returns Readonly reactive array
71
+ */
72
+ asReadonly(
73
+ frozen?: boolean,
74
+ ): typeof frozen extends true ? ReadonlyFrozenSignal<Item[]> : ReadonlySignal<Item[]>;
75
+
55
76
  /**
56
77
  * Get the value at an index
57
78
  *
@@ -114,17 +135,19 @@ export type ReactiveArray<Item> = {
114
135
  /**
115
136
  * Get the array _(without reactivity)_
116
137
  *
138
+ * @param copy Copy the array? _(defaults to `false`)_
117
139
  * @returns Array of items
118
140
  */
119
- peek(): Item[];
141
+ peek(copy?: boolean): Item[];
120
142
 
121
143
  /**
122
144
  * Get the value at an index _(without reactivity)_
123
145
  *
124
146
  * @param index Index of item to get _(if negative, starts from the end)_
147
+ * @param copy If the item is an array or record, should it be copied? _(defaults to `false`)_
125
148
  * @returns Item at index, or `undefined` if it doesn't exist
126
149
  */
127
- peek(index: number): Item | undefined;
150
+ peek(index: number, copy?: boolean): Item | undefined;
128
151
 
129
152
  /**
130
153
  * Get the length of the array _(without reactivity)_
@@ -208,18 +231,24 @@ export type ReactiveArray<Item> = {
208
231
  * Subscribe to changes
209
232
  *
210
233
  * @param callback Callback for changes
211
- * @returns Unsubscribe callback
234
+ * @param copy Copy the array? _(defaults to `false`)_
235
+ * @returns Subscription
212
236
  */
213
- subscribe(callback: (value: Item[]) => void): Unsubscribe;
237
+ subscribe(callback: (value: Item[]) => void, copy?: boolean): Subscription;
214
238
 
215
239
  /**
216
240
  * Subscribe to changes at a specific index
217
241
  *
218
242
  * @param index Index of item to subscribe to
219
243
  * @param callback Callback for changes
220
- * @returns Unsubscribe callback
244
+ * @param copy If the item is an array or record, should it be copied? _(defaults to `false`)_
245
+ * @returns Subscription
221
246
  */
222
- subscribe(index: number, callback: (value: Item | undefined) => void): Unsubscribe;
247
+ subscribe(
248
+ index: number,
249
+ callback: (value: Item | undefined) => void,
250
+ copy?: boolean,
251
+ ): Subscription;
223
252
 
224
253
  /**
225
254
  * Add items to the beginning of the array
@@ -228,21 +257,6 @@ export type ReactiveArray<Item> = {
228
257
  */
229
258
  unshift(...items: Item[]): number;
230
259
 
231
- /**
232
- * Unsubscribe from changes for a specific index
233
- *
234
- * @param index Index of the value to unsubscribe from
235
- * @param callback Callback to unsubscribe
236
- */
237
- unsubscribe(index: number, callback: (item: Item | undefined) => void): void;
238
-
239
- /**
240
- * Unsubscribe from changes
241
- *
242
- * @param callback Callback to unsubscribe
243
- */
244
- unsubscribe(callback: (array: Item[]) => void): void;
245
-
246
260
  /**
247
261
  * Update the value _(based on the current value)_
248
262
  *
@@ -262,23 +276,41 @@ export type ReactiveOptions<Value> = {
262
276
  equal?: (first: Value, second: Value) => boolean;
263
277
  };
264
278
 
265
- export type ReactiveState<Value, Equal> = {
279
+ export type ReactiveState<Value, Item = Value> = {
266
280
  computeds: Set<ComputedEffect>;
267
281
  effects: Set<EffectState>;
268
- equal: (first: Equal, second: Equal) => boolean;
282
+ equal: (first: Item, second: Item) => boolean;
269
283
  promise?: Promise<Value>;
270
284
  promises?: Map<Key, Promise<never>>;
271
- subscriptions: Map<GenericCallback, Subscription>;
285
+ subscriptions?: Subscriptions<GenericCallback>;
272
286
  value: Value;
273
287
  };
274
288
 
275
- export type ReactiveStore<Value> = {
289
+ export type ReactiveStore<Store> = {
290
+ /**
291
+ * Get a readonly version of the reactive store
292
+ *
293
+ * @param frozen Freeze the store? _(defaults to `false`)_
294
+ * @returns Readonly reactive store
295
+ */
296
+ asReadonly(frozen: true): ReadonlyFrozenSignal<Store>;
297
+
298
+ /**
299
+ * Get a readonly version of the reactive store
300
+ *
301
+ * @param frozen Freeze the store? _(defaults to `false`)_
302
+ * @returns Readonly reactive store
303
+ */
304
+ asReadonly(
305
+ frozen?: boolean,
306
+ ): typeof frozen extends true ? ReadonlyFrozenSignal<Store> : ReadonlySignal<Store>;
307
+
276
308
  /**
277
309
  * Get the value
278
310
  *
279
311
  * @returns Current value
280
312
  */
281
- get(): Value;
313
+ get(): Store;
282
314
 
283
315
  /**
284
316
  * Get a value by key
@@ -286,7 +318,7 @@ export type ReactiveStore<Value> = {
286
318
  * @param key Key of the value to get
287
319
  * @returns Value for the specified key, or `undefined` if it doesn't exist
288
320
  */
289
- get<Key extends keyof Value>(key: Key): Value[Key];
321
+ get<Key extends keyof Store>(key: Key): Store[Key];
290
322
 
291
323
  /**
292
324
  * Get a value by key
@@ -307,25 +339,28 @@ export type ReactiveStore<Value> = {
307
339
  /**
308
340
  * Get the value _(without reactivity)_
309
341
  *
342
+ * @param copy Copy the store? _(defaults to `false`)_
310
343
  * @returns Current value
311
344
  */
312
- peek(): Value;
345
+ peek(copy?: boolean): Store;
313
346
 
314
347
  /**
315
348
  * Get a value by key _(without reactivity)_
316
349
  *
317
350
  * @param key Key of the value to get
351
+ * @param copy If the value is an array or record, should it be copied? _(defaults to `false`)_
318
352
  * @returns Value for the specified key, or `undefined` if it doesn't exist
319
353
  */
320
- peek<Key extends keyof Value>(key: Key): Value[Key];
354
+ peek<Key extends keyof Store>(key: Key, copy?: boolean): Store[Key];
321
355
 
322
356
  /**
323
357
  * Get a value by key _(without reactivity)_
324
358
  *
325
359
  * @param key Key of the value to get
360
+ * @param copy If the value is an array or record, should it be copied? _(defaults to `false`)_
326
361
  * @returns Value for the specified key, or `undefined` if it doesn't exist
327
362
  */
328
- peek(key: Key): unknown;
363
+ peek(key: Key, copy?: boolean): unknown;
329
364
 
330
365
  /**
331
366
  * Set the value
@@ -334,9 +369,9 @@ export type ReactiveStore<Value> = {
334
369
  */
335
370
  set(
336
371
  value?:
337
- | Value
338
- | (() => null | undefined | Value | Promise<null | undefined | Value>)
339
- | Promise<null | undefined | Value>,
372
+ | Store
373
+ | (() => null | undefined | Store | Promise<null | undefined | Store>)
374
+ | Promise<null | undefined | Store>,
340
375
  ): void;
341
376
 
342
377
  /**
@@ -345,9 +380,9 @@ export type ReactiveStore<Value> = {
345
380
  * @param key Key of the value to set
346
381
  * @param value New value
347
382
  */
348
- set<Key extends keyof Value>(
383
+ set<Key extends keyof Store>(
349
384
  key: Key,
350
- value: Value[Key] | (() => Value[Key] | Promise<Value[Key]>) | Promise<Value[Key]>,
385
+ value: Store[Key] | (() => Store[Key] | Promise<Store[Key]>) | Promise<Store[Key]>,
351
386
  ): void;
352
387
 
353
388
  /**
@@ -362,67 +397,83 @@ export type ReactiveStore<Value> = {
362
397
  * Subscribe to changes
363
398
  *
364
399
  * @param callback Callback for changes
365
- * @returns Unsubscribe callback
400
+ * @param copy Copy the store? _(defaults to `false`)_
401
+ * @returns Subscription
366
402
  */
367
- subscribe(callback: (value: Value) => void): Unsubscribe;
403
+ subscribe(callback: (value: Store) => void, copy?: boolean): Subscription;
368
404
 
369
405
  /**
370
406
  * Subscribe to changes for a specific key
371
407
  *
372
408
  * @param key Key of the value to subscribe to
373
409
  * @param callback Callback for changes
374
- * @returns Unsubscribe callback
410
+ * @param copy If the value is an array or record, should it be copied? _(defaults to `false`)_
411
+ * @returns Subscription
375
412
  */
376
- subscribe<Key extends keyof Value>(
413
+ subscribe<Key extends keyof Store>(
377
414
  key: Key,
378
- callback: (value: Value[Key] | undefined) => void,
379
- ): Unsubscribe;
415
+ callback: (value: Store[Key] | undefined) => void,
416
+ copy?: boolean,
417
+ ): Subscription;
380
418
 
381
419
  /**
382
420
  * Subscribe to changes for a specific key
383
421
  *
384
422
  * @param key Key of the value to subscribe to
385
423
  * @param callback Callback for changes
386
- * @returns Unsubscribe callback
424
+ * @param copy If the value is an array or record, should it be copied? _(defaults to `false`)_
425
+ * @returns Subscription
387
426
  */
388
- subscribe(key: Key, callback: (value: unknown) => void): Unsubscribe;
427
+ subscribe(key: Key, callback: (value: unknown) => void, copy?: boolean): Subscription;
389
428
 
390
429
  /**
391
- * Unsubscribe from changes for a specific key
430
+ * Update the value _(based on the current value)_
392
431
  *
393
- * @param key Key of the value to unsubscribe from
394
- * @param callback Callback to unsubscribe
432
+ * @param callback Callback to update the value
395
433
  */
396
- unsubscribe<Key extends keyof Value>(
397
- key: Key,
398
- callback: (value: Value[Key] | undefined) => void,
399
- ): void;
434
+ update(callback: (value: Store) => Store): void;
435
+ } & Reactive<Store>;
436
+
437
+ export type ReadonlyInstances<Value> = {
438
+ frozen?: ReadonlyFrozenSignal<Value>;
439
+ original?: ReadonlySignal<Value>;
440
+ };
441
+
442
+ export type ReadonlyFrozenSignal<Value> = ReadonlySignal<ReadonlySignalValue<Value>>;
400
443
 
444
+ export type ReadonlySignal<Value> = {
401
445
  /**
402
- * Unsubscribe from changes
446
+ * Is the signal frozen?
447
+ */
448
+ get frozen(): boolean;
449
+ } & Reactive<Value> &
450
+ SimpleReactive<Value>;
451
+
452
+ export type ReadonlySignalValue<Value> = Value extends unknown[]
453
+ ? Readonly<Value>
454
+ : Value extends PlainObject
455
+ ? Readonly<Value>
456
+ : Value;
457
+
458
+ export type Signal<Value> = {
459
+ /**
460
+ * Get a readonly version of the signal
403
461
  *
404
- * @param callback Callback to unsubscribe
462
+ * @param frozen Freeze the signal? _(defaults to `false`)_
463
+ * @returns Readonly signal
405
464
  */
406
- unsubscribe(callback: (value: Value) => void): void;
465
+ asReadonly(frozen: true): ReadonlyFrozenSignal<Value>;
407
466
 
408
467
  /**
409
- * Update the value _(based on the current value)_
468
+ * Get a readonly version of the signal
410
469
  *
411
- * @param callback Callback to update the value
470
+ * @param frozen Freeze the signal? _(defaults to `false`)_
471
+ * @returns Readonly signal
412
472
  */
413
- update(callback: (value: Value) => Value): void;
414
- } & Reactive<Value>;
415
-
416
- export type SetValueInProxyParameters<Value, Equal> = {
417
- target: Value;
418
- property: PropertyKey;
419
- value: unknown;
420
- state: ReactiveState<Value, Equal>;
421
- isArray: boolean;
422
- length?: Signal<number>;
423
- };
473
+ asReadonly(
474
+ frozen?: boolean,
475
+ ): typeof frozen extends true ? ReadonlyFrozenSignal<Value> : ReadonlySignal<Value>;
424
476
 
425
- export type Signal<Value> = {
426
477
  /**
427
478
  * Set the value
428
479
  *
@@ -450,34 +501,28 @@ type SimpleReactive<Value> = {
450
501
  /**
451
502
  * Get the value _(without reactivity)_
452
503
  *
504
+ * @param copy If the value is an array or record, should it be copied? _(defaults to `false`)_
453
505
  * @returns Current value
454
506
  */
455
- peek(): Value;
507
+ peek(copy?: boolean): Value;
456
508
 
457
509
  /**
458
510
  * Subscribe to changes
459
511
  *
460
512
  * @param callback Callback for changes
461
- * @returns Unsubscribe callback
513
+ * @param copy If the value is an array or record, should it be copied? _(defaults to `false`)_
514
+ * @returns Subscription
462
515
  */
463
- subscribe(callback: (value: Value) => void): Unsubscribe;
464
-
465
- /**
466
- * Unsubscribe from changes
467
- *
468
- * @param callback Callback to unsubscribe
469
- */
470
- unsubscribe(callback: (value: Value) => void): void;
516
+ subscribe(callback: (value: Value) => void, copy?: boolean): Subscription;
471
517
  };
472
518
 
473
- export type Subscription = {
519
+ export type StoredSubscription = {
474
520
  callback: GenericCallback;
521
+ copy: boolean;
522
+ frozen: boolean;
475
523
  state: ReactiveState<unknown, never>;
476
-
477
- destroy(): void;
478
524
  };
479
525
 
480
- /**
481
- * Unsubscribe from changes
482
- */
483
- export type Unsubscribe = () => void;
526
+ export type SubscriptionType = 'copy' | 'frozen' | 'original' | 'readonly';
527
+
528
+ // #endregion
@@ -1,7 +1,5 @@
1
1
  import {select} from '@oscarpalmer/atoms/array';
2
2
  import {filter} from '@oscarpalmer/atoms/array/filter';
3
- import {noop} from '@oscarpalmer/atoms/function';
4
- import type {GenericCallback} from '@oscarpalmer/atoms/models';
5
3
  import {
6
4
  METHODS_AFFECTING_LENGTH,
7
5
  METHODS_UPDATE,
@@ -10,25 +8,31 @@ import {
10
8
  PROPERTY_LENGTH,
11
9
  } from '../constants';
12
10
  import {
13
- emityProxyValues,
14
- getReactiveValueInProxy,
11
+ emitProxyValues,
12
+ getValueInProxy,
13
+ peekValueInProxy,
15
14
  setProxyValue,
16
15
  setValueInProxy,
16
+ updateProxyValue,
17
17
  } from '../helpers/proxy';
18
- import {emitValue, equalArrays, getSimpleValue} from '../helpers/value';
18
+ import {subscribeToProxy} from '../helpers/subscription';
19
+ import {emitValue, equalArrays} from '../helpers/value';
19
20
  import type {
20
21
  Computed,
21
22
  ComputedEffect,
22
23
  ReactiveArray,
23
24
  ReactiveOptions,
24
25
  ReactiveState,
26
+ ReadonlyInstances,
25
27
  Signal,
26
28
  } from '../models';
27
- import {subscribe, unsubscribe} from '../subscription';
28
29
  import {computed} from './computed';
29
30
  import {reactive} from './reactive';
31
+ import {getReadonlyInstance} from './readonly';
30
32
  import {signal} from './signal';
31
33
 
34
+ // #region Functions
35
+
32
36
  /**
33
37
  * Create a reactive array from a function result
34
38
  *
@@ -68,8 +72,10 @@ export function array<Item>(
68
72
  ): ReactiveArray<Item> {
69
73
  const [rx, state] = reactive<Item[], Item>([], options);
70
74
 
71
- const indiced = new Map<number, [Computed<unknown>, ComputedEffect]>();
75
+ const isArray = true;
72
76
  const length = signal(0);
77
+ const mapped = new Map<number, [Computed<unknown>, ComputedEffect]>();
78
+ const readonlies: ReadonlyInstances<Item[]> = {};
73
79
 
74
80
  state.value = new Proxy([], {
75
81
  get: (target: Item[], property: PropertyKey) =>
@@ -77,14 +83,7 @@ export function array<Item>(
77
83
  ? updateArray(property as string, target, state, length)
78
84
  : Reflect.get(target, property),
79
85
  set: (target: Item[], property: PropertyKey, value: Item) =>
80
- setValueInProxy({
81
- length,
82
- property,
83
- state,
84
- target,
85
- value,
86
- isArray: true,
87
- }),
86
+ setValueInProxy(isArray, state, target, property, value, length),
88
87
  });
89
88
 
90
89
  function get(): Item[];
@@ -92,76 +91,43 @@ export function array<Item>(
92
91
  function get(property: typeof PROPERTY_LENGTH): number;
93
92
  function get(value?: unknown): number | Item | Item[] | undefined;
94
93
 
95
- function get(value?: unknown): number | Item | Item[] | undefined {
96
- return getArrayValue(instance as ReactiveArray<Item>, indiced, state, length, value);
94
+ function get(value?: unknown): unknown {
95
+ return value === PROPERTY_LENGTH
96
+ ? length.get()
97
+ : getValueInProxy(isArray, instance as never, state, mapped, value);
98
+ }
99
+
100
+ function set(first?: never, second?: never): void {
101
+ setProxyValue<Item[], Item>(true, state, setArrayValue, setAtIndex, first, second);
97
102
  }
98
103
 
99
104
  const instance = {
100
105
  ...rx,
101
- length: state.value.length,
102
- at: (index: number): Item | undefined => get(index),
106
+ asReadonly: (frozen?: never) => getReadonlyInstance(state, readonlies, frozen === true),
107
+ at: (index: never) => get(index),
103
108
  clear: () => {
104
109
  state.value.length = 0;
105
110
  },
106
- filter: (callback: (item: Item, index: number, array: Item[]) => boolean) =>
107
- computed(() => filter(get(), callback)),
108
- get: (value?: number | typeof PROPERTY_LENGTH) => get(value),
109
- map: <Mapped>(callback: (item: Item, index: number, array: Item[]) => Mapped) =>
110
- computed(() => (get() as Item[]).map(callback)),
111
- notify: () => {
112
- emityProxyValues(state, indiced);
113
- },
114
- peek: (value?: unknown) => peekArrayValue(state, length, value),
111
+ filter: (callback: never) => computed(() => filter(get(), callback)),
112
+ get: (value?: never) => get(value),
113
+ map: (callback: never) => computed(() => get().map(callback)),
114
+ notify: () => emitProxyValues(state, mapped),
115
+ peek: (first?: never, second?: never) => peekArrayValue(state, length, first, second),
115
116
  pop: () => state.value.pop(),
116
117
  push: (...items: Item[]) => state.value.push(...items),
117
- select: <Mapped>(
118
- filter: (item: Item, index: number, array: Item[]) => boolean,
119
- map: (item: Item, index: number, array: Item[]) => Mapped,
120
- ) => computed(() => select(get() as Item[], filter, map)),
121
- set: (first?: unknown, second?: unknown) => {
122
- setProxyValue<Item[], Item>(
123
- true,
124
- state,
125
- isArrayValue,
126
- isArrayIndex,
127
- setArray,
128
- setAtIndex,
129
- first,
130
- second,
131
- );
132
- },
118
+ select: (filter: never, map: never) => computed(() => select(get(), filter, map)),
119
+ set: (first?: never, second?: never) => set(first, second),
133
120
  shift: () => state.value.shift(),
134
- splice: (from: number, to?: number, ...items: Item[]) =>
121
+ splice: (from: never, to?: never, ...items: Item[]) =>
135
122
  state.value.splice(from, to ?? state.value.length, ...items),
136
- subscribe: (first: number | GenericCallback, second?: GenericCallback) => {
137
- if (typeof first === 'number' && typeof second === 'function') {
138
- return getReactiveValueInProxy(
139
- instance as ReactiveArray<Item>,
140
- indiced,
141
- first,
142
- true,
143
- ).subscribe(second);
144
- }
145
-
146
- return typeof first === 'function' ? subscribe(state, first) : noop;
147
- },
123
+ subscribe: (first: never, second?: never, third?: never) =>
124
+ subscribeToProxy(isArray, instance as never, state, mapped, first, second, third),
148
125
  unshift: (...items: Item[]) => state.value.unshift(...items),
149
- unsubscribe: (first: number | GenericCallback, second?: GenericCallback) => {
150
- if (typeof first === 'number' && typeof second === 'function') {
151
- getReactiveValueInProxy(instance as ReactiveArray<Item>, indiced, first, true)?.unsubscribe(
152
- second,
153
- );
154
- } else if (typeof first === 'function') {
155
- unsubscribe(state, first);
156
- }
157
- },
158
- update: (callback: (value: Item[]) => Item[]) =>
159
- updateArrayValue(instance as ReactiveArray<Item>, state, callback),
126
+ update: (callback: never) => updateProxyValue(true, state, setArrayValue, setAtIndex, callback),
160
127
  };
161
128
 
162
129
  Object.defineProperties(instance, {
163
130
  [NAME_MORA]: {
164
- enumerable: false,
165
131
  value: NAME_ARRAY,
166
132
  },
167
133
  length: {
@@ -171,60 +137,51 @@ export function array<Item>(
171
137
  },
172
138
  });
173
139
 
174
- instance.set(value);
175
-
176
- return Object.freeze(instance) as ReactiveArray<Item>;
177
- }
178
-
179
- function getArrayValue<Item>(
180
- instance: ReactiveArray<Item>,
181
- indiced: Map<number, [Computed<unknown>, ComputedEffect]>,
182
- state: ReactiveState<Item[], Item>,
183
- length: Signal<number>,
184
- first?: unknown,
185
- ): number | Item | Item[] | undefined {
186
- if (typeof first === 'number') {
187
- return getReactiveValueInProxy(instance, indiced, first, true).get();
188
- }
189
-
190
- return first === PROPERTY_LENGTH ? length.get() : getSimpleValue(state);
191
- }
140
+ set(value as never);
192
141
 
193
- function isArrayIndex(value: unknown): boolean {
194
- return typeof value === 'number';
195
- }
196
-
197
- function isArrayValue<Item>(value: unknown): value is Item[] | undefined {
198
- return value == null || Array.isArray(value);
142
+ return Object.freeze(instance) as never;
199
143
  }
200
144
 
201
145
  function peekArrayValue<Item>(
202
146
  state: ReactiveState<Item[], Item>,
203
147
  length: Signal<number>,
204
- value?: unknown,
205
- ): number | Item | Item[] | undefined {
206
- if (value === PROPERTY_LENGTH) {
207
- return length.peek();
208
- }
209
-
210
- return typeof value === 'number' ? state.value.at(value) : state.value.slice();
211
- }
212
-
213
- function setArray<Item>(state: ReactiveState<Item[], Item>, value: Item[] | undefined): void {
214
- state.value.splice(0, state.value.length, ...(value ?? []));
148
+ first?: unknown,
149
+ second?: boolean,
150
+ ): unknown {
151
+ return first === PROPERTY_LENGTH ? length.peek() : peekValueInProxy(true, state, first, second);
215
152
  }
216
153
 
217
154
  function setArrayLength<Item>(state: ReactiveState<Item[], Item>, value: number): void {
218
- if (typeof value === 'number' && value >= 0 && value !== state.value.length) {
155
+ if (
156
+ typeof value === 'number' &&
157
+ !Number.isNaN(value) &&
158
+ value >= 0 &&
159
+ value !== state.value.length
160
+ ) {
219
161
  state.value.length = value;
220
162
  }
221
163
  }
222
164
 
223
- function setAtIndex<Item>(state: ReactiveState<Item[], Item>, index: unknown, value: Item): void {
224
- const actual = (index as number) < 0 ? state.value.length + (index as number) : (index as number);
165
+ function setArrayValue<Value, Item = Value>(state: ReactiveState<Value, Item>, value: Value): void {
166
+ (state.value as unknown[]).splice(
167
+ 0,
168
+ (state.value as unknown[]).length,
169
+ ...((value as unknown[]) ?? []),
170
+ );
171
+ }
172
+
173
+ function setAtIndex<Value, Item = Value>(
174
+ state: ReactiveState<Value, Item>,
175
+ index: unknown,
176
+ value: Item,
177
+ ): void {
178
+ const actual =
179
+ (index as number) < 0
180
+ ? (state.value as unknown[]).length + (index as number)
181
+ : (index as number);
225
182
 
226
183
  if (actual > -1) {
227
- state.value[actual] = value;
184
+ (state.value as unknown[])[actual] = value;
228
185
  }
229
186
  }
230
187
 
@@ -238,7 +195,7 @@ function updateArray<Item>(
238
195
  const previousArray = affectsLength ? [] : array.slice();
239
196
  const previousLength = array.length;
240
197
 
241
- return (...args: unknown[]): unknown => {
198
+ return (...args: unknown[]) => {
242
199
  const result = (array[type as never] as (...args: unknown[]) => unknown)(...args);
243
200
 
244
201
  if (
@@ -253,14 +210,4 @@ function updateArray<Item>(
253
210
  };
254
211
  }
255
212
 
256
- function updateArrayValue<Item>(
257
- instance: ReactiveArray<Item>,
258
- state: ReactiveState<Item[], Item>,
259
- callback: (value: Item[]) => Item[],
260
- ): void {
261
- const updated = callback(state.value);
262
-
263
- if (updated == null || Array.isArray(updated)) {
264
- instance.set(updated);
265
- }
266
- }
213
+ // #endregion