@oscarpalmer/mora 0.31.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 (54) hide show
  1. package/dist/batch.d.mts +4 -5
  2. package/dist/batch.mjs +4 -2
  3. package/dist/constants.d.mts +29 -19
  4. package/dist/constants.mjs +17 -2
  5. package/dist/effect.d.mts +4 -5
  6. package/dist/effect.mjs +2 -2
  7. package/dist/helpers/is.d.mts +14 -9
  8. package/dist/helpers/is.mjs +6 -0
  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 +3 -2
  16. package/dist/models.d.mts +45 -87
  17. package/dist/mora.full.mjs +461 -285
  18. package/dist/value/array.d.mts +4 -5
  19. package/dist/value/array.mjs +22 -69
  20. package/dist/value/computed.d.mts +3 -4
  21. package/dist/value/computed.mjs +14 -14
  22. package/dist/value/reactive.d.mts +2 -3
  23. package/dist/value/reactive.mjs +0 -1
  24. package/dist/value/readonly.d.mts +3 -5
  25. package/dist/value/readonly.mjs +15 -19
  26. package/dist/value/signal.d.mts +4 -5
  27. package/dist/value/signal.mjs +9 -22
  28. package/dist/value/store.d.mts +4 -5
  29. package/dist/value/store.mjs +16 -56
  30. package/package.json +6 -6
  31. package/src/batch.ts +15 -5
  32. package/src/constants.ts +32 -2
  33. package/src/effect.ts +6 -2
  34. package/src/helpers/is.ts +10 -0
  35. package/src/helpers/proxy.ts +99 -49
  36. package/src/helpers/subscription.ts +78 -0
  37. package/src/helpers/value.ts +69 -4
  38. package/src/index.ts +1 -1
  39. package/src/models.ts +38 -81
  40. package/src/value/array.ts +61 -150
  41. package/src/value/computed.ts +36 -13
  42. package/src/value/reactive.ts +8 -5
  43. package/src/value/readonly.ts +26 -25
  44. package/src/value/signal.ts +19 -22
  45. package/src/value/store.ts +35 -114
  46. package/types/constants.d.ts +1 -1
  47. package/types/index.d.ts +1 -1
  48. package/types/value/array.d.ts +1 -1
  49. package/types/value/computed.d.ts +0 -3
  50. package/types/value/signal.d.ts +1 -1
  51. package/types/value/store.d.ts +1 -1
  52. package/dist/subscription.d.mts +0 -7
  53. package/dist/subscription.mjs +0 -27
  54. package/src/subscription.ts +0 -45
