@oscarpalmer/mora 0.28.0 → 0.30.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 (42) hide show
  1. package/dist/batch.mjs +15 -6
  2. package/dist/constants.d.mts +0 -1
  3. package/dist/constants.mjs +4 -3
  4. package/dist/effect.d.mts +5 -8
  5. package/dist/effect.mjs +23 -19
  6. package/dist/helpers/is.d.mts +9 -9
  7. package/dist/helpers/is.mjs +6 -0
  8. package/dist/helpers/proxy.d.mts +5 -9
  9. package/dist/helpers/proxy.mjs +4 -4
  10. package/dist/helpers/value.d.mts +3 -3
  11. package/dist/helpers/value.mjs +21 -3
  12. package/dist/index.d.mts +7 -8
  13. package/dist/index.mjs +1 -1
  14. package/dist/models.d.mts +356 -18
  15. package/dist/mora.full.mjs +458 -409
  16. package/dist/subscription.d.mts +1 -9
  17. package/dist/subscription.mjs +14 -15
  18. package/dist/value/array.d.mts +5 -133
  19. package/dist/value/array.mjs +91 -137
  20. package/dist/value/computed.d.mts +4 -12
  21. package/dist/value/computed.mjs +54 -50
  22. package/dist/value/reactive.d.mts +3 -38
  23. package/dist/value/reactive.mjs +10 -49
  24. package/dist/value/signal.d.mts +5 -21
  25. package/dist/value/signal.mjs +27 -49
  26. package/dist/value/store.d.mts +9 -92
  27. package/dist/value/store.mjs +42 -49
  28. package/package.json +8 -8
  29. package/src/batch.ts +22 -9
  30. package/src/constants.ts +3 -4
  31. package/src/effect.ts +31 -26
  32. package/src/helpers/is.ts +11 -10
  33. package/src/helpers/proxy.ts +23 -18
  34. package/src/helpers/value.ts +38 -3
  35. package/src/index.ts +6 -7
  36. package/src/models.ts +431 -16
  37. package/src/subscription.ts +20 -20
  38. package/src/value/array.ts +183 -265
  39. package/src/value/computed.ts +80 -74
  40. package/src/value/reactive.ts +16 -64
  41. package/src/value/signal.ts +34 -71
  42. package/src/value/store.ts +84 -177
@@ -1,268 +1,37 @@
1
+ import {select} from '@oscarpalmer/atoms/array';
2
+ import {filter} from '@oscarpalmer/atoms/array/filter';
3
+ import {noop} from '@oscarpalmer/atoms/function';
1
4
  import type {GenericCallback} from '@oscarpalmer/atoms/models';
2
- import {METHODS_AFFECTING_LENGTH, METHODS_UPDATE, NAME_ARRAY, PROPERTY_LENGTH} from '../constants';
5
+ import {
6
+ METHODS_AFFECTING_LENGTH,
7
+ METHODS_UPDATE,
8
+ NAME_ARRAY,
9
+ NAME_MORA,
10
+ PROPERTY_LENGTH,
11
+ } from '../constants';
3
12
  import {
4
13
  emityProxyValues,
5
14
  getReactiveValueInProxy,
6
15
  setProxyValue,
7
16
  setValueInProxy,
8
17
  } from '../helpers/proxy';
