@oscarpalmer/mora 0.31.0 → 0.33.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 (58) hide show
  1. package/dist/batch.d.mts +4 -5
  2. package/dist/batch.mjs +4 -2
  3. package/dist/constants.d.mts +31 -19
  4. package/dist/constants.mjs +19 -2
  5. package/dist/effect.d.mts +5 -5
  6. package/dist/effect.mjs +8 -5
  7. package/dist/helpers/is.d.mts +14 -9
  8. package/dist/helpers/is.mjs +6 -0
  9. package/dist/helpers/misc.d.mts +4 -0
  10. package/dist/helpers/misc.mjs +9 -0
  11. package/dist/helpers/proxy.d.mts +10 -10
  12. package/dist/helpers/proxy.mjs +83 -27
  13. package/dist/helpers/subscription.d.mts +8 -0
  14. package/dist/helpers/subscription.mjs +30 -0
  15. package/dist/helpers/value.d.mts +10 -7
  16. package/dist/helpers/value.mjs +56 -17
  17. package/dist/index.d.mts +3 -2
  18. package/dist/models.d.mts +82 -101
  19. package/dist/models.mjs +1 -0
  20. package/dist/mora.full.mjs +659 -412
  21. package/dist/value/array.d.mts +5 -5
  22. package/dist/value/array.mjs +70 -109
  23. package/dist/value/computed.d.mts +5 -4
  24. package/dist/value/computed.mjs +45 -31
  25. package/dist/value/readonly.d.mts +4 -6
  26. package/dist/value/readonly.mjs +34 -31
  27. package/dist/value/signal.d.mts +5 -5
  28. package/dist/value/signal.mjs +28 -34
  29. package/dist/value/store.d.mts +5 -5
  30. package/dist/value/store.mjs +25 -83
  31. package/package.json +6 -6
  32. package/src/batch.ts +15 -5
  33. package/src/constants.ts +36 -2
  34. package/src/effect.ts +20 -11
  35. package/src/helpers/is.ts +16 -6
  36. package/src/helpers/misc.ts +15 -0
  37. package/src/helpers/proxy.ts +151 -74
  38. package/src/helpers/subscription.ts +89 -0
  39. package/src/helpers/value.ts +121 -30
  40. package/src/index.ts +1 -1
  41. package/src/models.ts +81 -98
  42. package/src/value/array.ts +116 -226
  43. package/src/value/computed.ts +96 -43
  44. package/src/value/readonly.ts +68 -54
  45. package/src/value/signal.ts +54 -46
  46. package/src/value/store.ts +42 -168
  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/dist/value/reactive.d.mts +0 -5
  56. package/dist/value/reactive.mjs +0 -16
  57. package/src/subscription.ts +0 -45
  58. package/src/value/reactive.ts +0 -24
@@ -3,7 +3,7 @@ const ACTIVE = {};
3
3
  const BATCH = {
4
4
  depth: 0,
5
5
  flushing: false,
6
- handlers: /* @__PURE__ */ new Set()
6
+ handlers: /* @__PURE__ */ new Map()
7
7
  };