@@ -1,8 +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 {isPlainObject} from '@oscarpalmer/atoms/is';
5
- import type {GenericCallback} from '@oscarpalmer/atoms/models';
6
3
  import {
7
4
  METHODS_AFFECTING_LENGTH,
8
5
  METHODS_UPDATE,
@@ -11,12 +8,15 @@ import {
11
8
  PROPERTY_LENGTH,
12
9
  } from '../constants';
13
10
  import {
14
- emityProxyValues,
15
- getReactiveValueInProxy,
11
+ emitProxyValues,
12
+ getValueInProxy,
13
+ peekValueInProxy,
16
14
  setProxyValue,
17
15
  setValueInProxy,
16
+ updateProxyValue,
18
17
  } from '../helpers/proxy';
19
- import {emitValue, equalArrays, getSimpleValue} from '../helpers/value';
18
+ import {subscribeToProxy} from '../helpers/subscription';
19
+ import {emitValue, equalArrays} from '../helpers/value';
20
20
  import type {
21
21
  Computed,
22
22
  ComputedEffect,
@@ -26,12 +26,13 @@ import type {
26
26
  ReadonlyInstances,
27
27
  Signal,
28
28
  } from '../models';
29
- import {subscribe, unsubscribe} from '../subscription';
30
29
  import {computed} from './computed';
31
30
  import {reactive} from './reactive';
32
31
  import {getReadonlyInstance} from './readonly';
33
32
  import {signal} from './signal';
34
33
 
34
+ // #region Functions
35
+
35
36
  /**
36
37
  * Create a reactive array from a function result
37
38
  *
@@ -71,26 +72,18 @@ export function array<Item>(
71
72
  ): ReactiveArray<Item> {
72
73
  const [rx, state] = reactive<Item[], Item>([], options);
73
74
 
74
- const indiced = new Map<number, [Computed<unknown>, ComputedEffect]>();
75
+ const isArray = true;
75
76
  const length = signal(0);
77
+ const mapped = new Map<number, [Computed<unknown>, ComputedEffect]>();
76
78
  const readonlies: ReadonlyInstances<Item[]> = {};
77
79
 
78
- let instance: Record<string, unknown> = {};
79
-
80
80
  state.value = new Proxy([], {
81
81
  get: (target: Item[], property: PropertyKey) =>
82
82
  METHODS_UPDATE.has(property as string)
83
83
  ? updateArray(property as string, target, state, length)
84
84
  : Reflect.get(target, property),
85
85
  set: (target: Item[], property: PropertyKey, value: Item) =>
86
- setValueInProxy({
87
- length,
88
- property,
89
- state,
90
- target,
91
- value,
92
- isArray: true,
93
- }),
86
+ setValueInProxy(isArray, state, target, property, value, length),
94
87
  });
95
88
 
96
89
  function get(): Item[];
@@ -98,85 +91,43 @@ export function array<Item>(
98
91
  function get(property: typeof PROPERTY_LENGTH): number;
99
92
  function get(value?: unknown): number | Item | Item[] | undefined;
100
93
 
101
- function get(value?: unknown): number | Item | Item[] | undefined {
102
- 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);
103
98
  }
104
99
 
105
- function set(first?: unknown, second?: unknown): void {
106
- setProxyValue<Item[], Item>(
107
- true,
108
- state,
109
- isArrayValue,
110
- isArrayIndex,
111
- setArray,
112
- setAtIndex,
113
- first,
114
- second,
115
- );
100
+ function set(first?: never, second?: never): void {
101
+ setProxyValue<Item[], Item>(true, state, setArrayValue, setAtIndex, first, second);
116
102
  }
117
103
 
118
- const handlers = {
104
+ const instance = {
119
105
  ...rx,
120
- get: (value?: number | typeof PROPERTY_LENGTH) => get(value),
121
- peek: (first?: unknown, second?: boolean) => peekArrayValue(state, length, first, second),
122
- subscribe: (first: number | GenericCallback, second?: GenericCallback) => {
123
- if (typeof first === 'number' && typeof second === 'function') {
124
- return getReactiveValueInProxy(
125
- instance as ReactiveArray<Item>,
126
- indiced,
127
- first,
128
- true,
129
- ).subscribe(second);
130
- }
131
-
132
- return typeof first === 'function' ? subscribe(state, first) : noop;
133
- },
134
- unsubscribe: (first: number | GenericCallback, second?: GenericCallback) => {
135
- if (typeof first === 'number' && typeof second === 'function') {
136
- getReactiveValueInProxy(instance as ReactiveArray<Item>, indiced, first, true)?.unsubscribe(
137
- second,
138
- );
139
- } else if (typeof first === 'function') {
140
- unsubscribe(state, first);
141
- }
142
- },
143
- };
144
-
145
- instance = {
146
- ...handlers,
147
- asReadonly: (frozen?: unknown) =>
148
- getReadonlyInstance(state, readonlies, handlers, frozen === true),
149
- at: (index: number): Item | undefined => get(index),
106
+ asReadonly: (frozen?: never) => getReadonlyInstance(state, readonlies, frozen === true),
107
+ at: (index: never) => get(index),
150
108
  clear: () => {
151
109
  state.value.length = 0;
152
110
  },
153
- filter: (callback: (item: Item, index: number, array: Item[]) => boolean) =>
154
- computed(() => filter(get(), callback)),
155
- map: <Mapped>(callback: (item: Item, index: number, array: Item[]) => Mapped) =>
156
- computed(() => get().map(callback)),
157
- notify: () => {
158
- emityProxyValues(state, indiced);
159
- },
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),
160
116
  pop: () => state.value.pop(),
161
117
  push: (...items: Item[]) => state.value.push(...items),
162
- select: <Mapped>(
163
- filter: (item: Item, index: number, array: Item[]) => boolean,
164
- map: (item: Item, index: number, array: Item[]) => Mapped,
165
- ) => computed(() => select(get() as Item[], filter, map)),
166
- set: (first?: unknown, second?: unknown) => {
167
- set(first, second);
168
- },
118
+ select: (filter: never, map: never) => computed(() => select(get(), filter, map)),
119
+ set: (first?: never, second?: never) => set(first, second),
169
120
  shift: () => state.value.shift(),
170
- splice: (from: number, to?: number, ...items: Item[]) =>
121
+ splice: (from: never, to?: never, ...items: Item[]) =>
171
122
  state.value.splice(from, to ?? state.value.length, ...items),
123
+ subscribe: (first: never, second?: never, third?: never) =>
124
+ subscribeToProxy(isArray, instance as never, state, mapped, first, second, third),
172
125
  unshift: (...items: Item[]) => state.value.unshift(...items),
173
- update: (callback: (value: Item[]) => Item[]) =>
174
- updateArrayValue(instance as ReactiveArray<Item>, state, callback),
126
+ update: (callback: never) => updateProxyValue(true, state, setArrayValue, setAtIndex, callback),
175
127
  };
176
128
 
177
129
  Object.defineProperties(instance, {
178
130
  [NAME_MORA]: {
179
- enumerable: false,
180
131
  value: NAME_ARRAY,
181
132
  },
182
133
  length: {
@@ -186,31 +137,9 @@ export function array<Item>(
186
137
  },
187
138
  });
188
139
 
189
- set(value);
140
+ set(value as never);
190
141
 
191
- return Object.freeze(instance) as ReactiveArray<Item>;
192
- }
193
-
194
- function getArrayValue<Item>(
195
- instance: ReactiveArray<Item>,
196
- indiced: Map<number, [Computed<unknown>, ComputedEffect]>,
197
- state: ReactiveState<Item[], Item>,
198
- length: Signal<number>,
199
- first?: unknown,
200
- ): number | Item | Item[] | undefined {
201
- if (typeof first === 'number') {
202
- return getReactiveValueInProxy(instance, indiced, first, true).get();
203
- }
204
-
205
- return first === PROPERTY_LENGTH ? length.get() : getSimpleValue(state);
206
- }
207
-
208
- function isArrayIndex(value: unknown): boolean {
209
- return typeof value === 'number';
210
- }
211
-
212
- function isArrayValue<Item>(value: unknown): value is Item[] | undefined {
213
- return value == null || Array.isArray(value);
142
+ return Object.freeze(instance) as never;
214
143
  }
215
144
 
216
145
  function peekArrayValue<Item>(
@@ -218,49 +147,41 @@ function peekArrayValue<Item>(
218
147
  length: Signal<number>,
219
148
  first?: unknown,
220
149
  second?: boolean,
221
- ): number | Item | Item[] | undefined {
222
- if (first === PROPERTY_LENGTH) {
223
- return length.peek();
224
- }
225
-
226
- let value: Item | Item[] | undefined;
227
-
228
- if (typeof first === 'number') {
229
- value = state.value.at(first);
230
- } else {
231
- value = state.value;
232
- }
233
-
234
- if (!(first === true || second === true)) {
235
- return value;
236
- }
237
-
238
- if (Array.isArray(value)) {
239
- return value.slice();
240
- }
241
-
242
- if (isPlainObject(value)) {
243
- return {...value};
244
- }
245
-
246
- return value;
247
- }
248
-
249
- function setArray<Item>(state: ReactiveState<Item[], Item>, value: Item[] | undefined): void {
250
- state.value.splice(0, state.value.length, ...(value ?? []));
150
+ ): unknown {
151
+ return first === PROPERTY_LENGTH ? length.peek() : peekValueInProxy(true, state, first, second);
251
152
  }
252
153
 
253
154
  function setArrayLength<Item>(state: ReactiveState<Item[], Item>, value: number): void {
254
- 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
+ ) {
255
161
  state.value.length = value;
256
162
  }
257
163
  }
258
164
 
259
- function setAtIndex<Item>(state: ReactiveState<Item[], Item>, index: unknown, value: Item): void {
260
- 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);
261
182
 
262
183
  if (actual > -1) {
263
- state.value[actual] = value;
184
+ (state.value as unknown[])[actual] = value;
264
185
  }
265
186
  }
266
187
 
@@ -274,7 +195,7 @@ function updateArray<Item>(
274
195
  const previousArray = affectsLength ? [] : array.slice();
275
196
  const previousLength = array.length;
276
197
 
277
- return (...args: unknown[]): unknown => {
198
+ return (...args: unknown[]) => {
278
199
  const result = (array[type as never] as (...args: unknown[]) => unknown)(...args);
279
200
 
280
201
  if (
@@ -289,14 +210,4 @@ function updateArray<Item>(
289
210
  };
290
211
  }
291
212
 
292
- function updateArrayValue<Item>(
293
- instance: ReactiveArray<Item>,
294
- state: ReactiveState<Item[], Item>,
295
- callback: (value: Item[]) => Item[],
296
- ): void {
297
- const updated = callback(state.value);
298
-
299
- if (updated == null || Array.isArray(updated)) {
300
- instance.set(updated);
301
- }
302
- }
213
+ // #endregion
@@ -1,11 +1,21 @@
1
1
  import {flushHandlers} from '../batch';
2
- import {ACTIVE, BATCH, NAME_COMPUTED, NAME_MORA} from '../constants';
2
+ import {
3
+ ACTIVE,
4
+ BATCH,
5
+ NAME_COMPUTED,
6
+ NAME_MORA,
7
+ SUBSCRIPTION_TYPES_COPY,
8
+ SUBSCRIPTION_TYPE_FROZEN,
9
+ SUBSCRIPTION_TYPES,
10
+ } from '../constants';
3
11
  import {internalEffect, runEffect} from '../effect';
4
- import {handleSimpleValue} from '../helpers/value';
12
+ import {subscribeToSignal} from '../helpers/subscription';
13
+ import {handleSimpleValue, peekSimpleValue} from '../helpers/value';
5
14
  import type {Computed, ComputedEffect, ReactiveOptions, ReactiveState} from '../models';
6
- import {subscribe} from '../subscription';
7
15
  import {reactive} from './reactive';
8
16
 
17
+ // #region Functions
18
+
9
19
  /**
10
20
  * Create a computed value
11
21
  *
@@ -24,6 +34,10 @@ function getComputed<Value>(
24
34
  callback: () => Value | Promise<Value>,
25
35
  options?: ReactiveOptions<Value>,
26
36
  ): [Computed<Value>, ComputedEffect] {
37
+ if (typeof callback !== 'function') {
38
+ throw new TypeError('Computed callback must be a function');
39
+ }
40
+
27
41
  const [rx, state] = reactive<Value>(undefined as never, options);
28
42
 
29
43
  let fx: ComputedEffect;
@@ -31,21 +45,17 @@ function getComputed<Value>(
31
45
  const instance = {
32
46
  ...rx,
33
47
  get: () => getValue(state, fx),
34
- peek: () => state.value,
35
- subscribe: (callback: (value: Value) => void) => subscribe(state, callback),
36
- unsubscribe: (callback: (value: Value) => void) => {
37
- state.subscriptions.delete(callback);
38
- },
48
+ peek: (copy?: never) => peekSimpleValue(state.value, copy === true),
49
+ subscribe: (callback: never, copy?: never) => subscribeToSignal(state, callback, copy === true),
39
50
  };
40
51
 
41
52
  Object.defineProperty(instance, NAME_MORA, {
42
- enumerable: false,
43
53
  value: NAME_COMPUTED,
44
54
  });
45
55
 
46
56
  fx = getComputedEffect(state, callback);
47
57
 
48
- return [Object.freeze(instance), fx];
58
+ return [Object.freeze(instance) as never, fx];
49
59
  }
50
60
 
51
61
  function getComputedEffect<Value>(
@@ -109,12 +119,25 @@ function setAndEmit<Value>(state: ReactiveState<Value, Value>, value: Value): vo
109
119
  }
110
120
 
111
121
  for (const effect of state.effects) {
112
- BATCH.handlers.add(effect);
122
+ BATCH.handlers.set(effect, effect);
113
123
  }
114
124
 
115
- for (const [, subscription] of state.subscriptions) {
116
- subscription.callback(value);
125
+ for (const type of SUBSCRIPTION_TYPES) {
126
+ if (type === SUBSCRIPTION_TYPE_FROZEN) {
127
+ continue;
128
+ }
129
+
130
+ const copy = SUBSCRIPTION_TYPES_COPY.has(type);
131
+ const subscriptions = state.subscriptions?.values.to.keyed?.get(type);
132
+
133
+ if (subscriptions != null) {
134
+ for (const [, callback] of subscriptions) {
135
+ callback(peekSimpleValue(state.value, copy));
136
+ }
137
+ }
117
138
  }
118
139
 
119
140
  flushHandlers();
120
141
  }
142
+
143
+ // #endregion
@@ -1,17 +1,18 @@
1
1
  import type {Reactive, ReactiveOptions, ReactiveState} from '../models';
2
2
 
3
- export function reactive<Value, Equal = Value>(
3
+ // #region Functions
4
+
5
+ export function reactive<Value, Item = Value>(
4
6
  value: Value,
5
- options?: ReactiveOptions<Equal>,
6
- ): [Reactive<Value>, ReactiveState<Value, Equal>] {
7
- const state: ReactiveState<Value, Equal> = {
7
+ options?: ReactiveOptions<Item>,
8
+ ): [Reactive<Value>, ReactiveState<Value, Item>] {
9
+ const state: ReactiveState<Value, Item> = {
8
10
  computeds: new Set(),
9
11
  effects: new Set(),
10
12
  equal:
11
13
  typeof options === 'object' && typeof options?.equal === 'function'
12
14
  ? options.equal
13
15
  : Object.is,
14
- subscriptions: new Map(),
15
16
  value: value as Value,
16
17
  };
17
18
 
@@ -22,3 +23,5 @@ export function reactive<Value, Equal = Value>(
22
23
 
23
24
  return [instance, state];
24
25
  }
26
+
27
+ // #endregion
@@ -1,42 +1,46 @@
1
- import {isPlainObject} from '@oscarpalmer/atoms/is';
2
- import type {GenericCallback} from '@oscarpalmer/atoms/models';
3
- import {NAME_MORA, NAME_READONLY} from '../constants';
4
- import {getSimpleValue} from '../helpers/value';
1
+ import {
2
+ NAME_MORA,
3
+ NAME_READONLY,
4
+ SUBSCRIPTION_TYPE_FROZEN,
5
+ SUBSCRIPTION_TYPE_READONLY,
6
+ } from '../constants';
7
+ import {subscribeToReactive} from '../helpers/subscription';
8
+ import {getFrozenValue, getSimpleValue, peekSimpleValue} from '../helpers/value';
5
9
  import type {
6
10
  ReactiveState,
7
11
  ReadonlyFrozenSignal,
8
12
  ReadonlyInstances,
9
13
  ReadonlySignal,
10
- ReadonlySignalValue,
11
14
  } from '../models';
12
15
 
16
+ // #region Functions
17
+
13
18
  export function getReadonlyInstance<Value>(
14
19
  state: ReactiveState<Value, never>,
15
20
  instances: ReadonlyInstances<Value>,
16
- handlers: Record<string, GenericCallback>,
17
21
  frozen: boolean,
18
22
  ): ReadonlySignal<Value> {
19
23
  const key = frozen ? 'frozen' : 'original';
20
24
 
21
- instances[key] ??= getReadonlySignal(state, handlers, frozen) as never;
25
+ instances[key] ??= getReadonlySignal(state, frozen) as never;
22
26
 
23
- return instances[key] as ReadonlySignal<Value>;
27
+ return instances[key] as never;
24
28
  }
25
29
 
26
30
  export function getReadonlySignal<Value>(
27
31
  state: ReactiveState<Value, never>,
28
- handlers: Record<string, GenericCallback>,
29
32
  frozen: boolean,
30
33
  ): ReadonlySignal<Value> | ReadonlyFrozenSignal<Value> {
34
+ const type = frozen ? SUBSCRIPTION_TYPE_FROZEN : SUBSCRIPTION_TYPE_READONLY;
35
+
31
36
  const instance = {
32
- ...handlers,
33
37
  get: () => getReadonlyValue(state, false, frozen),
34
- peek: () => getReadonlyValue(state, true, frozen),
38
+ peek: (copy?: boolean) => getReadonlyValue(state, true, frozen, copy),
39
+ subscribe: (callback: never) => subscribeToReactive(type, state, callback),
35
40
  };
36
41
 
37
42
  Object.defineProperties(instance, {
38
43
  [NAME_MORA]: {
39
- enumerable: false,
40
44
  value: NAME_READONLY,
41
45
  },
42
46
  frozen: {
@@ -45,27 +49,24 @@ export function getReadonlySignal<Value>(
45
49
  },
46
50
  });
47
51
 
48
- return Object.freeze(instance) as ReadonlySignal<Value>;
52
+ return Object.freeze(instance) as never;
49
53
  }
50
54
 
51
55
  function getReadonlyValue<Value>(
52
56
  state: ReactiveState<Value, never>,
53
57
  peek: boolean,
54
58
  frozen: boolean,
55
- ): Value | ReadonlySignalValue<Value> {
56
- let value = peek ? state.value : getSimpleValue(state);
59
+ copy?: boolean,
60
+ ): unknown {
61
+ let value: unknown;
57
62
 
58
- if (!frozen) {
59
- return value;
60
- }
61
-
62
- if (Array.isArray(state.value)) {
63
- value = [...state.value] as Value;
64
- } else if (isPlainObject(state.value)) {
65
- value = {...state.value} as Value;
63
+ if (peek) {
64
+ value = peekSimpleValue(state.value, copy === true);
66
65
  } else {
67
- value = state.value;
66
+ value = getSimpleValue(state);
68
67
  }
69
68
 
70
- return Object.freeze(value);
69
+ return frozen ? getFrozenValue(value) : value;
71
70
  }
71
+
72
+ // #endregion
@@ -1,10 +1,18 @@
1
1
  import {NAME_MORA, NAME_SIGNAL} from '../constants';
2
- import {emitValue, getSimpleValue, handleSimpleValue} from '../helpers/value';
2
+ import {subscribeToSignal} from '../helpers/subscription';
3
+ import {
4
+ emitValue,
5
+ getSimpleValue,
6
+ handleSimpleValue,
7
+ peekSimpleValue,
8
+ updateSimpleValue,
9
+ } from '../helpers/value';
3
10
  import type {ReactiveOptions, ReactiveState, ReadonlyInstances, Signal} from '../models';
4
- import {subscribe} from '../subscription';
5
11
  import {reactive} from './reactive';
6
12
  import {getReadonlyInstance} from './readonly';
7
13
 
14
+ // #region Functions
15
+
8
16
  function setAndEmit<Value>(state: ReactiveState<Value, Value>, value: Value): void {
9
17
  if (!state.equal(state.value, value)) {
10
18
  state.value = value;
@@ -54,34 +62,23 @@ export function signal<Value>(
54
62
 
55
63
  const readonlies: ReadonlyInstances<Value> = {};
56
64
 
57
- const handlers = {
58
- ...rx,
59
- subscribe: (callback: (value: Value) => void) => subscribe(state, callback),
60
- unsubscribe: (callback: (value: Value) => void) => {
61
- state.subscriptions.delete(callback);
62
- },
63
- };
64
-
65
65
  const instance = {
66
- ...handlers,
67
- asReadonly: (frozen?: unknown) =>
68
- getReadonlyInstance(state, readonlies, handlers, frozen === true),
66
+ ...rx,
67
+ asReadonly: (frozen?: never) => getReadonlyInstance(state, readonlies, frozen === true),
69
68
  get: () => getSimpleValue(state),
70
- peek: () => state.value,
71
- set: (value: Value | (() => Value | Promise<Value>) | Promise<Value>) => {
72
- handleSimpleValue(state, value, setAndEmit);
73
- },
74
- update: (callback: (value: Value) => Value) => {
75
- handleSimpleValue(state, callback(state.value), setAndEmit);
76
- },
69
+ peek: (copy?: boolean) => peekSimpleValue(state.value, copy === true),
70
+ set: (value: never) => handleSimpleValue(state, value, setAndEmit),
71
+ subscribe: (callback: never, copy?: never) => subscribeToSignal(state, callback, copy === true),
72
+ update: (callback: never) => updateSimpleValue(state, callback, setAndEmit),
77
73
  };
78
74
 
79
75
  Object.defineProperty(instance, NAME_MORA, {
80
- enumerable: false,
81
76
  value: NAME_SIGNAL,
82
77
  });
83
78
 
84
79
  handleSimpleValue(state, value, setAndEmit);
85
80
 
86
- return Object.freeze(instance) as Signal<Value>;
81
+ return Object.freeze(instance) as never;
87
82
  }
83
+
84
+ // #endregion