9
- import {emitValue, equalArrays, getValue} from '../helpers/value';
10
- import type {ReactiveOptions, ReactiveState, Unsubscribe} from '../models';
11
- import {noop, subscribe} from '../subscription';
12
- import {type Computed, computed} from './computed';
13
- import {Reactive} from './reactive';
14
- import {type Signal, signal} from './signal';
15
-
16
- export class ReactiveArray<Item> extends Reactive<Item[], Item> {
17
- readonly #indiced = new Map<number, Computed<unknown>>();
18
-
19
- readonly #size = signal(0);
20
-
21
- /**
22
- * The length of the array
23
- */
24
- get length(): number {
25
- return this.#size.get();
26
- }
27
-
28
- /**
29
- * Set the length of the array
30
- */
31
- set length(value: number) {
32
- if (typeof value === 'number' && value >= 0 && value !== this.state.value.length) {
33
- this.get().length = value;
34
- }
35
- }
36
-
37
- constructor(value: Item[], options?: ReactiveOptions<Item>) {
38
- super(
39
- NAME_ARRAY,
40
- new Proxy(value, {
41
- get: (target: Item[], property: PropertyKey) =>
42
- METHODS_UPDATE.has(property as string)
43
- ? updateArray(property as string, target, this.state, this.#size)
44
- : Reflect.get(target, property),
45
- set: (target: Item[], property: PropertyKey, value: Item) =>
46
- setValueInProxy({
47
- property,
48
- target,
49
- value,
50
- isArray: true,
51
- state: this.state,
52
- length: this.#size,
53
- }),
54
- }),
55
- options,
56
- );
57
-
58
- this.#size.set(value.length);
59
- }
60
-
61
- /**
62
- * Clear the array
63
- */
64
- clear(): void {
65
- this.length = 0;
66
- }
67
-
68
- /**
69
- * Create a computed, filtered array
70
- * @param callback Callback to evaluate each item
71
- * @return Computed array of filtered items
72
- */
73
- filter(callback: (item: Item, index: number, array: Item[]) => boolean): Computed<Item[]> {
74
- return computed(() => this.get().filter(callback));
75
- }
76
-
77
- /**
78
- * @inheritdoc
79
- */
80
- get(): Item[];
81
-
82
- /**
83
- * Get the value at an index
84
- * @param index Index of item to get _(if negative, starts from the end)_
85
- * @returns Item at index, or `undefined` if it doesn't exist
86
- */
87
- get(index: number): Item | undefined;
88
-
89
- /**
90
- * Get the length of the array
91
- * @returns Length of the array
92
- */
93
- get(property: typeof PROPERTY_LENGTH): number;
94
-
95
- get(first?: unknown): unknown {
96
- if (typeof first === 'number') {
97
- return getReactiveValueInProxy(this, this.#indiced, first, true).get();
98
- }
99
-
100
- return first === PROPERTY_LENGTH ? this.length : getValue(this.state);
101
- }
102
-
103
- /**
104
- * Create a computed, mapped array
105
- * @param callback Callback to transform each item
106
- * @return Computed array of mapped items
107
- */
108
- map<Mapped>(callback: (item: Item, index: number, array: Item[]) => Mapped): Computed<Mapped[]> {
109
- return computed(() => this.get().map(callback));
110
- }
111
-
112
- /**
113
- * Notify dependents of changes
114
- *
115
- * _This bypasses equality checks and will immediately notify dependents.
116
- * Use this only if you're modifying nested data that would be ignored by equality checks._
117
- */
118
- notify(): void {
119
- emityProxyValues(this.state, this.#indiced);
120
- }
121
-
122
- /**
123
- * @inheritdoc
124
- */
125
- override peek(): Item[];
126
-
127
- /**
128
- * Get the value at an index _(without reactivity)_
129
- * @param index Index of item to get _(if negative, starts from the end)_
130
- * @returns Item at index, or `undefined` if it doesn't exist
131
- */
132
- override peek(index: number): Item | undefined;
133
-
134
- /**
135
- * Get the length of the array _(without reactivity)_
136
- * @returns Length of the array
137
- */
138
- override peek(property: typeof PROPERTY_LENGTH): number;
139
-
140
- override peek(value?: unknown): unknown {
141
- if (value === PROPERTY_LENGTH) {
142
- return this.#size.peek();
143
- }
144
-
145
- return typeof value === 'number' ? this.state.value.at(value) : this.state.value.slice();
146
- }
147
-
148
- /**
149
- * Remove and return the last item of the array
150
- * @returns Removed item, or `undefined` if the array is empty
151
- */
152
- pop(): Item | undefined {
153
- return this.state.value.pop();
154
- }
155
-
156
- /**
157
- * Add items to the end of the array
158
- * @param items Items to add
159
- * @returns New array length
160
- */
161
- push(...items: Item[]): number {
162
- return this.state.value.push(...items);
163
- }
164
-
165
- /**
166
- * Set the value
167
- * @param value New array of items _(defaults to an empty array)_
168
- */
169
- set(
170
- value?:
171
- | Item[]
172
- | (() => null | undefined | Item[] | Promise<null | undefined | Item[]>)
173
- | Promise<null | undefined | Item[]>,
174
- ): void;
175
-
176
- /**
177
- * Set the value at an index
178
- * @param index Index of item to set __(if negative, starts from the end)_
179
- * @param value New item
180
- */
181
- set(index: number, value: Item | (() => Item | Promise<Item>) | Promise<Item>): void;
182
-
183
- /**
184
- * Set the length of the array
185
- * @param value New array length
186
- */
187
- set(property: typeof PROPERTY_LENGTH, value: number): void;
188
-
189
- set(first?: unknown, second?: unknown): void {
190
- setProxyValue<Item[], Item>(
191
- true,
192
- this.state,
193
- isArrayValue,
194
- isArrayIndex,
195
- setArray,
196
- setAtIndex,
197
- first,
198
- second,
199
- );
200
- }
201
-
202
- /**
203
- * Remove and return the first item of the array
204
- * @returns Removed item, or `undefined` if the array is empty
205
- */
206
- shift(): Item | undefined {
207
- return this.state.value.shift();
208
- }
209
-
210
- /**
211
- * Remove and return items from the array _(and optionally add new items)_
212
- * @param from Index to start removing items from
213
- * @param to Index to stop removing items at _(defaults to the end of the array)_
214
- * @param items Optional items to add
215
- * @returns Removed items
216
- */
217
- splice(from: number, to?: number, ...items: Item[]): Item[] {
218
- return this.state.value.splice(from, to ?? this.state.value.length, ...items);
219
- }
220
-
221
- /**
222
- * @inheritdoc
223
- */
224
- override subscribe(callback: (value: Item[]) => void): Unsubscribe;
225
-
226
- /**
227
- * Subscribe to changes at a specific index
228
- * @param index Index of item to subscribe to
229
- * @param callback Callback for changes
230
- * @returns Unsubscribe callback
231
- */
232
- override subscribe(index: number, callback: (value: Item | undefined) => void): Unsubscribe;
233
-
234
- override subscribe(first: number | GenericCallback, second?: GenericCallback): Unsubscribe {
235
- if (typeof first === 'number' && typeof second === 'function') {
236
- return getReactiveValueInProxy(this, this.#indiced, first, true).subscribe(second);
237
- }
238
-
239
- return typeof first === 'function' ? subscribe(this.state, first) : noop;
240
- }
241
-
242
- /**
243
- * Add items to the beginning of the array
244
- * @param items Items to add
245
- * @returns New array length
246
- */
247
- unshift(...items: Item[]): number {
248
- return this.state.value.unshift(...items);
249
- }
250
-
251
- /**
252
- * Update the value _(based on the current value)_
253
- * @param callback Callback to update the value
254
- */
255
- update(callback: (value: Item[]) => Item[]): void {
256
- const updated = callback(this.state.value);
257
-
258
- if (updated == null || Array.isArray(updated)) {
259
- this.set(updated);
260
- }
261
- }
262
- }
18
+ import {emitValue, equalArrays, getSimpleValue} from '../helpers/value';
19
+ import type {
20
+ Computed,
21
+ ComputedEffect,
22
+ ReactiveArray,
23
+ ReactiveOptions,
24
+ ReactiveState,
25
+ Signal,
26
+ } from '../models';
27
+ import {subscribe, unsubscribe} from '../subscription';
28
+ import {computed} from './computed';
29
+ import {reactive} from './reactive';
30
+ import {signal} from './signal';
263
31
 
264
32
  /**
265
33
  * Create a reactive array from a function result
34
+ *
266
35
  * @param value Initial array of items
267
36
  * @param options Reactivity options
268
37
  * @returns Reactive array
@@ -274,6 +43,7 @@ export function array<Item>(
274
43
 
275
44
  /**
276
45
  * Create a reactive array from a promise
46
+ *
277
47
  * @param value Initial array of items
278
48
  * @param options Reactivity options
279
49
  * @returns Reactive array
@@ -285,6 +55,7 @@ export function array<Item>(
285
55
 
286
56
  /**
287
57
  * Create a reactive array
58
+ *
288
59
  * @param value Initial array of items
289
60
  * @param options Reactivity options
290
61
  * @returns Reactive array
@@ -295,11 +66,128 @@ export function array<Item>(
295
66
  value: Item[] | (() => Item[] | Promise<Item[]>) | Promise<Item[]>,
296
67
  options?: ReactiveOptions<Item>,
297
68
  ): ReactiveArray<Item> {
298
- const instance = new ReactiveArray([], options);
69
+ const [rx, state] = reactive<Item[], Item>([], options);
70
+
71
+ const indiced = new Map<number, [Computed<unknown>, ComputedEffect]>();
72
+ const length = signal(0);
73
+
74
+ state.value = new Proxy([], {
75
+ get: (target: Item[], property: PropertyKey) =>
76
+ METHODS_UPDATE.has(property as string)
77
+ ? updateArray(property as string, target, state, length)
78
+ : Reflect.get(target, property),
79
+ set: (target: Item[], property: PropertyKey, value: Item) =>
80
+ setValueInProxy({
81
+ length,
82
+ property,
83
+ state,
84
+ target,
85
+ value,
86
+ isArray: true,
87
+ }),
88
+ });
89
+
90
+ function get(): Item[];
91
+ function get(index: number): Item | undefined;
92
+ function get(property: typeof PROPERTY_LENGTH): number;
93
+ function get(value?: unknown): number | Item | Item[] | undefined;
94
+
95
+ function get(value?: unknown): number | Item | Item[] | undefined {
96
+ return getArrayValue(instance as ReactiveArray<Item>, indiced, state, length, value);
97
+ }
98
+
99
+ const instance = {
100
+ ...rx,
101
+ length: state.value.length,
102
+ at: (index: number): Item | undefined => get(index),
103
+ clear: () => {
104
+ state.value.length = 0;
105
+ },
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),
115
+ pop: () => state.value.pop(),
116
+ 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
+ },
133
+ shift: () => state.value.shift(),
134
+ splice: (from: number, to?: number, ...items: Item[]) =>
135
+ 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
+ },
148
+ 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),
160
+ };
161
+
162
+ Object.defineProperties(instance, {
163
+ [NAME_MORA]: {
164
+ enumerable: false,
165
+ value: NAME_ARRAY,
166
+ },
167
+ length: {
168
+ enumerable: true,
169
+ get: () => length.get(),
170
+ set: (value: number) => setArrayLength(state, value),
171
+ },
172
+ });
299
173
 
300
174
  instance.set(value);
301
175
 
302
- return instance;
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);
303
191
  }
304
192
 
305
193
  function isArrayIndex(value: unknown): boolean {
@@ -310,6 +198,36 @@ function isArrayValue<Item>(value: unknown): value is Item[] | undefined {
310
198
  return value == null || Array.isArray(value);
311
199
  }
312
200
 
201
+ function peekArrayValue<Item>(
202
+ state: ReactiveState<Item[], Item>,
203
+ 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 ?? []));
215
+ }
216
+
217
+ function setArrayLength<Item>(state: ReactiveState<Item[], Item>, value: number): void {
218
+ if (typeof value === 'number' && value >= 0 && value !== state.value.length) {
219
+ state.value.length = value;
220
+ }
221
+ }
222
+
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);
225
+
226
+ if (actual > -1) {
227
+ state.value[actual] = value;
228
+ }
229
+ }
230
+
313
231
  function updateArray<Item>(
314
232
  type: string,
315
233
  array: Item[],
@@ -335,14 +253,14 @@ function updateArray<Item>(
335
253
  };
336
254
  }
337
255
 
338
- function setArray<Item>(state: ReactiveState<Item[], Item>, value: Item[] | undefined): void {
339
- state.value.splice(0, state.value.length, ...(value ?? []));
340
- }
341
-
342
- function setAtIndex<Item>(state: ReactiveState<Item[], Item>, index: unknown, value: Item): void {
343
- const actual = (index as number) < 0 ? state.value.length + (index as number) : (index as number);
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);
344
262
 
345
- if (actual > -1) {
346
- state.value[actual] = value;
263
+ if (updated == null || Array.isArray(updated)) {
264
+ instance.set(updated);
347
265
  }
348
266
  }
@@ -1,58 +1,100 @@
1
1
  import {flushHandlers} from '../batch';
2
- import {ACTIVE, BATCH, NAME_COMPUTED} from '../constants';
3
- import {effect, runEffect} from '../effect';
4
- import type {ComputedEffect, InternalComputed, ReactiveOptions, ReactiveState} from '../models';
5
- import {Reactive} from './reactive';
2
+ import {ACTIVE, BATCH, NAME_COMPUTED, NAME_MORA} from '../constants';
3
+ import {internalEffect, runEffect} from '../effect';
4
+ import {handleSimpleValue} from '../helpers/value';
5
+ import type {Computed, ComputedEffect, ReactiveOptions, ReactiveState} from '../models';
6
+ import {subscribe} from '../subscription';
7
+ import {reactive} from './reactive';
6
8
 
7
- export class Computed<Value> extends Reactive<Value> {
8
- private readonly effect: ComputedEffect = {
9
+ /**
10
+ * Create a computed value
11
+ *
12
+ * @param callback Callback to compute the value
13
+ * @param options Reactivity options
14
+ * @returns Computed value
15
+ */
16
+ export function computed<Value>(
17
+ callback: () => Value | Promise<Value>,
18
+ options?: ReactiveOptions<Value>,
19
+ ): Computed<Value> {
20
+ return getComputed(callback, options)[0];
21
+ }
22
+
23
+ function getComputed<Value>(
24
+ callback: () => Value | Promise<Value>,
25
+ options?: ReactiveOptions<Value>,
26
+ ): [Computed<Value>, ComputedEffect] {
27
+ const [rx, state] = reactive<Value>(undefined as never, options);
28
+
29
+ let fx: ComputedEffect;
30
+
31
+ const instance = {
32
+ ...rx,
33
+ 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
+ },
39
+ };
40
+
41
+ Object.defineProperty(instance, NAME_MORA, {
42
+ enumerable: false,
43
+ value: NAME_COMPUTED,
44
+ });
45
+
46
+ fx = getComputedEffect(state, callback);
47
+
48
+ return [Object.freeze(instance), fx];
49
+ }
50
+
51
+ function getComputedEffect<Value>(
52
+ state: ReactiveState<Value, Value>,
53
+ callback: () => Value | Promise<Value>,
54
+ ): ComputedEffect {
55
+ const fx: ComputedEffect = {
9
56
  dirty: true,
10
57
  instance: undefined as never,
11
58
  };
12
59
 
13
- constructor(callback: () => Value | Promise<Value>, options?: ReactiveOptions<Value>) {
14
- super(NAME_COMPUTED, undefined as never, options);
60
+ fx.instance = internalEffect(() => {
61
+ if (fx.dirty) {
62
+ const previousComputed = ACTIVE.computed;
15
63
 
16
- this.effect.instance = effect(() => {
17
- if (this.effect.dirty) {
18
- setValue(this, this.state, callback);
64
+ ACTIVE.computed = fx;
19
65
 
20
- this.effect.dirty = false;
21
- }
22
- });
23
- }
66
+ handleSimpleValue(state, callback, setAndEmit, () => {
67
+ ACTIVE.computed = previousComputed;
68
+ });
24
69
 
25
- /**
26
- * @inheritdoc
27
- */
28
- get(): Value {
29
- if (ACTIVE.computed != null && this !== ACTIVE.computed) {
30
- this.state.computeds.add(ACTIVE.computed);
70
+ fx.dirty = false;
31
71
  }
72
+ });
32
73
 
33
- if (ACTIVE.effect != null && ACTIVE.effect !== this.effect.instance) {
34
- this.state.effects.add(ACTIVE.effect);
35
- }
74
+ return fx;
75
+ }
36
76
 
37
- if (this.effect.dirty && BATCH.depth === 0) {
38
- runEffect(this.effect.instance);
39
- }
77
+ function getValue<Value>(state: ReactiveState<Value, Value>, fx: ComputedEffect): Value {
78
+ if (ACTIVE.computed != null && fx !== ACTIVE.computed) {
79
+ state.computeds.add(ACTIVE.computed);
80
+ }
40
81
 
41
- return this.state.value;
82
+ if (ACTIVE.effect != null && ACTIVE.effect !== fx.instance) {
83
+ state.effects.add(ACTIVE.effect);
42
84
  }
85
+
86
+ if (fx.dirty && BATCH.depth === 0) {
87
+ runEffect(fx.instance);
88
+ }
89
+
90
+ return state.value;
43
91
  }
44
92
 
45
- /**
46
- * Create a computed value
47
- * @param callback Callback to compute the value
48
- * @param options Reactivity options
49
- * @returns Computed value
50
- */
51
- export function computed<Value>(
93
+ export function internalComputed<Value>(
52
94
  callback: () => Value | Promise<Value>,
53
95
  options?: ReactiveOptions<Value>,
54
- ): Computed<Value> {
55
- return new Computed(callback, options);
96
+ ): [Computed<Value>, ComputedEffect] {
97
+ return getComputed(callback, options);
56
98
  }
57
99
 
58
100
  function setAndEmit<Value>(state: ReactiveState<Value, Value>, value: Value): void {
@@ -63,7 +105,7 @@ function setAndEmit<Value>(state: ReactiveState<Value, Value>, value: Value): vo
63
105
  state.value = value;
64
106
 
65
107
  for (const computed of state.computeds) {
66
- (computed as unknown as InternalComputed).effect.dirty = true;
108
+ computed.dirty = true;
67
109
  }
68
110
 
69
111
  for (const effect of state.effects) {
@@ -76,39 +118,3 @@ function setAndEmit<Value>(state: ReactiveState<Value, Value>, value: Value): vo
76
118
 
77
119
  flushHandlers();
78
120
  }
79
-
80
- function setValue<Value>(
81
- instance: Computed<Value>,
82
- state: ReactiveState<Value, Value>,
83
- callback: () => Value | Promise<Value>,
84
- ): void {
85
- const previousComputed = ACTIVE.computed;
86
-
87
- ACTIVE.computed = instance as never;
88
-
89
- try {
90
- const value = callback();
91
-
92
- if (value instanceof Promise) {
93
- state.promise = value;
94
-
95
- value
96
- .then(resolvedValue => {
97
- if (state.promise === value) {
98
- state.promise = undefined;
99
-
100
- setAndEmit(state, resolvedValue);
101
- }
102
- })
103
- .catch(() => {
104
- if (state.promise === value) {
105
- state.promise = undefined;
106
- }
107
- });
108
- } else {
109
- setAndEmit(state, value);
110
- }
111
- } finally {
112
- ACTIVE.computed = previousComputed;
113
- }
114
- }