8
8
  const METHODS_AFFECTING_LENGTH = /* @__PURE__ */ new Set([
9
9
  "pop",
@@ -26,6 +26,7 @@ const NAME_MORA = "$mora";
26
26
  const NAME_READONLY = "readonly";
27
27
  const NAME_SIGNAL = "signal";
28
28
  const NAME_STORE = "store";
29
+ const NAME_SUBSCRIPTION = "subscription";
29
30
  const NAME_ALL = /* @__PURE__ */ new Set([
30
31
  NAME_ARRAY,
31
32
  NAME_COMPUTED,
@@ -33,8 +34,30 @@ const NAME_ALL = /* @__PURE__ */ new Set([
33
34
  NAME_SIGNAL,
34
35
  NAME_STORE
35
36
  ]);
37
+ const PROPERTY_LENGTH = "length";
38
+ const SYMBOL_EFFECT = Symbol("effect");
39
+ const SYMBOL_STATE = Symbol("state");
40
+ const SUBSCRIPTION_PROPERTY$1 = {
41
+ key: NAME_MORA,
42
+ value: NAME_SUBSCRIPTION
43
+ };
44
+ const SUBSCRIPTION_TYPE_COPY = "copy";
45
+ const SUBSCRIPTION_TYPE_FROZEN = "frozen";
46
+ const SUBSCRIPTION_TYPE_ORIGINAL = "original";
47
+ const SUBSCRIPTION_TYPE_READONLY = "readonly";
48
+ const SUBSCRIPTION_TYPES_COPY = /* @__PURE__ */ new Set([SUBSCRIPTION_TYPE_COPY, SUBSCRIPTION_TYPE_READONLY]);
49
+ const SUBSCRIPTION_TYPES = /* @__PURE__ */ new Set([
50
+ ...SUBSCRIPTION_TYPES_COPY,
51
+ SUBSCRIPTION_TYPE_FROZEN,
52
+ SUBSCRIPTION_TYPE_ORIGINAL
53
+ ]);
36
54
  //#endregion
37
55
  //#region src/effect.ts
56
+ function Effect(callback) {
57
+ this[SYMBOL_STATE] = { callback };
58
+ runEffect(this[SYMBOL_STATE]);
59
+ }
60
+ Effect.prototype[NAME_MORA] = NAME_EFFECT;
38
61
  /**
39
62
  * Create an effect
40
63
  *
@@ -46,10 +69,8 @@ function effect(callback) {
46
69
  return getEffect(callback)[0];
47
70
  }
48
71
  function getEffect(callback) {
49
- const state = { callback };
50
- const instance = Object.freeze({ $mora: NAME_EFFECT });
51
- runEffect(state);
52
- return [instance, state];
72
+ const instance = new Effect(callback);
73
+ return [instance, instance[SYMBOL_STATE]];
53
74
  }
54
75
  function internalEffect(callback) {
55
76
  return getEffect(callback)[1];
@@ -64,6 +85,111 @@ function runEffect(state) {
64
85
  }
65
86
  }
66
87
  //#endregion
88
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/is.mjs
89
+ /**
90
+ * Is the value a _Key_?
91
+ *
92
+ * @param value Value to check
93
+ * @returns `true` if the value is a _Key_ _(`number` or `string`)_, otherwise `false`
94
+ */
95
+ function isKey(value) {
96
+ return typeof value === "number" || typeof value === "string";
97
+ }
98
+ /**
99
+ * Is the value a plain object?
100
+ *
101
+ * @param value Value to check
102
+ * @returns `true` if the value is a plain object, otherwise `false`
103
+ */
104
+ function isPlainObject(value) {
105
+ if (value === null || typeof value !== "object") return false;
106
+ if (Symbol.toStringTag in value || Symbol.iterator in value) return false;
107
+ const prototype = Object.getPrototypeOf(value);
108
+ return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
109
+ }
110
+ //#endregion
111
+ //#region src/helpers/value.ts
112
+ function emitValue(instance) {
113
+ const state = instance[SYMBOL_STATE];
114
+ if (state.computeds != null && state.computeds.size > 0) for (const computed of state.computeds) computed.dirty = true;
115
+ if (state.effects != null && state.effects.size > 0) for (const effect of state.effects) BATCH.handlers.set(effect, effect);
116
+ for (const type of SUBSCRIPTION_TYPES) {
117
+ const subscriptions = state.subscriptions?.values.to.keyed?.get(type);
118
+ if (subscriptions != null && subscriptions.size > 0) for (const [subscription, callback] of subscriptions) BATCH.handlers.set(subscription, {
119
+ callback,
120
+ instance,
121
+ state,
122
+ frozen: type === SUBSCRIPTION_TYPE_FROZEN,
123
+ copy: SUBSCRIPTION_TYPES_COPY.has(type)
124
+ });
125
+ }
126
+ if (BATCH.depth === 0) flushHandlers();
127
+ }
128
+ function equalArrays(state, first, second) {
129
+ const { length } = first;
130
+ if (length !== second.length) return false;
131
+ const eq = state.equal ?? Object.is;
132
+ let offset = 0;
133
+ if (length >= 100) {
134
+ offset = Math.round(length / 10);
135
+ offset = offset > 25 ? 25 : offset;
136
+ for (let index = 0; index < offset; index += 1) if (!(eq(first[index], second[index]) && eq(first[length - index - 1], second[length - index - 1]))) return false;
137
+ }
138
+ const end = length - offset;
139
+ for (let index = offset; index < end; index += 1) if (!eq(first[index], second[index])) return false;
140
+ return true;
141
+ }
142
+ function getFrozenValue(value) {
143
+ let frozen = value;
144
+ if (Array.isArray(frozen)) frozen = Object.freeze(frozen.slice());
145
+ else if (isPlainObject(frozen)) frozen = Object.freeze({ ...frozen });
146
+ return frozen;
147
+ }
148
+ function getSignalValue() {
149
+ if (ACTIVE.computed != null) {
150
+ this[SYMBOL_STATE].computeds ??= /* @__PURE__ */ new Set();
151
+ this[SYMBOL_STATE].computeds.add(ACTIVE.computed);
152
+ }
153
+ if (ACTIVE.effect != null) {
154
+ this[SYMBOL_STATE].effects ??= /* @__PURE__ */ new Set();
155
+ this[SYMBOL_STATE].effects.add(ACTIVE.effect);
156
+ }
157
+ return this[SYMBOL_STATE].value;
158
+ }
159
+ function getStringValue(json) {
160
+ return json === true ? JSON.stringify(this[SYMBOL_STATE].value) : String(this[SYMBOL_STATE].value);
161
+ }
162
+ function handleSignalValue(instance, origin, setValue, onAfter) {
163
+ const state = instance[SYMBOL_STATE];
164
+ try {
165
+ let actual = typeof origin === "function" ? origin() : origin;
166
+ if (actual instanceof Promise) {
167
+ state.promise = actual;
168
+ actual.then((value) => {
169
+ if (actual === state.promise) {
170
+ state.promise = void 0;
171
+ setValue(instance, value);
172
+ }
173
+ }).catch(() => {
174
+ if (actual === state.promise) state.promise = void 0;
175
+ });
176
+ } else setValue(instance, actual);
177
+ } catch {} finally {
178
+ onAfter?.();
179
+ }
180
+ }
181
+ function peekSignalValue(copy) {
182
+ let peeked = Array.isArray(this) ? this[1] : this[SYMBOL_STATE].value;
183
+ if (copy !== true) return peeked;
184
+ if (Array.isArray(peeked)) peeked = peeked.slice();
185
+ else if (isPlainObject(peeked)) peeked = { ...peeked };
186
+ return peeked;
187
+ }
188
+ function updateSignalValue(instance, callback, setValue) {
189
+ if (typeof callback !== "function") throw new TypeError("Callback must be a function");
190
+ handleSignalValue(instance, callback(instance[SYMBOL_STATE].value), setValue);
191
+ }
192
+ //#endregion
67
193
  //#region src/batch.ts
68
194
  function flushHandlers() {
69
195
  if (BATCH.flushing) return;
@@ -74,8 +200,9 @@ function flushHandlers() {
74
200
  const { length } = handlers;
75
201
  BATCH.handlers.clear();
76
202
  for (let index = 0; index < length; index += 1) {
77
- const handler = handlers[index];
78
- if (typeof handler.destroy === "function") handler.callback(handler.state.value);
203
+ const [, handler] = handlers[index];
204
+ const subscription = handler;
205
+ if (typeof subscription.frozen === "boolean") subscription.callback(subscription.frozen ? getFrozenValue(subscription.state.value) : peekSignalValue.call(subscription.instance, subscription.copy));
79
206
  else runEffect(handler);
80
207
  }
81
208
  }
@@ -157,6 +284,12 @@ function isReactiveArray(value) {
157
284
  function isReactiveStore(value) {
158
285
  return isMora(value, NAME_STORE);
159
286
  }
287
+ /**
288
+ * Is the value a readonly signal?
289
+ *
290
+ * @param value Value to check
291
+ * @returns True if value is a {@link ReadonlySignal}
292
+ */
160
293
  function isReadonlySignal(value) {
161
294
  return isMora(value, NAME_READONLY);
162
295
  }
@@ -167,6 +300,7 @@ function getArrayCallback(value) {
167
300
  case "function": return value;
168
301
  case "number":
169
302
  case "string": return typeof value === "string" && value.includes(".") ? void 0 : (obj) => obj[value];
303
+ default: return;
170
304
  }
171
305
  }
172
306
  function getArrayCallbacks(bool, key, value) {
@@ -178,10 +312,18 @@ function getArrayCallbacks(bool, key, value) {
178
312
  }
179
313
  //#endregion
180
314
  //#region node_modules/@oscarpalmer/atoms/dist/internal/array/find.mjs
315
+ function createFindParameters(original) {
316
+ const { length } = original;
317
+ return {
318
+ bool: length === 1 && typeof original[0] === "function" ? original[0] : void 0,
319
+ key: length === 2 ? original[0] : void 0,
320
+ value: length === 1 && typeof original[0] !== "function" ? original[0] : original[1]
321
+ };
322
+ }
181
323
  function findValue(type, array, parameters, reversed) {
182
324
  const findIndex = type === FIND_VALUE_INDEX;
183
325
  if (!Array.isArray(array) || array.length === 0) return findIndex ? -1 : void 0;
184
- const { bool, key, value } = getFindParameters(parameters);
326
+ const { bool, key, value } = createFindParameters(parameters);
185
327
  const callbacks = getArrayCallbacks(bool, key);
186
328
  if (callbacks?.bool == null && callbacks?.keyed == null) {
187
329
  if (findIndex) return reversed ? array.lastIndexOf(value) : array.indexOf(value);
@@ -208,18 +350,22 @@ function findValues(type, array, parameters, mapper) {
208
350
  };
209
351
  if (!Array.isArray(array) || array.length === 0) return result;
210
352
  const { length } = array;
211
- const { bool, key, value } = getFindParameters(parameters);
353
+ const { bool, key, value } = createFindParameters(parameters);
212
354
  const callbacks = getArrayCallbacks(bool, key);
213
- if (type === "unique" && callbacks?.keyed == null && length >= UNIQUE_THRESHOLD) {
355
+ if (type === "unique" && callbacks?.keyed == null && length >= FIND_UNIQUE_THRESHOLD) {
214
356
  result.matched = [...new Set(array)];
215
357
  return result;
216
358
  }
217
- const mapCallback = getArrayCallback(mapper);
359
+ const mapCallback = getArrayCallback(mapper?.callback);
360
+ const mapReverse = mapper?.reverse ?? false;
361
+ const mapAfter = mapCallback == null ? void 0 : mapReverse ? void 0 : mapCallback;
362
+ const mapBefore = mapCallback == null ? void 0 : mapReverse ? mapCallback : void 0;
218
363
  if (callbacks?.bool != null || type === "all" && key == null) {
219
364
  const callback = callbacks?.bool ?? ((item) => Object.is(item, value));
220
365
  for (let index = 0; index < length; index += 1) {
221
366
  const item = array[index];
222
- if (callback(item, index, array)) result.matched.push(mapCallback?.(item, index, array) ?? item);
367
+ const transformed = mapBefore?.(item, index, array) ?? item;
368
+ if (callback(transformed, index, array)) result.matched.push(mapAfter?.(item, index, array) ?? transformed);
223
369
  else result.notMatched.push(item);
224
370
  }
225
371
  return result;
@@ -227,71 +373,64 @@ function findValues(type, array, parameters, mapper) {
227
373
  const keys = /* @__PURE__ */ new Set();
228
374
  for (let index = 0; index < length; index += 1) {
229
375
  const item = array[index];
230
- const keyed = callbacks?.keyed?.(item, index, array) ?? item;
376
+ let keyed;
377
+ let transformed;
378
+ if (mapBefore == null) {
379
+ keyed = callbacks?.keyed?.(item, index, array) ?? item;
380
+ transformed = item;
381
+ } else {
382
+ transformed = mapBefore(item, index, array);
383
+ keyed = callbacks?.keyed?.(transformed, index, array) ?? transformed;
384
+ }
231
385
  if (type === "all" && Object.is(keyed, value) || type === "unique" && !keys.has(keyed)) {
232
386
  keys.add(keyed);
233
- result.matched.push(mapCallback?.(item, index, array) ?? item);
387
+ result.matched.push(mapAfter?.(item, index, array) ?? transformed);
234
388
  } else result.notMatched.push(item);
235
389
  }
236
390
  return result;
237
391
  }
238
- function getFindParameters(original) {
239
- const { length } = original;
240
- return {
241
- bool: length === 1 && typeof original[0] === "function" ? original[0] : void 0,
242
- key: length === 2 ? original[0] : void 0,
243
- value: length === 1 && typeof original[0] !== "function" ? original[0] : original[1]
244
- };
245
- }
246
392
  const FIND_VALUE_INDEX = "index";
247
393
  const FIND_VALUE_ITEM = "item";
248
- const UNIQUE_THRESHOLD = 100;
394
+ const FIND_UNIQUE_THRESHOLD = 100;
249
395
  //#endregion
250
396
  //#region node_modules/@oscarpalmer/atoms/dist/internal/array/index-of.mjs
251
397
  function indexOf(array, ...parameters) {
252
398
  return findValue(FIND_VALUE_INDEX, array, parameters, false);
253
399
  }
254
- indexOf.last = lastIndexOf;
255
400
  function lastIndexOf(array, ...parameters) {
256
401
  return findValue(FIND_VALUE_INDEX, array, parameters, true);
257
402
  }
258
- //#endregion
259
- //#region node_modules/@oscarpalmer/atoms/dist/internal/is.mjs
260
- /**
261
- * Is the value a _Key_?
262
- *
263
- * @param value Value to check
264
- * @returns `true` if the value is a _Key_ _(`number` or `string`)_, otherwise `false`
265
- */
266
- function isKey(value) {
267
- return typeof value === "number" || typeof value === "string";
268
- }
269
- /**
270
- * Is the value a plain object?
271
- *
272
- * @param value Value to check
273
- * @returns `true` if the value is a plain object, otherwise `false`
274
- */
275
- function isPlainObject(value) {
276
- if (value === null || typeof value !== "object") return false;
277
- if (Symbol.toStringTag in value || Symbol.iterator in value) return false;
278
- const prototype = Object.getPrototypeOf(value);
279
- return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
280
- }
403
+ indexOf.last = lastIndexOf;
404
+ Object.defineProperty(indexOf, "last", { value: lastIndexOf });
281
405
  //#endregion
282
406
  //#region node_modules/@oscarpalmer/atoms/dist/array/find.mjs
283
407
  function find(array, ...parameters) {
284
408
  return findValue(FIND_VALUE_ITEM, array, parameters, false);
285
409
  }
286
- find.last = findLast;
287
410
  function findLast(array, ...parameters) {
288
411
  return findValue(FIND_VALUE_ITEM, array, parameters, true);
289
412
  }
413
+ find.last = findLast;
414
+ Object.defineProperty(find, "last", { value: findLast });
290
415
  //#endregion
291
416
  //#region node_modules/@oscarpalmer/atoms/dist/array/select.mjs
417
+ function reverseSelect(array, ...parameters) {
418
+ return findValues("all", array, parameters, {
419
+ callback: parameters.shift(),
420
+ reverse: true
421
+ }).matched;
422
+ }
292
423
  function select(array, ...parameters) {
293
- return findValues("all", array, parameters, parameters.pop()).matched;
424
+ return selectValues(array, parameters);
425
+ }
426
+ function selectValues(array, parameters) {
427
+ return findValues("all", array, parameters, {
428
+ callback: parameters.pop(),
429
+ reverse: false
430
+ }).matched;
294
431
  }
432
+ select.reverse = reverseSelect;
433
+ Object.defineProperty(select, "reverse", { value: reverseSelect });
295
434
  //#endregion
296
435
  //#region node_modules/@oscarpalmer/atoms/dist/array/filter.mjs
297
436
  function exclude(array, ...parameters) {
@@ -301,99 +440,247 @@ function filter(array, ...parameters) {
301
440
  return findValues("all", array, parameters).matched;
302
441
  }
303
442
  filter.remove = exclude;
443
+ Object.defineProperty(filter, "remove", { value: exclude });
304
444
  //#endregion
305
- //#region node_modules/@oscarpalmer/atoms/dist/internal/function/misc.mjs
306
- /**
307
- * A function that does nothing, which can be useful, I guess…
308
- */
309
- function noop$1() {}
445
+ //#region src/helpers/misc.ts
446
+ function getState(value, options) {
447
+ return {
448
+ value,
449
+ equal: typeof options === "object" && typeof options?.equal === "function" ? options.equal : void 0
450
+ };
451
+ }
310
452
  //#endregion
311
- //#region src/helpers/value.ts
312
- function emitValue(state) {
313
- for (const computed of state.computeds) computed.dirty = true;
314
- for (const effect of state.effects) BATCH.handlers.add(effect);
315
- for (const [, subscription] of state.subscriptions) BATCH.handlers.add(subscription);
316
- if (BATCH.depth === 0) flushHandlers();
453
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/abort.mjs
454
+ function createAborter(value, onAbort) {
455
+ if (!(value instanceof AbortSignal)) return;
456
+ value.addEventListener(ABORT_EVENT, onAbort, ABORT_OPTIONS);
457
+ return {
458
+ callback: onAbort,
459
+ signal: value,
460
+ cancel: () => value.removeEventListener(ABORT_EVENT, onAbort)
461
+ };
317
462
  }
318
- function equalArrays(state, first, second) {
319
- let { length } = first;
320
- if (length !== second.length) return false;
321
- let offset = 0;
322
- if (length >= 100) {
323
- offset = Math.round(length / 10);
324
- offset = offset > 25 ? 25 : offset;
325
- for (let index = 0; index < offset; index += 1) if (!state.equal(first[index], second[index])) return false;
463
+ const ABORT_EVENT = "abort";
464
+ const ABORT_OPTIONS = { once: true };
465
+ //#endregion
466
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/subscription.mjs
467
+ function addSubscription(subscriptions, subscription, state) {
468
+ const { items, values } = subscriptions;
469
+ const { key, value } = state.parameters;
470
+ if (!isKey(key)) {
471
+ items.any.add(subscription);
472
+ values.from.any.set(value, subscription);
473
+ values.to.any.set(subscription, value);
474
+ return;
326
475
  }
327
- length -= offset;
328
- for (let index = offset; index < length; index += 1) if (!state.equal(first[index], second[index])) return false;
329
- return true;
476
+ /* istanbul ignore if */
477
+ if (items.keyed == null || values.from.keyed == null || values.to.keyed == null)
478
+ // istanbul ignore next
479
+ return;
480
+ let keyedItems = items.keyed.get(key);
481
+ if (keyedItems == null) {
482
+ keyedItems = /* @__PURE__ */ new Set();
483
+ items.keyed.set(key, keyedItems);
484
+ }
485
+ keyedItems.add(subscription);
486
+ let keyedFrom = values.from.keyed.get(key);
487
+ if (keyedFrom == null) {
488
+ keyedFrom = /* @__PURE__ */ new Map();
489
+ values.from.keyed.set(key, keyedFrom);
490
+ }
491
+ keyedFrom.set(value, subscription);
492
+ let keyedTo = values.to.keyed.get(key);
493
+ if (keyedTo == null) {
494
+ keyedTo = /* @__PURE__ */ new Map();
495
+ values.to.keyed.set(key, keyedTo);
496
+ }
497
+ keyedTo.set(subscription, value);
330
498
  }
331
- function getSimpleValue(state) {
332
- if (ACTIVE.computed != null) state.computeds.add(ACTIVE.computed);
333
- if (ACTIVE.effect != null) state.effects.add(ACTIVE.effect);
334
- return state.value;
499
+ function clearSubscriptions(store) {
500
+ for (const susbcription of store.values.to.any.keys()) susbcription.unsubscribe();
501
+ if (store.values.to.keyed != null) for (const values of store.values.to.keyed.values()) for (const susbcription of values.keys()) susbcription.unsubscribe();
335
502
  }
336
- function handleSimpleValue(state, origin, setValue, onAfter) {
337
- try {
338
- let actual = typeof origin === "function" ? origin() : origin;
339
- if (actual instanceof Promise) {
340
- state.promise = actual;
341
- actual.then((value) => {
342
- if (actual === state.promise) {
343
- state.promise = void 0;
344
- setValue(state, value);
345
- }
346
- }).catch(() => {
347
- if (actual === state.promise) state.promise = void 0;
348
- });
349
- } else setValue(state, actual);
350
- } catch {} finally {
351
- onAfter?.();
503
+ function createSubscription(subscriptions, property, params) {
504
+ const parameters = createSubscriptionParameters(params);
505
+ if (parameters.signal?.aborted ?? false) throw new Error(parameters.signal?.reason);
506
+ const state = {
507
+ parameters,
508
+ active: true
509
+ };
510
+ const existing = getExistingSubscription(subscriptions, state);
511
+ if (existing != null) return [existing, true];
512
+ if (subscriptions.keys != null && isKey(parameters.key)) {
513
+ if (subscriptions.keys === false) throw new Error(SUBSCRIPTION_DISALLOWED_KEY);
514
+ else if (subscriptions.keys !== true && !subscriptions.keys.has(parameters.key)) throw new Error(SUBSCRIPTION_INVALID_KEY);
352
515
  }
516
+ state.aborter = createAborter(parameters.signal, () => unsubscribe(subscriptions, instance, state));
517
+ const instance = { unsubscribe: () => unsubscribe(subscriptions, instance, state) };
518
+ Object.defineProperties(instance, {
519
+ [SUBSCRIPTION_PROPERTY]: { value: SUBSCRIPTION_NAME },
520
+ [property.key]: { value: property.value },
521
+ active: {
522
+ enumerable: true,
523
+ get: () => (parameters.isActive?.() ?? true) && state.active
524
+ }
525
+ });
526
+ addSubscription(subscriptions, instance, state);
527
+ return [Object.freeze(instance), false];
353
528
  }
354
- //#endregion
355
- //#region src/subscription.ts
356
- function noop() {}
357
- function subscribe(state, callback) {
358
- if (typeof callback !== "function" || state.subscriptions.has(callback)) return noop;
359
- state.subscriptions.set(callback, subscription(state, callback));
360
- return () => {
361
- unsubscribe(state, callback);
529
+ function getExistingSubscription(subscriptions, state) {
530
+ const { values } = subscriptions;
531
+ const { parameters } = state;
532
+ return isKey(parameters.key) ? values.from.keyed?.get(parameters.key)?.get(parameters.value) : values.from.any.get(parameters.value);
533
+ }
534
+ function createSubscriptionParameters(input) {
535
+ const values = isPlainObject(input) ? input : {};
536
+ if (values.value == null) throw new Error(SUBSCRIPTION_INVALID_VALUE);
537
+ return {
538
+ isActive: typeof values.isActive === "function" ? values.isActive : void 0,
539
+ key: isKey(values.key) ? values.key : void 0,
540
+ signal: values.signal instanceof AbortSignal ? values.signal : void 0,
541
+ value: values.value
362
542
  };
363
543
  }
364
- function subscription(state, callback) {
365
- const instance = {
366
- callback,
367
- state,
368
- destroy: () => {
369
- instance.callback = noop;
370
- instance.state = void 0;
544
+ function createSubscriptionsParameters(input) {
545
+ const values = isPlainObject(input) ? input : {};
546
+ let keys;
547
+ if (values.keys instanceof Set) keys = values.keys;
548
+ else keys = typeof values.keys === "boolean" ? values.keys : false;
549
+ return {
550
+ keys,
551
+ property: createSubscriptionsProperty(values.property)
552
+ };
553
+ }
554
+ function createSubscriptionsProperty(input) {
555
+ const values = isPlainObject(input) ? input : {};
556
+ return {
557
+ key: typeof values.key === "string" ? values.key : SUBSCRIPTION_PROPERTY,
558
+ value: values.value == null ? SUBSCRIPTION_NAME : values.value
559
+ };
560
+ }
561
+ function createSubscriptionsState(keys) {
562
+ return {
563
+ keys,
564
+ items: {
565
+ any: /* @__PURE__ */ new Set(),
566
+ keyed: keys === false ? void 0 : /* @__PURE__ */ new Map()
567
+ },
568
+ values: {
569
+ from: {
570
+ any: /* @__PURE__ */ new Map(),
571
+ keyed: keys === false ? void 0 : /* @__PURE__ */ new Map()
572
+ },
573
+ to: {
574
+ any: /* @__PURE__ */ new Map(),
575
+ keyed: keys === false ? void 0 : /* @__PURE__ */ new Map()
576
+ }
371
577
  }
372
578
  };
373
- callback(state.value);
374
- return instance;
375
579
  }
376
- function unsubscribe(state, callback) {
377
- state.subscriptions.get(callback)?.destroy();
378
- state.subscriptions.delete(callback);
580
+ function removeFromStore(items, values, subscription, value, key) {
581
+ items.delete(subscription);
582
+ if (key == null) {
583
+ values.from.any.delete(value);
584
+ values.to.any.delete(subscription);
585
+ } else {
586
+ values.from.keyed?.get(key)?.delete(value);
587
+ values.to.keyed?.get(key)?.delete(subscription);
588
+ }
379
589
  }
380
- //#endregion
381
- //#region src/value/reactive.ts
382
- function reactive(value, options) {
383
- const state = {
384
- computeds: /* @__PURE__ */ new Set(),
385
- effects: /* @__PURE__ */ new Set(),
386
- equal: typeof options === "object" && typeof options?.equal === "function" ? options.equal : Object.is,
387
- subscriptions: /* @__PURE__ */ new Map(),
388
- value
590
+ function removeSubscription(subscriptionsState, subscription, state) {
591
+ if (!state.active) return;
592
+ state.aborter = void 0;
593
+ state.active = false;
594
+ state.parameters.isActive = void 0;
595
+ state.parameters.signal = void 0;
596
+ const { items, values } = subscriptionsState;
597
+ const { key, value } = state.parameters;
598
+ if (!isKey(key)) {
599
+ removeFromStore(items.any, values, subscription, value);
600
+ return;
601
+ }
602
+ const keyed = items.keyed?.get(key);
603
+ /* istanbul ignore if */
604
+ if (items.keyed == null || keyed == null)
605
+ // istanbul ignore next
606
+ return;
607
+ removeFromStore(keyed, values, subscription, value, key);
608
+ if (keyed.size === 0) items.keyed.delete(key);
609
+ }
610
+ /**
611
+ * Create a subscription store
612
+ *
613
+ * @param parameters Store parameters
614
+ * @returns Subscription store
615
+ */
616
+ function subscriptions(parameters) {
617
+ const { keys, property } = createSubscriptionsParameters(parameters);
618
+ const state = createSubscriptionsState(keys);
619
+ const instance = {
620
+ clear: () => clearSubscriptions(state),
621
+ create: (parameters) => createSubscription(state, property, parameters)
389
622
  };
390
- return [{
391
- toJSON: () => state.value,
392
- toString: () => String(state.value)
393
- }, state];
623
+ Object.defineProperties(instance, {
624
+ [SUBSCRIPTION_PROPERTY]: { value: SUBSCRIPTION_STORE },
625
+ items: {
626
+ enumerable: true,
627
+ value: state.items
628
+ },
629
+ values: {
630
+ enumerable: true,
631
+ value: state.values
632
+ }
633
+ });
634
+ return Object.freeze(instance);
635
+ }
636
+ function unsubscribe(subscriptionsState, subscription, state) {
637
+ state.aborter?.cancel();
638
+ removeSubscription(subscriptionsState, subscription, state);
639
+ }
640
+ const SUBSCRIPTION_DISALLOWED_KEY = "Disallowed key for subscription";
641
+ const SUBSCRIPTION_INVALID_KEY = "Invalid key for subscription";
642
+ const SUBSCRIPTION_INVALID_VALUE = "A subscription requires a non-null value to identify it";
643
+ const SUBSCRIPTION_NAME = "subscription";
644
+ const SUBSCRIPTION_PROPERTY = "$subscriptions";
645
+ const SUBSCRIPTION_STORE = "subscriptions";
646
+ //#endregion
647
+ //#region src/helpers/subscription.ts
648
+ function subscribeToProxy(first, second, third) {
649
+ if (isKey(first)) return getReactiveValueInProxy(this, first).subscribe(second, third);
650
+ return subscribeToSignal.call(this, first, second);
651
+ }
652
+ function subscribeToReactive(type, subscriber) {
653
+ this[SYMBOL_STATE].subscriptions ??= subscriptions({
654
+ keys: SUBSCRIPTION_TYPES,
655
+ property: SUBSCRIPTION_PROPERTY$1
656
+ });
657
+ const [subscription, existing] = this[SYMBOL_STATE].subscriptions.create({
658
+ key: type,
659
+ value: subscriber
660
+ });
661
+ if (!existing) subscriber(type === "frozen" ? getFrozenValue(this[SYMBOL_STATE].value) : peekSignalValue.call(this, SUBSCRIPTION_TYPES_COPY.has(type)), subscription);
662
+ return subscription;
663
+ }
664
+ function subscribeToReadonly(subscriber) {
665
+ return subscribeToReactive.call(this, this.frozen ? SUBSCRIPTION_TYPE_FROZEN : SUBSCRIPTION_TYPE_READONLY, subscriber);
666
+ }
667
+ function subscribeToSignal(subscriber, copy) {
668
+ return subscribeToReactive.call(this, copy === true ? SUBSCRIPTION_TYPE_COPY : SUBSCRIPTION_TYPE_ORIGINAL, subscriber);
394
669
  }
395
670
  //#endregion
396
671
  //#region src/value/computed.ts
672
+ function Computed(callback, options) {
673
+ this[SYMBOL_STATE] = getState(void 0, options);
674
+ this[SYMBOL_EFFECT] = getComputedEffect(this, callback);
675
+ }
676
+ Computed.prototype[NAME_MORA] = NAME_COMPUTED;
677
+ Computed.prototype.get = getComputedValue;
678
+ Computed.prototype.peek = peekSignalValue;
679
+ Computed.prototype.subscribe = subscribeToSignal;
680
+ Computed.prototype.toString = getStringValue;
681
+ Computed.prototype.toJSON = function() {
682
+ return this[SYMBOL_STATE].value;
683
+ };
397
684
  /**
398
685
  * Create a computed value
399
686
  *
@@ -405,25 +692,11 @@ function computed(callback, options) {
405
692
  return getComputed(callback, options)[0];
406
693
  }
407
694
  function getComputed(callback, options) {
408
- const [rx, state] = reactive(void 0, options);
409
- let fx;
410
- const instance = {
411
- ...rx,
412
- get: () => getValue(state, fx),
413
- peek: () => state.value,
414
- subscribe: (callback) => subscribe(state, callback),
415
- unsubscribe: (callback) => {
416
- state.subscriptions.delete(callback);
417
- }
418
- };
419
- Object.defineProperty(instance, NAME_MORA, {
420
- enumerable: false,
421
- value: NAME_COMPUTED
422
- });
423
- fx = getComputedEffect(state, callback);
424
- return [Object.freeze(instance), fx];
695
+ if (typeof callback !== "function") throw new TypeError("Computed callback must be a function");
696
+ const instance = new Computed(callback, options);
697
+ return [instance, instance[SYMBOL_EFFECT]];
425
698
  }
426
- function getComputedEffect(state, callback) {
699
+ function getComputedEffect(instance, callback) {
427
700
  const fx = {
428
701
  dirty: true,
429
702
  instance: void 0
@@ -432,7 +705,7 @@ function getComputedEffect(state, callback) {
432
705
  if (fx.dirty) {
433
706
  const previousComputed = ACTIVE.computed;
434
707
  ACTIVE.computed = fx;
435
- handleSimpleValue(state, callback, setAndEmit$1, () => {
708
+ handleSignalValue(instance, callback, setAndEmit$1, () => {
436
709
  ACTIVE.computed = previousComputed;
437
710
  });
438
711
  fx.dirty = false;
@@ -440,50 +713,116 @@ function getComputedEffect(state, callback) {
440
713
  });
441
714
  return fx;
442
715
  }
443
- function getValue(state, fx) {
444
- if (ACTIVE.computed != null && fx !== ACTIVE.computed) state.computeds.add(ACTIVE.computed);
445
- if (ACTIVE.effect != null && ACTIVE.effect !== fx.instance) state.effects.add(ACTIVE.effect);
716
+ function getComputedValue() {
717
+ const fx = this[SYMBOL_EFFECT];
718
+ const state = this[SYMBOL_STATE];
719
+ if (ACTIVE.computed != null && fx !== ACTIVE.computed) {
720
+ state.computeds ??= /* @__PURE__ */ new Set();
721
+ state.computeds.add(ACTIVE.computed);
722
+ }
723
+ if (ACTIVE.effect != null && ACTIVE.effect !== fx.instance) {
724
+ state.effects ??= /* @__PURE__ */ new Set();
725
+ state.effects.add(ACTIVE.effect);
726
+ }
446
727
  if (fx.dirty && BATCH.depth === 0) runEffect(fx.instance);
447
728
  return state.value;
448
729
  }
449
730
  function internalComputed(callback, options) {
450
731
  return getComputed(callback, options);
451
732
  }
452
- function setAndEmit$1(state, value) {
453
- if (state.equal(state.value, value)) return;
733
+ function setAndEmit$1(instance, value) {
734
+ const state = instance[SYMBOL_STATE];
735
+ if ((state.equal ?? Object.is)(state.value, value)) return;
454
736
  state.value = value;
455
- for (const computed of state.computeds) computed.dirty = true;
456
- for (const effect of state.effects) BATCH.handlers.add(effect);
457
- for (const [, subscription] of state.subscriptions) subscription.callback(value);
737
+ if (state.computeds != null && state.computeds.size > 0) for (const computed of state.computeds) computed.dirty = true;
738
+ if (state.effects != null && state.effects.size > 0) for (const effect of state.effects) BATCH.handlers.set(effect, effect);
739
+ for (const type of SUBSCRIPTION_TYPES) {
740
+ if (type === "frozen") continue;
741
+ const subscriptions = state.subscriptions?.values.to.keyed?.get(type);
742
+ if (subscriptions != null && subscriptions.size > 0) {
743
+ const copy = SUBSCRIPTION_TYPES_COPY.has(type);
744
+ for (const [, callback] of subscriptions) callback(peekSignalValue.call(instance, copy));
745
+ }
746
+ }
458
747
  flushHandlers();
459
748
  }
460
749
  //#endregion
461
750
  //#region src/helpers/proxy.ts
462
- function emityProxyValues(state, mapped) {
463
- const values = [...mapped.values()];
751
+ function emitProxyValues() {
752
+ const state = this[SYMBOL_STATE];
753
+ state.mapped ??= /* @__PURE__ */ new Map();
754
+ const values = [...state.mapped.values()];
464
755
  const { length } = values;
465
756
  for (let index = 0; index < length; index += 1) values[index][1].dirty = true;
466
- emitValue(state);
757
+ emitValue(this);
467
758
  }
468
- function getReactiveValueInProxy(reactive, mapped, key, isArray) {
469
- let item = mapped.get(key);
759
+ function getReactiveValueInProxy(instance, key) {
760
+ const state = instance[SYMBOL_STATE];
761
+ state.mapped ??= /* @__PURE__ */ new Map();
762
+ const mapKey = String(key);
763
+ let item = state.mapped.get(mapKey);
470
764
  if (item == null) {
471
- item = internalComputed(() => isArray ? reactive.get().at(key) : reactive.get()[key]);
472
- mapped.set(key, item);
765
+ item = internalComputed(() => state.isArray ? instance.get().at(key) : instance.get()[key]);
766
+ state.mapped.set(mapKey, item);
473
767
  }
474
768
  return item[0];
475
769
  }
476
- function setProxyValue(array, state, isObject, isProperty, setObject, setProperty, first, second) {
477
- if (array && first === "length") {
770
+ function getValueInProxy(first) {
771
+ if (this[SYMBOL_STATE].isArray ? typeof first === "number" : isKey(first)) return getReactiveValueInProxy(this, first).get();
772
+ return getSignalValue.call(this);
773
+ }
774
+ function isProxyObject(isArray, value) {
775
+ return value == null || (isArray ? Array.isArray(value) : isPlainObject(value));
776
+ }
777
+ function peekValueInProxy(first, second) {
778
+ const state = this[SYMBOL_STATE];
779
+ let value;
780
+ if (state.isArray ? typeof first === "number" : isKey(first)) value = state.isArray ? state.value.at(first) : state.value[first];
781
+ else value = state.value;
782
+ return peekSignalValue.call([this, value], first === true || second === true);
783
+ }
784
+ function setProxyObject(state, value) {
785
+ if (state.isArray) {
786
+ state.value.splice(0, state.value.length, ...value ?? []);
787
+ return;
788
+ }
789
+ startBatch();
790
+ const actual = value ?? {};
791
+ const proxy = state.value;
792
+ const proxyKeys = Object.keys(proxy);
793
+ const actualKeys = Object.keys(actual);
794
+ let { length } = proxyKeys;
795
+ for (let index = 0; index < length; index += 1) {
796
+ const key = proxyKeys[index];
797
+ proxy[key] = actualKeys.includes(key) ? actual[key] : void 0;
798
+ }
799
+ length = actualKeys.length;
800
+ for (let index = 0; index < length; index += 1) {
801
+ const key = actualKeys[index];
802
+ if (!proxyKeys.includes(key)) proxy[key] = actual[key];
803
+ }
804
+ stopBatch();
805
+ }
806
+ function setProxyProperty(state, property, value) {
807
+ if (!state.isArray) {
808
+ state.value[property] = value;
809
+ return;
810
+ }
811
+ const actual = property < 0 ? state.value.length + property : property;
812
+ if (actual > -1) state.value[actual] = value;
813
+ }
814
+ function setProxyValue(first, second) {
815
+ const state = this[SYMBOL_STATE];
816
+ if (state.isArray && first === "length") {
478
817
  state.value.length = second;
479
818
  return;
480
819
  }
481
- if (isObject(first)) {
482
- setObject(state, first);
820
+ if (isProxyObject(state.isArray, first)) {
821
+ setProxyObject(state, first);
483
822
  return;
484
823
  }
485
- const property = isProperty(first);
486
- if (array && property && Number.isNaN(first)) return;
824
+ const property = state.isArray ? typeof first === "number" : isKey(first);
825
+ if (state.isArray && property && Number.isNaN(first)) return;
487
826
  let actual = property ? second : first;
488
827
  if (typeof actual === "function") try {
489
828
  actual = actual();
@@ -498,305 +837,213 @@ function setProxyValue(array, state, isObject, isProperty, setObject, setPropert
498
837
  actual.then((value) => {
499
838
  if (property && state.promises.get(first) === actual) {
500
839
  state.promises.delete(first);
501
- setProperty(state, first, value);
840
+ setProxyProperty(state, first, value);
502
841
  return;
503
842
  }
504
- if (!property && isObject(value) && state.promise === actual) {
843
+ if (!property && isProxyObject(state.isArray, value) && state.promise === actual) {
505
844
  state.promise = void 0;
506
- setObject(state, value);
845
+ setProxyObject(state, value);
507
846
  }
508
847
  }).catch(() => {
509
848
  if (property && state.promises.get(first) === actual) state.promises.delete(first);
510
849
  else if (!property && state.promise === actual) state.promise = void 0;
511
850
  });
512
- } else if (property) setProperty(state, first, actual);
513
- else if (isObject(actual)) setObject(state, actual);
851
+ } else if (property) setProxyProperty(state, first, actual);
852
+ else if (isProxyObject(state.isArray, actual)) setProxyObject(state, actual);
514
853
  }
515
- function setValueInProxy(parameters) {
516
- const { isArray, length, property, state, target, value } = parameters;
517
- if (isArray) {
854
+ function setValueInProxy(instance, target, property, value) {
855
+ const state = instance[SYMBOL_STATE];
856
+ if (state.isArray) {
518
857
  if (!(!Number.isNaN(Number(property)) || property === "length")) return Reflect.set(target, property, value);
519
858
  }
520
859
  const previous = Reflect.get(target, property);
521
- if (!state.equal(previous, value)) {
860
+ if (!(state.equal ?? Object.is)(previous, value)) {
522
861
  Reflect.set(target, property, value);
523
- emitValue(state);
524
- if (isArray) length?.set(target.length);
862
+ emitValue(instance);
863
+ if (state.isArray) state.length?.set(target.length);
525
864
  }
526
865
  return true;
527
866
  }
867
+ function updateProxyValue(callback) {
868
+ if (typeof callback !== "function") throw new TypeError("Callback must be a function");
869
+ setProxyValue.call(this, callback(this[SYMBOL_STATE].value));
870
+ }
528
871
  //#endregion
529
872
  //#region src/value/readonly.ts
530
- function getReadonlyInstance(state, instances, handlers, frozen) {
531
- const key = frozen ? "frozen" : "original";
532
- instances[key] ??= getReadonlySignal(state, handlers, frozen);
533
- return instances[key];
534
- }
535
- function getReadonlySignal(state, handlers, frozen) {
536
- const instance = {
537
- ...handlers,
538
- get: () => getReadonlyValue(state, false, frozen),
539
- peek: () => getReadonlyValue(state, true, frozen)
540
- };
541
- Object.defineProperties(instance, {
542
- [NAME_MORA]: {
543
- enumerable: false,
544
- value: NAME_READONLY
545
- },
546
- frozen: {
547
- enumerable: true,
548
- value: frozen
549
- }
873
+ function Readonly(state, frozen) {
874
+ this[SYMBOL_STATE] = state;
875
+ Object.defineProperty(this, SUBSCRIPTION_TYPE_FROZEN, {
876
+ enumerable: true,
877
+ value: frozen
550
878
  });
551
- return Object.freeze(instance);
552
879
  }
553
- function getReadonlyValue(state, peek, frozen) {
554
- let value = peek ? state.value : getSimpleValue(state);
555
- if (!frozen) return value;
556
- if (Array.isArray(state.value)) value = [...state.value];
557
- else if (isPlainObject(state.value)) value = { ...state.value };
558
- else value = state.value;
559
- return Object.freeze(value);
880
+ Readonly.prototype[NAME_MORA] = NAME_READONLY;
881
+ Readonly.prototype.subscribe = subscribeToReadonly;
882
+ Readonly.prototype.toString = getStringValue;
883
+ Readonly.prototype.get = function() {
884
+ return getReadonlyValue(this, false, this[SUBSCRIPTION_TYPE_FROZEN]);
885
+ };
886
+ Readonly.prototype.peek = function(copy) {
887
+ return getReadonlyValue(this, true, this[SUBSCRIPTION_TYPE_FROZEN], copy);
888
+ };
889
+ Readonly.prototype.toJSON = function() {
890
+ return this[SYMBOL_STATE].value;
891
+ };
892
+ function getReadonlyInstance(frozen) {
893
+ const key = frozen === true ? SUBSCRIPTION_TYPE_FROZEN : SUBSCRIPTION_TYPE_ORIGINAL;
894
+ this[SYMBOL_STATE].readonlies ??= {};
895
+ this[SYMBOL_STATE].readonlies[key] ??= getReadonlySignal(this[SYMBOL_STATE], frozen === true);
896
+ return this[SYMBOL_STATE].readonlies[key];
897
+ }
898
+ function getReadonlySignal(state, frozen) {
899
+ return new Readonly(state, frozen);
900
+ }
901
+ function getReadonlyValue(instance, peek, frozen, copy) {
902
+ let value;
903
+ if (peek) value = peekSignalValue.call(instance, copy === true);
904
+ else value = getSignalValue.call(instance);
905
+ return frozen ? getFrozenValue(value) : value;
560
906
  }
561
907
  //#endregion
562
908
  //#region src/value/signal.ts
563
- function setAndEmit(state, value) {
564
- if (!state.equal(state.value, value)) {
909
+ function Signal(value, options) {
910
+ this[SYMBOL_STATE] = getState(void 0, options);
911
+ handleSignalValue(this, value, setAndEmit);
912
+ }
913
+ Signal.prototype[NAME_MORA] = NAME_SIGNAL;
914
+ Signal.prototype.asReadonly = getReadonlyInstance;
915
+ Signal.prototype.get = getSignalValue;
916
+ Signal.prototype.peek = peekSignalValue;
917
+ Signal.prototype.subscribe = subscribeToSignal;
918
+ Signal.prototype.toString = getStringValue;
919
+ Signal.prototype.set = function(value) {
920
+ return handleSignalValue(this, value, setAndEmit);
921
+ };
922
+ Signal.prototype.toJSON = function() {
923
+ return this[SYMBOL_STATE].value;
924
+ };
925
+ Signal.prototype.update = function(callback) {
926
+ return updateSignalValue(this, callback, setAndEmit);
927
+ };
928
+ function setAndEmit(instance, value) {
929
+ const state = instance[SYMBOL_STATE];
930
+ if (!(state.equal ?? Object.is)(state.value, value)) {
565
931
  state.value = value;
566
- emitValue(state);
932
+ emitValue(instance);
567
933
  }
568
934
  }
569
935
  function signal(value, options) {
570
- const [rx, state] = reactive(void 0, options);
571
- const readonlies = {};
572
- const handlers = {
573
- ...rx,
574
- subscribe: (callback) => subscribe(state, callback),
575
- unsubscribe: (callback) => {
576
- state.subscriptions.delete(callback);
577
- }
578
- };
579
- const instance = {
580
- ...handlers,
581
- asReadonly: (frozen) => getReadonlyInstance(state, readonlies, handlers, frozen === true),
582
- get: () => getSimpleValue(state),
583
- peek: () => state.value,
584
- set: (value) => {
585
- handleSimpleValue(state, value, setAndEmit);
586
- },
587
- update: (callback) => {
588
- handleSimpleValue(state, callback(state.value), setAndEmit);
589
- }
590
- };
591
- Object.defineProperty(instance, NAME_MORA, {
592
- enumerable: false,
593
- value: NAME_SIGNAL
594
- });
595
- handleSimpleValue(state, value, setAndEmit);
596
- return Object.freeze(instance);
936
+ return new Signal(value, options);
597
937
  }
598
938
  //#endregion
599
939
  //#region src/value/array.ts
600
- function array(value, options) {
601
- const [rx, state] = reactive([], options);
602
- const indiced = /* @__PURE__ */ new Map();
603
- const length = signal(0);
604
- const readonlies = {};
605
- let instance = {};
606
- state.value = new Proxy([], {
607
- get: (target, property) => METHODS_UPDATE.has(property) ? updateArray(property, target, state, length) : Reflect.get(target, property),
608
- set: (target, property, value) => setValueInProxy({
609
- length,
610
- property,
611
- state,
612
- target,
613
- value,
614
- isArray: true
615
- })
616
- });
617
- function get(value) {
618
- return getArrayValue(instance, indiced, state, length, value);
619
- }
620
- function set(first, second) {
621
- setProxyValue(true, state, isArrayValue, isArrayIndex, setArray, setAtIndex, first, second);
622
- }
623
- const handlers = {
624
- ...rx,
625
- get: (value) => get(value),
626
- peek: (first, second) => peekArrayValue(state, length, first, second),
627
- subscribe: (first, second) => {
628
- if (typeof first === "number" && typeof second === "function") return getReactiveValueInProxy(instance, indiced, first, true).subscribe(second);
629
- return typeof first === "function" ? subscribe(state, first) : noop$1;
630
- },
631
- unsubscribe: (first, second) => {
632
- if (typeof first === "number" && typeof second === "function") getReactiveValueInProxy(instance, indiced, first, true)?.unsubscribe(second);
633
- else if (typeof first === "function") unsubscribe(state, first);
634
- }
635
- };
636
- instance = {
637
- ...handlers,
638
- asReadonly: (frozen) => getReadonlyInstance(state, readonlies, handlers, frozen === true),
639
- at: (index) => get(index),
640
- clear: () => {
641
- state.value.length = 0;
642
- },
643
- filter: (callback) => computed(() => filter(get(), callback)),
644
- map: (callback) => computed(() => get().map(callback)),
645
- notify: () => {
646
- emityProxyValues(state, indiced);
647
- },
648
- pop: () => state.value.pop(),
649
- push: (...items) => state.value.push(...items),
650
- select: (filter, map) => computed(() => select(get(), filter, map)),
651
- set: (first, second) => {
652
- set(first, second);
653
- },
654
- shift: () => state.value.shift(),
655
- splice: (from, to, ...items) => state.value.splice(from, to ?? state.value.length, ...items),
656
- unshift: (...items) => state.value.unshift(...items),
657
- update: (callback) => updateArrayValue(instance, state, callback)
940
+ function ReactiveArray(value, options) {
941
+ this[SYMBOL_STATE] = {
942
+ ...getState(void 0, options),
943
+ isArray: true,
944
+ length: signal(0)
658
945
  };
659
- Object.defineProperties(instance, {
660
- [NAME_MORA]: {
661
- enumerable: false,
662
- value: NAME_ARRAY
663
- },
664
- length: {
665
- enumerable: true,
666
- get: () => length.get(),
667
- set: (value) => setArrayLength(state, value)
668
- }
946
+ this[SYMBOL_STATE].value = new Proxy([], {
947
+ get: (target, property) => METHODS_UPDATE.has(property) ? updateArray(this, property, target) : Reflect.get(target, property),
948
+ set: (target, property, value) => setValueInProxy(this, target, property, value)
669
949
  });
670
- set(value);
671
- return Object.freeze(instance);
672
- }
673
- function getArrayValue(instance, indiced, state, length, first) {
674
- if (typeof first === "number") return getReactiveValueInProxy(instance, indiced, first, true).get();
675
- return first === "length" ? length.get() : getSimpleValue(state);
676
- }
677
- function isArrayIndex(value) {
678
- return typeof value === "number";
679
- }
680
- function isArrayValue(value) {
681
- return value == null || Array.isArray(value);
950
+ Object.defineProperty(this, PROPERTY_LENGTH, {
951
+ enumerable: true,
952
+ get: () => this[SYMBOL_STATE].length.get(),
953
+ set: (value) => setArrayLength(this[SYMBOL_STATE], value)
954
+ });
955
+ setProxyValue.call(this, value);
956
+ }
957
+ ReactiveArray.prototype[NAME_MORA] = NAME_ARRAY;
958
+ ReactiveArray.prototype.asReadonly = getReadonlyInstance;
959
+ ReactiveArray.prototype.at = getArrayValues;
960
+ ReactiveArray.prototype.get = getArrayValues;
961
+ ReactiveArray.prototype.notify = emitProxyValues;
962
+ ReactiveArray.prototype.peek = peekArrayValue;
963
+ ReactiveArray.prototype.set = setProxyValue;
964
+ ReactiveArray.prototype.subscribe = subscribeToProxy;
965
+ ReactiveArray.prototype.toString = getStringValue;
966
+ ReactiveArray.prototype.update = updateProxyValue;
967
+ ReactiveArray.prototype.clear = function() {
968
+ this[SYMBOL_STATE].value.length = 0;
969
+ };
970
+ ReactiveArray.prototype.filter = function(callback) {
971
+ return computed(() => filter(getArrayValues.call(this), callback));
972
+ };
973
+ ReactiveArray.prototype.map = function(callback) {
974
+ return computed(() => getArrayValues.call(this).map(callback));
975
+ };
976
+ ReactiveArray.prototype.pop = function() {
977
+ return this[SYMBOL_STATE].value.pop();
978
+ };
979
+ ReactiveArray.prototype.push = function(...items) {
980
+ return this[SYMBOL_STATE].value.push(...items);
981
+ };
982
+ ReactiveArray.prototype.select = function(filter, map) {
983
+ return computed(() => select(getArrayValues.call(this), filter, map));
984
+ };
985
+ ReactiveArray.prototype.shift = function() {
986
+ return this[SYMBOL_STATE].value.shift();
987
+ };
988
+ ReactiveArray.prototype.splice = function(from, to, ...items) {
989
+ return this[SYMBOL_STATE].value.splice(from, to ?? this[SYMBOL_STATE].value.length, ...items);
990
+ };
991
+ ReactiveArray.prototype.toJSON = function() {
992
+ return this[SYMBOL_STATE].value;
993
+ };
994
+ ReactiveArray.prototype.unshift = function(...items) {
995
+ return this[SYMBOL_STATE].value.unshift(...items);
996
+ };
997
+ function array(value, options) {
998
+ return new ReactiveArray(value, options);
682
999
  }
683
- function peekArrayValue(state, length, first, second) {
684
- if (first === "length") return length.peek();
685
- let value;
686
- if (typeof first === "number") value = state.value.at(first);
687
- else value = state.value;
688
- if (!(first === true || second === true)) return value;
689
- if (Array.isArray(value)) return value.slice();
690
- if (isPlainObject(value)) return { ...value };
691
- return value;
1000
+ function getArrayValues(value) {
1001
+ return value === "length" ? this[SYMBOL_STATE].length.get() : getValueInProxy.call(this, value);
692
1002
  }
693
- function setArray(state, value) {
694
- state.value.splice(0, state.value.length, ...value ?? []);
1003
+ function peekArrayValue(first, second) {
1004
+ return first === "length" ? this[SYMBOL_STATE].length.peek() : peekValueInProxy.call(this, first, second);
695
1005
  }
696
1006
  function setArrayLength(state, value) {
697
- if (typeof value === "number" && value >= 0 && value !== state.value.length) state.value.length = value;
698
- }
699
- function setAtIndex(state, index, value) {
700
- const actual = index < 0 ? state.value.length + index : index;
701
- if (actual > -1) state.value[actual] = value;
1007
+ if (typeof value === "number" && !Number.isNaN(value) && value >= 0 && value !== state.value.length) state.value.length = value;
702
1008
  }
703
- function updateArray(type, array, state, length) {
1009
+ function updateArray(instance, type, array) {
1010
+ const state = instance[SYMBOL_STATE];
704
1011
  const affectsLength = METHODS_AFFECTING_LENGTH.has(type);
705
1012
  const previousArray = affectsLength ? [] : array.slice();
706
1013
  const previousLength = array.length;
707
1014
  return (...args) => {
708
1015
  const result = array[type](...args);
709
1016
  if (affectsLength ? array.length !== previousLength : !equalArrays(state, previousArray, array)) {
710
- emitValue(state);
711
- length.set(array.length);
1017
+ emitValue(instance);
1018
+ state.length.set(array.length);
712
1019
  }
713
1020
  return result;
714
1021
  };
715
1022
  }
716
- function updateArrayValue(instance, state, callback) {
717
- const updated = callback(state.value);
718
- if (updated == null || Array.isArray(updated)) instance.set(updated);
719
- }
720
1023
  //#endregion
721
1024
  //#region src/value/store.ts
722
- function isStoreObject(value) {
723
- return value == null || isPlainObject(value);
724
- }
725
- function setObject(state, value) {
726
- startBatch();
727
- const actual = value ?? {};
728
- const proxy = state.value;
729
- const proxyKeys = Object.keys(proxy);
730
- const actualKeys = Object.keys(actual);
731
- let { length } = proxyKeys;
732
- for (let index = 0; index < length; index += 1) {
733
- const key = proxyKeys[index];
734
- proxy[key] = actualKeys.includes(key) ? actual[key] : void 0;
735
- }
736
- length = actualKeys.length;
737
- for (let index = 0; index < length; index += 1) {
738
- const key = actualKeys[index];
739
- if (!proxyKeys.includes(key)) proxy[key] = actual[key];
740
- }
741
- stopBatch();
742
- }
743
- function peekStoreValue(state, first, second) {
744
- let value;
745
- if (isKey(first)) value = state.value[first];
746
- else value = state.value;
747
- if (!(first === true || second === true)) return value;
748
- if (Array.isArray(value)) return value.slice();
749
- if (isPlainObject(value)) return { ...value };
750
- return value;
751
- }
752
- function setProperty(state, key, value) {
753
- state.value[key] = value;
754
- }
755
- function store(value, options) {
756
- const [rx, state] = reactive(void 0, options);
757
- const keyed = /* @__PURE__ */ new Map();
758
- const readonlies = {};
759
- let instance = {};
760
- state.value = new Proxy({}, { set: (target, property, value) => setValueInProxy({
761
- target,
762
- property,
763
- state,
764
- value,
1025
+ function ReactiveStore(value, options) {
1026
+ this[SYMBOL_STATE] = {
1027
+ ...getState(void 0, options),
765
1028
  isArray: false
766
- }) });
767
- const handlers = {
768
- ...rx,
769
- get: (value) => isKey(value) ? getReactiveValueInProxy(instance, keyed, value, false).get() : getSimpleValue(state),
770
- peek: (first, second) => peekStoreValue(state, first, second),
771
- subscribe: (first, second) => {
772
- if (isKey(first) && typeof second === "function") return getReactiveValueInProxy(instance, keyed, first, false).subscribe(second);
773
- return typeof first === "function" ? subscribe(state, first) : noop;
774
- },
775
- unsubscribe: (first, second) => {
776
- if (isKey(first) && typeof second === "function") getReactiveValueInProxy(instance, keyed, first, false)?.unsubscribe(second);
777
- else if (typeof first === "function") unsubscribe(state, first);
778
- }
779
- };
780
- instance = {
781
- ...handlers,
782
- asReadonly: (frozen) => getReadonlyInstance(state, readonlies, handlers, frozen === true),
783
- notify() {
784
- emityProxyValues(state, keyed);
785
- },
786
- set: (first, second) => {
787
- setProxyValue(false, state, isStoreObject, isKey, setObject, setProperty, first, second);
788
- },
789
- update: (callback) => {
790
- const updated = callback(state.value);
791
- if (updated == null || isPlainObject(updated)) setObject(state, updated);
792
- }
793
1029
  };
794
- Object.defineProperty(instance, NAME_MORA, {
795
- enumerable: false,
796
- value: NAME_STORE
797
- });
798
- instance.set(value);
799
- return Object.freeze(instance);
1030
+ this[SYMBOL_STATE].value = new Proxy({}, { set: (target, property, value) => setValueInProxy(this, target, property, value) });
1031
+ setProxyValue.call(this, value);
1032
+ }
1033
+ ReactiveStore.prototype[NAME_MORA] = NAME_STORE;
1034
+ ReactiveStore.prototype.asReadonly = getReadonlyInstance;
1035
+ ReactiveStore.prototype.get = getValueInProxy;
1036
+ ReactiveStore.prototype.notify = emitProxyValues;
1037
+ ReactiveStore.prototype.peek = peekValueInProxy;
1038
+ ReactiveStore.prototype.set = setProxyValue;
1039
+ ReactiveStore.prototype.subscribe = subscribeToProxy;
1040
+ ReactiveStore.prototype.toString = getStringValue;
1041
+ ReactiveStore.prototype.update = updateProxyValue;
1042
+ ReactiveStore.prototype.toJSON = function() {
1043
+ return this[SYMBOL_STATE].value;
1044
+ };
1045
+ function store(value, options) {
1046
+ return new ReactiveStore(value, options);
800
1047
  }
801
1048
  //#endregion
802
1049
  export { array, computed, effect, isComputed, isEffect, isReactive, isReactiveArray, isReactiveStore, isReadonlySignal, isSignal, signal, startBatch, stopBatch, store };