@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.
- package/dist/batch.d.mts +4 -5
- package/dist/batch.mjs +4 -2
- package/dist/constants.d.mts +31 -19
- package/dist/constants.mjs +19 -2
- package/dist/effect.d.mts +5 -5
- package/dist/effect.mjs +8 -5
- package/dist/helpers/is.d.mts +14 -9
- package/dist/helpers/is.mjs +6 -0
- package/dist/helpers/misc.d.mts +4 -0
- package/dist/helpers/misc.mjs +9 -0
- package/dist/helpers/proxy.d.mts +10 -10
- package/dist/helpers/proxy.mjs +83 -27
- package/dist/helpers/subscription.d.mts +8 -0
- package/dist/helpers/subscription.mjs +30 -0
- package/dist/helpers/value.d.mts +10 -7
- package/dist/helpers/value.mjs +56 -17
- package/dist/index.d.mts +3 -2
- package/dist/models.d.mts +82 -101
- package/dist/models.mjs +1 -0
- package/dist/mora.full.mjs +659 -412
- package/dist/value/array.d.mts +5 -5
- package/dist/value/array.mjs +70 -109
- package/dist/value/computed.d.mts +5 -4
- package/dist/value/computed.mjs +45 -31
- package/dist/value/readonly.d.mts +4 -6
- package/dist/value/readonly.mjs +34 -31
- package/dist/value/signal.d.mts +5 -5
- package/dist/value/signal.mjs +28 -34
- package/dist/value/store.d.mts +5 -5
- package/dist/value/store.mjs +25 -83
- package/package.json +6 -6
- package/src/batch.ts +15 -5
- package/src/constants.ts +36 -2
- package/src/effect.ts +20 -11
- package/src/helpers/is.ts +16 -6
- package/src/helpers/misc.ts +15 -0
- package/src/helpers/proxy.ts +151 -74
- package/src/helpers/subscription.ts +89 -0
- package/src/helpers/value.ts +121 -30
- package/src/index.ts +1 -1
- package/src/models.ts +81 -98
- package/src/value/array.ts +116 -226
- package/src/value/computed.ts +96 -43
- package/src/value/readonly.ts +68 -54
- package/src/value/signal.ts +54 -46
- package/src/value/store.ts +42 -168
- package/types/constants.d.ts +1 -1
- package/types/index.d.ts +1 -1
- package/types/value/array.d.ts +1 -1
- package/types/value/computed.d.ts +0 -3
- package/types/value/signal.d.ts +1 -1
- package/types/value/store.d.ts +1 -1
- package/dist/subscription.d.mts +0 -7
- package/dist/subscription.mjs +0 -27
- package/dist/value/reactive.d.mts +0 -5
- package/dist/value/reactive.mjs +0 -16
- package/src/subscription.ts +0 -45
- package/src/value/reactive.ts +0 -24
package/dist/value/store.mjs
CHANGED
|
@@ -1,90 +1,32 @@
|
|
|
1
|
-
import { NAME_MORA, NAME_STORE } from "../constants.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { emityProxyValues, getReactiveValueInProxy, setProxyValue, setValueInProxy } from "../helpers/proxy.mjs";
|
|
1
|
+
import { NAME_MORA, NAME_STORE, SYMBOL_STATE } from "../constants.mjs";
|
|
2
|
+
import { getStringValue } from "../helpers/value.mjs";
|
|
3
|
+
import { getState } from "../helpers/misc.mjs";
|
|
4
|
+
import { subscribeToProxy } from "../helpers/subscription.mjs";
|
|
5
|
+
import { emitProxyValues, getValueInProxy, peekValueInProxy, setProxyValue, setValueInProxy, updateProxyValue } from "../helpers/proxy.mjs";
|
|
7
6
|
import { getReadonlyInstance } from "./readonly.mjs";
|
|
8
|
-
import { isKey, isPlainObject } from "@oscarpalmer/atoms/is";
|
|
9
7
|
//#region src/value/store.ts
|
|
10
|
-
function
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
function setObject(state, value) {
|
|
14
|
-
startBatch();
|
|
15
|
-
const actual = value ?? {};
|
|
16
|
-
const proxy = state.value;
|
|
17
|
-
const proxyKeys = Object.keys(proxy);
|
|
18
|
-
const actualKeys = Object.keys(actual);
|
|
19
|
-
let { length } = proxyKeys;
|
|
20
|
-
for (let index = 0; index < length; index += 1) {
|
|
21
|
-
const key = proxyKeys[index];
|
|
22
|
-
proxy[key] = actualKeys.includes(key) ? actual[key] : void 0;
|
|
23
|
-
}
|
|
24
|
-
length = actualKeys.length;
|
|
25
|
-
for (let index = 0; index < length; index += 1) {
|
|
26
|
-
const key = actualKeys[index];
|
|
27
|
-
if (!proxyKeys.includes(key)) proxy[key] = actual[key];
|
|
28
|
-
}
|
|
29
|
-
stopBatch();
|
|
30
|
-
}
|
|
31
|
-
function peekStoreValue(state, first, second) {
|
|
32
|
-
let value;
|
|
33
|
-
if (isKey(first)) value = state.value[first];
|
|
34
|
-
else value = state.value;
|
|
35
|
-
if (!(first === true || second === true)) return value;
|
|
36
|
-
if (Array.isArray(value)) return value.slice();
|
|
37
|
-
if (isPlainObject(value)) return { ...value };
|
|
38
|
-
return value;
|
|
39
|
-
}
|
|
40
|
-
function setProperty(state, key, value) {
|
|
41
|
-
state.value[key] = value;
|
|
42
|
-
}
|
|
43
|
-
function store(value, options) {
|
|
44
|
-
const [rx, state] = reactive(void 0, options);
|
|
45
|
-
const keyed = /* @__PURE__ */ new Map();
|
|
46
|
-
const readonlies = {};
|
|
47
|
-
let instance = {};
|
|
48
|
-
state.value = new Proxy({}, { set: (target, property, value) => setValueInProxy({
|
|
49
|
-
target,
|
|
50
|
-
property,
|
|
51
|
-
state,
|
|
52
|
-
value,
|
|
8
|
+
function ReactiveStore(value, options) {
|
|
9
|
+
this[SYMBOL_STATE] = {
|
|
10
|
+
...getState(void 0, options),
|
|
53
11
|
isArray: false
|
|
54
|
-
}) });
|
|
55
|
-
const handlers = {
|
|
56
|
-
...rx,
|
|
57
|
-
get: (value) => isKey(value) ? getReactiveValueInProxy(instance, keyed, value, false).get() : getSimpleValue(state),
|
|
58
|
-
peek: (first, second) => peekStoreValue(state, first, second),
|
|
59
|
-
subscribe: (first, second) => {
|
|
60
|
-
if (isKey(first) && typeof second === "function") return getReactiveValueInProxy(instance, keyed, first, false).subscribe(second);
|
|
61
|
-
return typeof first === "function" ? subscribe(state, first) : noop;
|
|
62
|
-
},
|
|
63
|
-
unsubscribe: (first, second) => {
|
|
64
|
-
if (isKey(first) && typeof second === "function") getReactiveValueInProxy(instance, keyed, first, false)?.unsubscribe(second);
|
|
65
|
-
else if (typeof first === "function") unsubscribe(state, first);
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
instance = {
|
|
69
|
-
...handlers,
|
|
70
|
-
asReadonly: (frozen) => getReadonlyInstance(state, readonlies, handlers, frozen === true),
|
|
71
|
-
notify() {
|
|
72
|
-
emityProxyValues(state, keyed);
|
|
73
|
-
},
|
|
74
|
-
set: (first, second) => {
|
|
75
|
-
setProxyValue(false, state, isStoreObject, isKey, setObject, setProperty, first, second);
|
|
76
|
-
},
|
|
77
|
-
update: (callback) => {
|
|
78
|
-
const updated = callback(state.value);
|
|
79
|
-
if (updated == null || isPlainObject(updated)) setObject(state, updated);
|
|
80
|
-
}
|
|
81
12
|
};
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
13
|
+
this[SYMBOL_STATE].value = new Proxy({}, { set: (target, property, value) => setValueInProxy(this, target, property, value) });
|
|
14
|
+
setProxyValue.call(this, value);
|
|
15
|
+
}
|
|
16
|
+
ReactiveStore.prototype[NAME_MORA] = NAME_STORE;
|
|
17
|
+
ReactiveStore.prototype.asReadonly = getReadonlyInstance;
|
|
18
|
+
ReactiveStore.prototype.get = getValueInProxy;
|
|
19
|
+
ReactiveStore.prototype.notify = emitProxyValues;
|
|
20
|
+
ReactiveStore.prototype.peek = peekValueInProxy;
|
|
21
|
+
ReactiveStore.prototype.set = setProxyValue;
|
|
22
|
+
ReactiveStore.prototype.subscribe = subscribeToProxy;
|
|
23
|
+
ReactiveStore.prototype.toString = getStringValue;
|
|
24
|
+
ReactiveStore.prototype.update = updateProxyValue;
|
|
25
|
+
ReactiveStore.prototype.toJSON = function() {
|
|
26
|
+
return this[SYMBOL_STATE].value;
|
|
27
|
+
};
|
|
28
|
+
function store(value, options) {
|
|
29
|
+
return new ReactiveStore(value, options);
|
|
88
30
|
}
|
|
89
31
|
//#endregion
|
|
90
32
|
export { store };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oscarpalmer/mora",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.33.0",
|
|
4
4
|
"description": "Signals and stuff…",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"reactive",
|
|
@@ -39,17 +39,17 @@
|
|
|
39
39
|
"test:leak": "vpx vp test run --detect-async-leaks --coverage"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@oscarpalmer/atoms": "^0.
|
|
42
|
+
"@oscarpalmer/atoms": "^0.202"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@types/node": "^26.
|
|
46
|
-
"@vitest/coverage-istanbul": "4.1
|
|
45
|
+
"@types/node": "^26.5",
|
|
46
|
+
"@vitest/coverage-istanbul": "^4.1",
|
|
47
47
|
"jsdom": "^30",
|
|
48
|
-
"tsdown": "^0.
|
|
48
|
+
"tsdown": "^0.23",
|
|
49
49
|
"typescript": "^6",
|
|
50
50
|
"vite": "npm:@voidzero-dev/vite-plus-core@latest",
|
|
51
51
|
"vite-plus": "latest",
|
|
52
52
|
"vitest": "npm:@voidzero-dev/vite-plus-test@latest"
|
|
53
53
|
},
|
|
54
|
-
"packageManager": "npm@11.
|
|
54
|
+
"packageManager": "npm@11.19.0"
|
|
55
55
|
}
|
package/src/batch.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import {BATCH} from './constants';
|
|
2
2
|
import {runEffect} from './effect';
|
|
3
|
-
import
|
|
3
|
+
import {getFrozenValue, peekSignalValue} from './helpers/value';
|
|
4
|
+
import type {EffectState, StoredSubscription} from './models';
|
|
5
|
+
|
|
6
|
+
// #region Functions
|
|
4
7
|
|
|
5
8
|
export function flushHandlers(): void {
|
|
6
9
|
if (BATCH.flushing) {
|
|
@@ -17,10 +20,15 @@ export function flushHandlers(): void {
|
|
|
17
20
|
BATCH.handlers.clear();
|
|
18
21
|
|
|
19
22
|
for (let index = 0; index < length; index += 1) {
|
|
20
|
-
const handler = handlers[index];
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
const [, handler] = handlers[index];
|
|
24
|
+
const subscription = handler as StoredSubscription;
|
|
25
|
+
|
|
26
|
+
if (typeof subscription.frozen === 'boolean') {
|
|
27
|
+
subscription.callback(
|
|
28
|
+
subscription.frozen
|
|
29
|
+
? getFrozenValue(subscription.state.value)
|
|
30
|
+
: peekSignalValue.call(subscription.instance, subscription.copy),
|
|
31
|
+
);
|
|
24
32
|
} else {
|
|
25
33
|
runEffect(handler as EffectState);
|
|
26
34
|
}
|
|
@@ -50,3 +58,5 @@ export function stopBatch(): void {
|
|
|
50
58
|
|
|
51
59
|
flushHandlers();
|
|
52
60
|
}
|
|
61
|
+
|
|
62
|
+
// #endregion
|
package/src/constants.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import type {Active, Batch,
|
|
1
|
+
import type {Active, Batch, SubscriptionType} from './models';
|
|
2
|
+
|
|
3
|
+
// #region Variables
|
|
2
4
|
|
|
3
5
|
export const ACTIVE: Active = {};
|
|
4
6
|
|
|
@@ -11,7 +13,7 @@ export const ARRAY_PEEK = 10;
|
|
|
11
13
|
export const BATCH: Batch = {
|
|
12
14
|
depth: 0,
|
|
13
15
|
flushing: false,
|
|
14
|
-
handlers: new
|
|
16
|
+
handlers: new Map(),
|
|
15
17
|
};
|
|
16
18
|
|
|
17
19
|
export const METHODS_AFFECTING_LENGTH = new Set<string>(['pop', 'push', 'shift', 'unshift']);
|
|
@@ -39,6 +41,8 @@ export const NAME_SIGNAL = 'signal';
|
|
|
39
41
|
|
|
40
42
|
export const NAME_STORE = 'store';
|
|
41
43
|
|
|
44
|
+
export const NAME_SUBSCRIPTION = 'subscription';
|
|
45
|
+
|
|
42
46
|
export const NAME_ALL = new Set([
|
|
43
47
|
NAME_ARRAY,
|
|
44
48
|
NAME_COMPUTED,
|
|
@@ -48,3 +52,33 @@ export const NAME_ALL = new Set([
|
|
|
48
52
|
]);
|
|
49
53
|
|
|
50
54
|
export const PROPERTY_LENGTH = 'length';
|
|
55
|
+
|
|
56
|
+
export const SYMBOL_EFFECT = Symbol('effect');
|
|
57
|
+
|
|
58
|
+
export const SYMBOL_STATE = Symbol('state');
|
|
59
|
+
|
|
60
|
+
export const SUBSCRIPTION_PROPERTY = {
|
|
61
|
+
key: NAME_MORA,
|
|
62
|
+
value: NAME_SUBSCRIPTION,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const SUBSCRIPTION_TYPE_COPY: SubscriptionType = 'copy';
|
|
66
|
+
|
|
67
|
+
export const SUBSCRIPTION_TYPE_FROZEN: SubscriptionType = 'frozen';
|
|
68
|
+
|
|
69
|
+
export const SUBSCRIPTION_TYPE_ORIGINAL: SubscriptionType = 'original';
|
|
70
|
+
|
|
71
|
+
export const SUBSCRIPTION_TYPE_READONLY: SubscriptionType = 'readonly';
|
|
72
|
+
|
|
73
|
+
export const SUBSCRIPTION_TYPES_COPY = new Set<SubscriptionType>([
|
|
74
|
+
SUBSCRIPTION_TYPE_COPY,
|
|
75
|
+
SUBSCRIPTION_TYPE_READONLY,
|
|
76
|
+
]);
|
|
77
|
+
|
|
78
|
+
export const SUBSCRIPTION_TYPES: Set<SubscriptionType> = new Set([
|
|
79
|
+
...SUBSCRIPTION_TYPES_COPY,
|
|
80
|
+
SUBSCRIPTION_TYPE_FROZEN,
|
|
81
|
+
SUBSCRIPTION_TYPE_ORIGINAL,
|
|
82
|
+
]);
|
|
83
|
+
|
|
84
|
+
// #endregion
|
package/src/effect.ts
CHANGED
|
@@ -1,7 +1,21 @@
|
|
|
1
1
|
import type {GenericCallback} from '@oscarpalmer/atoms/models';
|
|
2
|
-
import {ACTIVE, NAME_EFFECT} from './constants';
|
|
2
|
+
import {ACTIVE, NAME_EFFECT, NAME_MORA, SYMBOL_STATE} from './constants';
|
|
3
3
|
import type {Effect, EffectState} from './models';
|
|
4
4
|
|
|
5
|
+
// #region Instance
|
|
6
|
+
|
|
7
|
+
function Effect(this: any, callback: GenericCallback) {
|
|
8
|
+
this[SYMBOL_STATE] = {callback};
|
|
9
|
+
|
|
10
|
+
runEffect(this[SYMBOL_STATE]);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
Effect.prototype[NAME_MORA] = NAME_EFFECT;
|
|
14
|
+
|
|
15
|
+
// #endregion
|
|
16
|
+
|
|
17
|
+
// #region Functions
|
|
18
|
+
|
|
5
19
|
/**
|
|
6
20
|
* Create an effect
|
|
7
21
|
*
|
|
@@ -17,17 +31,10 @@ export function effect(callback: GenericCallback): Effect {
|
|
|
17
31
|
}
|
|
18
32
|
|
|
19
33
|
function getEffect(callback: GenericCallback): [Effect, EffectState] {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const instance = Object.freeze({
|
|
25
|
-
$mora: NAME_EFFECT,
|
|
26
|
-
});
|
|
34
|
+
// @ts-expect-error All good, no worries :-)
|
|
35
|
+
const instance = new Effect(callback);
|
|
27
36
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return [instance, state];
|
|
37
|
+
return [instance, instance[SYMBOL_STATE]];
|
|
31
38
|
}
|
|
32
39
|
|
|
33
40
|
export function internalEffect(callback: GenericCallback): EffectState {
|
|
@@ -45,3 +52,5 @@ export function runEffect(state: EffectState): void {
|
|
|
45
52
|
ACTIVE.effect = previousEffect;
|
|
46
53
|
}
|
|
47
54
|
}
|
|
55
|
+
|
|
56
|
+
// #endregion
|
package/src/helpers/is.ts
CHANGED
|
@@ -19,13 +19,15 @@ import type {
|
|
|
19
19
|
Signal,
|
|
20
20
|
} from '../models';
|
|
21
21
|
|
|
22
|
+
// #region Functions
|
|
23
|
+
|
|
22
24
|
/**
|
|
23
25
|
* Is the value a computed signal?
|
|
24
26
|
*
|
|
25
27
|
* @param value Value to check
|
|
26
28
|
* @returns True if value is a {@link Computed}
|
|
27
29
|
*/
|
|
28
|
-
export function isComputed<Value>(value: unknown): value is Computed<Value> {
|
|
30
|
+
export function isComputed<Value = unknown>(value: unknown): value is Computed<Value> {
|
|
29
31
|
return isMora<Computed<Value>>(value, NAME_COMPUTED);
|
|
30
32
|
}
|
|
31
33
|
|
|
@@ -56,7 +58,7 @@ function isMora<Instance>(value: unknown, name: string | Set<string>): value is
|
|
|
56
58
|
* @param value Value to check
|
|
57
59
|
* @returns True if value is a {@link Reactive}
|
|
58
60
|
*/
|
|
59
|
-
export function isReactive<Value>(value: unknown): value is Reactive<Value> {
|
|
61
|
+
export function isReactive<Value = unknown>(value: unknown): value is Reactive<Value> {
|
|
60
62
|
return isMora<Reactive<Value>>(value, NAME_ALL);
|
|
61
63
|
}
|
|
62
64
|
|
|
@@ -66,7 +68,7 @@ export function isReactive<Value>(value: unknown): value is Reactive<Value> {
|
|
|
66
68
|
* @param value Value to check
|
|
67
69
|
* @returns True if value is a {@link Signal}
|
|
68
70
|
*/
|
|
69
|
-
export function isSignal<Value>(value: unknown): value is Signal<Value> {
|
|
71
|
+
export function isSignal<Value = unknown>(value: unknown): value is Signal<Value> {
|
|
70
72
|
return isMora<Signal<Value>>(value, NAME_SIGNAL);
|
|
71
73
|
}
|
|
72
74
|
|
|
@@ -76,7 +78,7 @@ export function isSignal<Value>(value: unknown): value is Signal<Value> {
|
|
|
76
78
|
* @param value Value to check
|
|
77
79
|
* @returns True if value is a {@link ReactiveArray}
|
|
78
80
|
*/
|
|
79
|
-
export function isReactiveArray<Item>(value: unknown): value is ReactiveArray<Item> {
|
|
81
|
+
export function isReactiveArray<Item = unknown>(value: unknown): value is ReactiveArray<Item> {
|
|
80
82
|
return isMora<ReactiveArray<Item>>(value, NAME_ARRAY);
|
|
81
83
|
}
|
|
82
84
|
|
|
@@ -86,12 +88,20 @@ export function isReactiveArray<Item>(value: unknown): value is ReactiveArray<It
|
|
|
86
88
|
* @param value Value to check
|
|
87
89
|
* @returns True if value is a {@link Store}
|
|
88
90
|
*/
|
|
89
|
-
export function isReactiveStore<Value extends PlainObject>(
|
|
91
|
+
export function isReactiveStore<Value extends PlainObject = PlainObject>(
|
|
90
92
|
value: unknown,
|
|
91
93
|
): value is ReactiveStore<Value> {
|
|
92
94
|
return isMora<ReactiveStore<Value>>(value, NAME_STORE);
|
|
93
95
|
}
|
|
94
96
|
|
|
95
|
-
|
|
97
|
+
/**
|
|
98
|
+
* Is the value a readonly signal?
|
|
99
|
+
*
|
|
100
|
+
* @param value Value to check
|
|
101
|
+
* @returns True if value is a {@link ReadonlySignal}
|
|
102
|
+
*/
|
|
103
|
+
export function isReadonlySignal<Value = unknown>(value: unknown): value is ReadonlySignal<Value> {
|
|
96
104
|
return isMora<ReadonlySignal<Value>>(value, NAME_READONLY);
|
|
97
105
|
}
|
|
106
|
+
|
|
107
|
+
// #endregion
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type {ReactiveOptions, ReactiveState} from '../models';
|
|
2
|
+
|
|
3
|
+
// #region Functions
|
|
4
|
+
|
|
5
|
+
export function getState(value: unknown, options?: ReactiveOptions<unknown>): ReactiveState {
|
|
6
|
+
return {
|
|
7
|
+
value,
|
|
8
|
+
equal:
|
|
9
|
+
typeof options === 'object' && typeof options?.equal === 'function'
|
|
10
|
+
? options.equal
|
|
11
|
+
: undefined,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// #endregion
|
package/src/helpers/proxy.ts
CHANGED
|
@@ -1,100 +1,164 @@
|
|
|
1
|
+
import {isKey, isPlainObject} from '@oscarpalmer/atoms/is';
|
|
1
2
|
import type {ArrayOrPlainObject, Key, PlainObject} from '@oscarpalmer/atoms/models';
|
|
2
|
-
import {
|
|
3
|
+
import {startBatch, stopBatch} from '../batch';
|
|
4
|
+
import {PROPERTY_LENGTH, SYMBOL_STATE} from '../constants';
|
|
3
5
|
import type {
|
|
4
6
|
Computed,
|
|
5
|
-
ComputedEffect,
|
|
6
7
|
ReactiveArray,
|
|
7
|
-
|
|
8
|
+
ReactiveProxyState,
|
|
8
9
|
ReactiveStore,
|
|
9
|
-
|
|
10
|
+
InternalProxy,
|
|
10
11
|
} from '../models';
|
|
11
12
|
import {internalComputed} from '../value/computed';
|
|
12
|
-
import {emitValue} from './value';
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
): void;
|
|
23
|
-
|
|
24
|
-
export function emityProxyValues(
|
|
25
|
-
state: ReactiveState<unknown, unknown>,
|
|
26
|
-
mapped: Map<Key, [Computed<unknown>, ComputedEffect]>,
|
|
27
|
-
): void {
|
|
28
|
-
const values = [...mapped.values()];
|
|
13
|
+
import {emitValue, getSignalValue, peekSignalValue} from './value';
|
|
14
|
+
|
|
15
|
+
// #region Functions
|
|
16
|
+
|
|
17
|
+
export function emitProxyValues(this: InternalProxy): void {
|
|
18
|
+
const state = this[SYMBOL_STATE];
|
|
19
|
+
|
|
20
|
+
state.mapped ??= new Map();
|
|
21
|
+
|
|
22
|
+
const values = [...state.mapped.values()];
|
|
29
23
|
const {length} = values;
|
|
30
24
|
|
|
31
25
|
for (let index = 0; index < length; index += 1) {
|
|
32
26
|
values[index][1].dirty = true;
|
|
33
27
|
}
|
|
34
28
|
|
|
35
|
-
emitValue(
|
|
29
|
+
emitValue(this);
|
|
36
30
|
}
|
|
37
31
|
|
|
38
|
-
export function getReactiveValueInProxy<Value, Result = Value>(
|
|
39
|
-
array: ReactiveArray<Value>,
|
|
40
|
-
mapped: Map<Key, [Computed<unknown>, ComputedEffect]>,
|
|
41
|
-
index: number,
|
|
42
|
-
isArray: true,
|
|
43
|
-
): Computed<Result>;
|
|
44
|
-
|
|
45
|
-
export function getReactiveValueInProxy<Value extends PlainObject>(
|
|
46
|
-
store: ReactiveStore<Value>,
|
|
47
|
-
mapped: Map<Key, [Computed<unknown>, ComputedEffect]>,
|
|
48
|
-
key: Key,
|
|
49
|
-
isArray: false,
|
|
50
|
-
): Computed<unknown>;
|
|
51
|
-
|
|
52
32
|
export function getReactiveValueInProxy(
|
|
53
|
-
|
|
54
|
-
mapped: Map<Key, [Computed<unknown>, ComputedEffect]>,
|
|
33
|
+
instance: ReactiveArray<unknown> | ReactiveStore<unknown>,
|
|
55
34
|
key: Key,
|
|
56
|
-
isArray: boolean,
|
|
57
35
|
): Computed<unknown> {
|
|
58
|
-
|
|
36
|
+
const state = (instance as unknown as InternalProxy)[SYMBOL_STATE];
|
|
37
|
+
|
|
38
|
+
state.mapped ??= new Map();
|
|
39
|
+
|
|
40
|
+
const mapKey = String(key);
|
|
41
|
+
|
|
42
|
+
let item = state.mapped.get(mapKey);
|
|
59
43
|
|
|
60
44
|
if (item == null) {
|
|
61
45
|
item = internalComputed(() =>
|
|
62
|
-
isArray
|
|
63
|
-
? (
|
|
64
|
-
: (
|
|
46
|
+
state.isArray
|
|
47
|
+
? (instance.get() as unknown[]).at(key as number)
|
|
48
|
+
: (instance.get() as PlainObject)[key],
|
|
65
49
|
);
|
|
66
50
|
|
|
67
|
-
mapped.set(
|
|
51
|
+
state.mapped.set(mapKey, item);
|
|
68
52
|
}
|
|
69
53
|
|
|
70
54
|
return item[0];
|
|
71
55
|
}
|
|
72
56
|
|
|
73
|
-
export function
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
):
|
|
83
|
-
|
|
57
|
+
export function getValueInProxy(this: InternalProxy, first?: unknown): unknown {
|
|
58
|
+
if (this[SYMBOL_STATE].isArray ? typeof first === 'number' : isKey(first)) {
|
|
59
|
+
return getReactiveValueInProxy(this as never, first as Key).get();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return getSignalValue.call(this);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function isProxyObject(isArray: boolean, value: unknown): value is ArrayOrPlainObject {
|
|
66
|
+
return value == null || (isArray ? Array.isArray(value) : isPlainObject(value));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function peekValueInProxy(this: InternalProxy, first?: unknown, second?: boolean): unknown {
|
|
70
|
+
const state = this[SYMBOL_STATE];
|
|
71
|
+
|
|
72
|
+
let value: unknown;
|
|
73
|
+
|
|
74
|
+
if (state.isArray ? typeof first === 'number' : isKey(first)) {
|
|
75
|
+
value = state.isArray
|
|
76
|
+
? (state.value as unknown[]).at(first as number)
|
|
77
|
+
: (state.value as PlainObject)[first as Key];
|
|
78
|
+
} else {
|
|
79
|
+
value = state.value;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return peekSignalValue.call([this, value], first === true || second === true);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function setProxyObject(state: ReactiveProxyState, value: unknown): void {
|
|
86
|
+
if (state.isArray) {
|
|
87
|
+
(state.value as unknown[]).splice(
|
|
88
|
+
0,
|
|
89
|
+
(state.value as unknown[]).length,
|
|
90
|
+
...((value ?? []) as unknown[]),
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
startBatch();
|
|
97
|
+
|
|
98
|
+
const actual = (value as Record<string, unknown>) ?? {};
|
|
99
|
+
const proxy = state.value as PlainObject;
|
|
100
|
+
|
|
101
|
+
const proxyKeys = Object.keys(proxy);
|
|
102
|
+
const actualKeys = Object.keys(actual);
|
|
103
|
+
|
|
104
|
+
let {length} = proxyKeys;
|
|
105
|
+
|
|
106
|
+
for (let index = 0; index < length; index += 1) {
|
|
107
|
+
const key = proxyKeys[index];
|
|
108
|
+
|
|
109
|
+
proxy[key] = actualKeys.includes(key) ? actual[key] : undefined;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
length = actualKeys.length;
|
|
113
|
+
|
|
114
|
+
for (let index = 0; index < length; index += 1) {
|
|
115
|
+
const key = actualKeys[index];
|
|
116
|
+
|
|
117
|
+
if (!proxyKeys.includes(key)) {
|
|
118
|
+
const keyedValue = actual[key];
|
|
119
|
+
|
|
120
|
+
proxy[key] = keyedValue;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
stopBatch();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function setProxyProperty(state: ReactiveProxyState, property: unknown, value: unknown): void {
|
|
128
|
+
if (!state.isArray) {
|
|
129
|
+
(state.value as PlainObject)[property as Key] = value;
|
|
130
|
+
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const actual =
|
|
135
|
+
(property as number) < 0
|
|
136
|
+
? (state.value as unknown[]).length + (property as number)
|
|
137
|
+
: (property as number);
|
|
138
|
+
|
|
139
|
+
if (actual > -1) {
|
|
140
|
+
(state.value as unknown[])[actual] = value;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function setProxyValue(this: InternalProxy, first?: unknown, second?: unknown): void {
|
|
145
|
+
const state = this[SYMBOL_STATE] as ReactiveProxyState;
|
|
146
|
+
|
|
147
|
+
if (state.isArray && first === PROPERTY_LENGTH) {
|
|
84
148
|
(state.value as unknown[]).length = second as number;
|
|
85
149
|
|
|
86
150
|
return;
|
|
87
151
|
}
|
|
88
152
|
|
|
89
|
-
if (
|
|
90
|
-
|
|
153
|
+
if (isProxyObject(state.isArray, first)) {
|
|
154
|
+
setProxyObject(state, first);
|
|
91
155
|
|
|
92
156
|
return;
|
|
93
157
|
}
|
|
94
158
|
|
|
95
|
-
const property =
|
|
159
|
+
const property = state.isArray ? typeof first === 'number' : isKey(first);
|
|
96
160
|
|
|
97
|
-
if (
|
|
161
|
+
if (state.isArray && property && Number.isNaN(first)) {
|
|
98
162
|
return;
|
|
99
163
|
}
|
|
100
164
|
|
|
@@ -122,15 +186,15 @@ export function setProxyValue<Value, Item = Value>(
|
|
|
122
186
|
if (property && state.promises!.get(first as Key) === actual) {
|
|
123
187
|
state.promises!.delete(first as Key);
|
|
124
188
|
|
|
125
|
-
|
|
189
|
+
setProxyProperty(state, first, value);
|
|
126
190
|
|
|
127
191
|
return;
|
|
128
192
|
}
|
|
129
193
|
|
|
130
|
-
if (!property &&
|
|
194
|
+
if (!property && isProxyObject(state.isArray, value) && state.promise === actual) {
|
|
131
195
|
state.promise = undefined;
|
|
132
196
|
|
|
133
|
-
|
|
197
|
+
setProxyObject(state, value);
|
|
134
198
|
}
|
|
135
199
|
})
|
|
136
200
|
.catch(() => {
|
|
@@ -141,18 +205,21 @@ export function setProxyValue<Value, Item = Value>(
|
|
|
141
205
|
}
|
|
142
206
|
});
|
|
143
207
|
} else if (property) {
|
|
144
|
-
|
|
145
|
-
} else if (
|
|
146
|
-
|
|
208
|
+
setProxyProperty(state, first, actual);
|
|
209
|
+
} else if (isProxyObject(state.isArray, actual)) {
|
|
210
|
+
setProxyObject(state, actual);
|
|
147
211
|
}
|
|
148
212
|
}
|
|
149
213
|
|
|
150
|
-
export function setValueInProxy
|
|
151
|
-
|
|
214
|
+
export function setValueInProxy(
|
|
215
|
+
instance: InternalProxy,
|
|
216
|
+
target: object,
|
|
217
|
+
property: PropertyKey,
|
|
218
|
+
value: unknown,
|
|
152
219
|
): boolean {
|
|
153
|
-
const
|
|
220
|
+
const state = instance[SYMBOL_STATE];
|
|
154
221
|
|
|
155
|
-
if (isArray) {
|
|
222
|
+
if (state.isArray) {
|
|
156
223
|
const isIndex = !Number.isNaN(Number(property));
|
|
157
224
|
const isLength = property === PROPERTY_LENGTH;
|
|
158
225
|
|
|
@@ -161,17 +228,27 @@ export function setValueInProxy<Value extends ArrayOrPlainObject, Equal>(
|
|
|
161
228
|
}
|
|
162
229
|
}
|
|
163
230
|
|
|
164
|
-
const previous = Reflect.get(target, property);
|
|
231
|
+
const previous = Reflect.get(target as object, property);
|
|
165
232
|
|
|
166
|
-
if (!state.equal(previous as never, value as never)) {
|
|
233
|
+
if (!(state.equal ?? Object.is)(previous as never, value as never)) {
|
|
167
234
|
Reflect.set(target, property, value);
|
|
168
235
|
|
|
169
|
-
emitValue(
|
|
236
|
+
emitValue(instance);
|
|
170
237
|
|
|
171
|
-
if (isArray) {
|
|
172
|
-
length?.set((target as unknown[]).length);
|
|
238
|
+
if (state.isArray) {
|
|
239
|
+
state.length?.set((target as unknown[]).length);
|
|
173
240
|
}
|
|
174
241
|
}
|
|
175
242
|
|
|
176
243
|
return true;
|
|
177
244
|
}
|
|
245
|
+
|
|
246
|
+
export function updateProxyValue(this: InternalProxy, callback: unknown): void {
|
|
247
|
+
if (typeof callback !== 'function') {
|
|
248
|
+
throw new TypeError('Callback must be a function');
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
setProxyValue.call(this, callback(this[SYMBOL_STATE].value));
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// #endregion
|