r-state-tree 0.6.0 → 0.6.1
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/README.md +26 -47
- package/dist/model/ModelAdministration.d.ts +0 -2
- package/dist/observables/array.d.ts +3 -2
- package/dist/r-state-tree.cjs +55 -186
- package/dist/r-state-tree.js +55 -186
- package/package.json +1 -1
- package/dist/computedProxy.d.ts +0 -2
package/README.md
CHANGED
|
@@ -355,66 +355,45 @@ class ListStore extends Store {
|
|
|
355
355
|
- Models: model fields are shallow-reactive, but values are not auto-wrapped. For raw `@state` arrays/objects, prefer **reassignment** (immutability) so snapshots stay up to date. If you want in-place mutation (`push`, `splice`, `set`, etc.) to trigger updates and snapshot invalidation, store an `observable()` container (or `signal()`) in `@state`.
|
|
356
356
|
- Stores: store fields are shallow-reactive. Use `observable()` containers (or `signal()`) when you want in-place mutations of nested values/collections to trigger updates.
|
|
357
357
|
|
|
358
|
-
|
|
358
|
+
### `Observable` base class
|
|
359
359
|
|
|
360
|
-
For
|
|
360
|
+
For class instances that need to be reactive, extending the `Observable` base class is the supported pattern. This ensures compatibility with ES `#private` fields and built-in brand checks because the observable is created in the base constructor, allowing derived field initializers (including `#private`) to run on the observable.
|
|
361
361
|
|
|
362
362
|
```ts
|
|
363
|
-
import {
|
|
363
|
+
import { Observable, effect } from "r-state-tree";
|
|
364
364
|
|
|
365
|
-
class Counter {
|
|
366
|
-
|
|
365
|
+
class Counter extends Observable {
|
|
366
|
+
count = 0; // Public fields are automatically reactive
|
|
367
|
+
#internal = 0; // Private fields also work perfectly
|
|
367
368
|
|
|
368
|
-
|
|
369
|
-
return this.
|
|
369
|
+
get total() {
|
|
370
|
+
return this.count + this.#internal;
|
|
370
371
|
}
|
|
371
372
|
|
|
372
373
|
increment() {
|
|
373
|
-
this.
|
|
374
|
+
this.count++;
|
|
375
|
+
this.#internal++;
|
|
374
376
|
}
|
|
375
377
|
}
|
|
376
378
|
|
|
377
379
|
const counter = new Counter();
|
|
378
380
|
|
|
381
|
+
// Use an effect to track and react to property changes
|
|
379
382
|
effect(() => {
|
|
380
|
-
console.log(
|
|
383
|
+
console.log(`Visible: ${counter.count}, Total: ${counter.total}`);
|
|
381
384
|
});
|
|
382
385
|
|
|
383
|
-
counter.increment(); // Triggers the effect
|
|
384
|
-
```
|
|
385
|
-
|
|
386
|
-
### `Observable` base class
|
|
387
|
-
|
|
388
|
-
For class instances that need to be reactive, extending the `Observable` base class is the supported pattern. This ensures compatibility with ES `#private` fields and built-in brand checks because the Proxy is created in the base constructor, allowing derived field initializers (including `#private`) to run on the Proxy.
|
|
389
|
-
|
|
390
|
-
```ts
|
|
391
|
-
import { Observable, effect } from "r-state-tree";
|
|
392
|
-
|
|
393
|
-
class Counter extends Observable {
|
|
394
|
-
#count = 0; // Correctly works with #private
|
|
395
|
-
|
|
396
|
-
get count() {
|
|
397
|
-
return this.#count;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
increment() {
|
|
401
|
-
this.#count++;
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
const counter = new Counter();
|
|
406
|
-
effect(() => console.log(counter.count));
|
|
407
386
|
counter.increment();
|
|
408
387
|
```
|
|
409
388
|
|
|
410
389
|
> [!IMPORTANT] > **Why `extends Observable`?**
|
|
411
|
-
> ES `#private` fields are brand-checked. If you
|
|
390
|
+
> ES `#private` fields are brand-checked. If you wrap a class instance with `observable()` _after_ it has been created (post-hoc wrapping), or if you return an observable from a standard constructor, the private state is installed on the original `this`, but methods run with the observable as `this`, causing `TypeError: Cannot read private member`.
|
|
412
391
|
>
|
|
413
|
-
> `extends Observable` solves this by returning the
|
|
392
|
+
> `extends Observable` solves this by returning the observable from `super()`, so derived classes initialize their private fields directly on the observable receiver.
|
|
414
393
|
|
|
415
394
|
### Limitations of `observable(instance)`
|
|
416
395
|
|
|
417
|
-
The `observable()` function is selective about what it
|
|
396
|
+
The `observable()` function is selective about what it makes observable. It wraps **supported containers** only:
|
|
418
397
|
|
|
419
398
|
- Plain objects
|
|
420
399
|
- Arrays
|
|
@@ -425,10 +404,10 @@ The `observable()` function is selective about what it proxies. It wraps **suppo
|
|
|
425
404
|
|
|
426
405
|
If you pass an arbitrary class instance, built-in (like `URL`, `RegExp`, `Promise`, or DOM objects), or frozen object to `observable()`, it will **return the object unchanged** and emit a warning in development mode.
|
|
427
406
|
|
|
428
|
-
This design prevents “silent failure” where
|
|
407
|
+
This design prevents “silent failure” where an observable object appears to work but throws `TypeError` when accessing private members or internal slots. For your own classes, use `extends Observable`. For third-party or built-in objects, use composition:
|
|
429
408
|
|
|
430
409
|
```ts
|
|
431
|
-
// ❌ Post-hoc
|
|
410
|
+
// ❌ Post-hoc wrapping - returns raw URL, not an observable
|
|
432
411
|
const url = observable(new URL("..."));
|
|
433
412
|
|
|
434
413
|
// ✅ Composition - wrap a container instead
|
|
@@ -520,19 +499,19 @@ Create reactive structures outside Stores/Models. Supported: Objects, Arrays, Ma
|
|
|
520
499
|
|
|
521
500
|
- Track reads with `effect`/`reaction`. Observables are **shallow**: reads are tracked on the observable container, but nested object mutations do **not** trigger unless you explicitly wrap nested values with `observable()` (or use signals).
|
|
522
501
|
- Access backing values via `source(value)`; check if something is reactive with `isObservable(value)`.
|
|
523
|
-
- Rule of thumb: `source(...)` returns the backing data, **not** a sanitizer—it's only
|
|
502
|
+
- Rule of thumb: `source(...)` returns the backing data, **not** a sanitizer—it's only observable-free if you didn't manually seed observables into the backing source.
|
|
524
503
|
- Arrays: reading specific indices (`arr[i]`) or `length` tracks those; common mutators (`push/pop/shift/unshift/splice/reverse/sort/fill`) are reactive; non-index and symbol keys are not reactive.
|
|
525
504
|
|
|
526
505
|
### `source()` and structuredClone
|
|
527
506
|
|
|
528
|
-
`source(x)` returns the backing value behind an observable
|
|
507
|
+
`source(x)` returns the backing value behind an observable. It is **not** a “observable stripper”.
|
|
529
508
|
|
|
530
509
|
**One-way rule (important):**
|
|
531
510
|
|
|
532
511
|
- If you mutate through the observable wrapper (e.g. `obj.prop = observable(child)`), r-state-tree stores the **raw backing value** in `source(obj).prop` (unwrap-on-write).
|
|
533
|
-
- If you manually mutate backing sources yourself (e.g. `source(obj).prop = observable(child)`), r-state-tree does **not** sanitize or rewrite your data. In that case, `source(...)` may contain
|
|
512
|
+
- If you manually mutate backing sources yourself (e.g. `source(obj).prop = observable(child)`), r-state-tree does **not** sanitize or rewrite your data. In that case, `source(...)` may contain observables.
|
|
534
513
|
|
|
535
|
-
If you need to pass values to APIs that require cloneable data (e.g. `structuredClone`, `postMessage`), avoid seeding
|
|
514
|
+
If you need to pass values to APIs that require cloneable data (e.g. `structuredClone`, `postMessage`), avoid seeding observables into backing sources. Prefer reading via `source(...)` and keep your stored values plain/cloneable.
|
|
536
515
|
|
|
537
516
|
```ts
|
|
538
517
|
import { observable, effect, computed, reaction } from "r-state-tree";
|
|
@@ -586,7 +565,7 @@ state.count++;
|
|
|
586
565
|
Native methods that return copies of a collection—such as `Array.prototype.slice`, `filter`, and `concat`, or `Set.prototype.union` and `intersection`—behave according to the **Explicit Architecture**:
|
|
587
566
|
|
|
588
567
|
- **Raw Return**: The returned container is a plain JavaScript object (raw, non-observable).
|
|
589
|
-
- **Identity Preservation**: Each element in the returned container maintains the same identity it had in the observable source. If an element was
|
|
568
|
+
- **Identity Preservation**: Each element in the returned container maintains the same identity it had in the observable source. If an element was an observable (because it was explicitly owned), it remains an observable in the raw result.
|
|
590
569
|
|
|
591
570
|
This ensures that "derived" state is not automatically made reactive, while still allowing observers to maintain reference stability with existing objects in your state tree.
|
|
592
571
|
|
|
@@ -599,7 +578,7 @@ const sliced = arr.slice();
|
|
|
599
578
|
isObservable(sliced); // false
|
|
600
579
|
|
|
601
580
|
// Identity is preserved
|
|
602
|
-
sliced[0] === item; // true (same
|
|
581
|
+
sliced[0] === item; // true (same observable identity)
|
|
603
582
|
|
|
604
583
|
// If you want the result to be reactive, wrap it explicitly
|
|
605
584
|
const reactiveSlice = observable(arr.slice());
|
|
@@ -634,8 +613,8 @@ tree.user.tags[0] = "superadmin"; // triggers
|
|
|
634
613
|
tree.newProp = { foo: 1 };
|
|
635
614
|
isObservable(tree.newProp); // false — not wrapped
|
|
636
615
|
|
|
637
|
-
// Source is
|
|
638
|
-
// into backing data structures. r-state-tree unwraps
|
|
616
|
+
// Source is observable-free and clonable *as long as you don't manually seed observables*
|
|
617
|
+
// into backing data structures. r-state-tree unwraps observables on writes performed
|
|
639
618
|
// through observable containers, but it does not sanitize user-mutated backing sources.
|
|
640
619
|
const snapshot = structuredClone(source(tree));
|
|
641
620
|
```
|
|
@@ -1127,7 +1106,7 @@ const off = onSnapshot(m, (snap) =>
|
|
|
1127
1106
|
- Forgetting stable keys for `@child` arrays causes identity churn.
|
|
1128
1107
|
- Assuming **deep** reactivity: nested plain objects/arrays are not reactive unless you explicitly wrap them (or use `toObservableTree` for initial hydration).
|
|
1129
1108
|
- Mutating raw `@state` arrays/objects in place (`push`, `obj.x = 1`) and expecting snapshots to update. Snapshots are memoized; use reassignment or store `observable()` containers / `signal()` values in `@state`.
|
|
1130
|
-
- Passing
|
|
1109
|
+
- Passing observables to third‑party APIs that expect cloneable/serializable values (e.g. `structuredClone`). Use `source(value)` to get the backing value. It will be observable-free for values written via r-state-tree’s observable APIs (unwrap-on-write), but `source(...)` is **not** guaranteed observable-free if you manually seed observables into backing sources.
|
|
1131
1110
|
- Creating child stores in constructors: `@child` must be on getters so identity and lifecycle can be managed by the framework.
|
|
1132
1111
|
- Passing `models` into child stores during mount can create a recursive mount loop. If a child needs parent models, create the child store/model inside `storeDidMount` instead of wiring it through `models` during the mount cycle.
|
|
1133
1112
|
|
|
@@ -16,11 +16,9 @@ export declare class ModelAdministration extends PreactObjectAdministration<any>
|
|
|
16
16
|
private modelsTraceUnsub;
|
|
17
17
|
private writeInProgress;
|
|
18
18
|
private computedSnapshot;
|
|
19
|
-
private snapshotAtom;
|
|
20
19
|
private snapshotMap;
|
|
21
20
|
private contextCache;
|
|
22
21
|
parentName: PropertyKey | null;
|
|
23
|
-
private observeSnapshotValue;
|
|
24
22
|
get parent(): ModelAdministration | null;
|
|
25
23
|
set parent(value: ModelAdministration | null);
|
|
26
24
|
setConfiguration(configurationGetter: () => ModelConfiguration<any>): void;
|
|
@@ -4,8 +4,9 @@ import { SignalMap } from "./internal/NodeMap";
|
|
|
4
4
|
export declare class ArrayAdministration<T> extends Administration<T[]> {
|
|
5
5
|
valuesMap: SignalMap<number>;
|
|
6
6
|
keysAtom: AtomNode;
|
|
7
|
-
private
|
|
8
|
-
private
|
|
7
|
+
private observableSources;
|
|
8
|
+
private rawSources;
|
|
9
|
+
private trackValue;
|
|
9
10
|
static proxyTraps: ProxyHandler<Array<unknown>>;
|
|
10
11
|
static methods: Partial<{
|
|
11
12
|
[K in keyof typeof Array.prototype as (typeof Array.prototype)[K] extends Function ? K : never]: (typeof Array.prototype)[K];
|
package/dist/r-state-tree.cjs
CHANGED
|
@@ -315,9 +315,7 @@ class ObjectAdministration extends Administration {
|
|
|
315
315
|
return Reflect.get(this.source, key, this.proxy);
|
|
316
316
|
}
|
|
317
317
|
set(key, value) {
|
|
318
|
-
return signalsCore.batch(() =>
|
|
319
|
-
return Reflect.set(this.source, key, value, this.proxy);
|
|
320
|
-
});
|
|
318
|
+
return signalsCore.batch(() => Reflect.set(this.source, key, value, this.proxy));
|
|
321
319
|
}
|
|
322
320
|
getComputed(key) {
|
|
323
321
|
if (!this.computedMap) this.computedMap = /* @__PURE__ */ new Map();
|
|
@@ -683,17 +681,7 @@ class CollectionAdministration extends Administration {
|
|
|
683
681
|
return collectionMethods[name];
|
|
684
682
|
}
|
|
685
683
|
if (typeof val === "function") {
|
|
686
|
-
return
|
|
687
|
-
if (process.env.NODE_ENV !== "production") {
|
|
688
|
-
console.warn(
|
|
689
|
-
`r-state-tree: Calling uninstrumented collection method "${String(
|
|
690
|
-
name
|
|
691
|
-
)}". Reactivity is not guaranteed for this call.`
|
|
692
|
-
);
|
|
693
|
-
}
|
|
694
|
-
const result = val.apply(adm.source, arguments);
|
|
695
|
-
return result === adm.source ? adm.proxy : result;
|
|
696
|
-
};
|
|
684
|
+
return val;
|
|
697
685
|
}
|
|
698
686
|
return val;
|
|
699
687
|
}
|
|
@@ -819,9 +807,6 @@ class CollectionAdministration extends Administration {
|
|
|
819
807
|
const target = getSource(value);
|
|
820
808
|
if (isObservable(value)) {
|
|
821
809
|
this.trackExplicitObservable(target);
|
|
822
|
-
} else {
|
|
823
|
-
this.untrackExplicitObservable(target);
|
|
824
|
-
this.untrackExplicitObservable(value);
|
|
825
810
|
}
|
|
826
811
|
if (!this.hasEntry(value)) {
|
|
827
812
|
this.source.add(target);
|
|
@@ -1054,15 +1039,40 @@ function isArrayIndexKey(key) {
|
|
|
1054
1039
|
return Number.isInteger(num) && num >= 0 && num < 4294967295 && // 2^32 - 1
|
|
1055
1040
|
String(num) === keyStr;
|
|
1056
1041
|
}
|
|
1042
|
+
function reportConflict() {
|
|
1043
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1044
|
+
throw new Error(
|
|
1045
|
+
"r-state-tree: Cannot assign the same object as both observable and raw source in the same array. The value will be treated as observable."
|
|
1046
|
+
);
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1057
1049
|
class ArrayAdministration extends Administration {
|
|
1058
1050
|
valuesMap;
|
|
1059
1051
|
keysAtom;
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1052
|
+
/**
|
|
1053
|
+
* Parent-based ownership tracking: sources assigned as observable.
|
|
1054
|
+
* Unlike index-based tracking, this doesn't require updates on reorder ops.
|
|
1055
|
+
*/
|
|
1056
|
+
observableSources = /* @__PURE__ */ new WeakSet();
|
|
1057
|
+
rawSources = /* @__PURE__ */ new WeakSet();
|
|
1058
|
+
/**
|
|
1059
|
+
* Track a value being assigned to this array.
|
|
1060
|
+
* Detects conflicts if same source is assigned as both observable and raw.
|
|
1061
|
+
*/
|
|
1062
|
+
trackValue(value) {
|
|
1063
|
+
if (value && typeof value === "object") {
|
|
1064
|
+
const source2 = getSource(value);
|
|
1064
1065
|
if (isObservable(value)) {
|
|
1065
|
-
this.
|
|
1066
|
+
if (this.rawSources.has(source2)) {
|
|
1067
|
+
reportConflict();
|
|
1068
|
+
}
|
|
1069
|
+
this.observableSources.add(source2);
|
|
1070
|
+
} else {
|
|
1071
|
+
if (this.observableSources.has(source2)) {
|
|
1072
|
+
reportConflict();
|
|
1073
|
+
} else {
|
|
1074
|
+
this.rawSources.add(source2);
|
|
1075
|
+
}
|
|
1066
1076
|
}
|
|
1067
1077
|
}
|
|
1068
1078
|
}
|
|
@@ -1119,7 +1129,6 @@ class ArrayAdministration extends Administration {
|
|
|
1119
1129
|
if (result && had && isIndex) {
|
|
1120
1130
|
const index = Number(name);
|
|
1121
1131
|
adm.onArrayChanged(true, index, 1);
|
|
1122
|
-
adm.explicitObservables.delete(index);
|
|
1123
1132
|
}
|
|
1124
1133
|
return result;
|
|
1125
1134
|
},
|
|
@@ -1145,16 +1154,12 @@ class ArrayAdministration extends Administration {
|
|
|
1145
1154
|
static methods = {
|
|
1146
1155
|
fill(value, start, end) {
|
|
1147
1156
|
const adm = getAdministration(this);
|
|
1148
|
-
|
|
1157
|
+
adm.trackValue(value);
|
|
1149
1158
|
const targetValue = getSource(value);
|
|
1150
1159
|
adm.source.fill(targetValue, start, end);
|
|
1151
1160
|
const length = adm.source.length;
|
|
1152
1161
|
const from = start == null ? 0 : start < 0 ? Math.max(length + start, 0) : start;
|
|
1153
1162
|
const to = end == null ? length : end < 0 ? Math.max(length + end, 0) : Math.min(end, length);
|
|
1154
|
-
for (let i = from; i < to; i++) {
|
|
1155
|
-
if (shouldTrack) adm.explicitObservables.add(i);
|
|
1156
|
-
else adm.explicitObservables.delete(i);
|
|
1157
|
-
}
|
|
1158
1163
|
if (from < to) {
|
|
1159
1164
|
adm.onArrayChanged(false, from, to - from);
|
|
1160
1165
|
}
|
|
@@ -1193,41 +1198,24 @@ class ArrayAdministration extends Administration {
|
|
|
1193
1198
|
},
|
|
1194
1199
|
reverse() {
|
|
1195
1200
|
const adm = getAdministration(this);
|
|
1196
|
-
adm.syncExplicitObservablesFromSource();
|
|
1197
|
-
const flags = new Array(adm.source.length);
|
|
1198
|
-
for (let i = 0; i < flags.length; i++) {
|
|
1199
|
-
flags[i] = adm.explicitObservables.has(i);
|
|
1200
|
-
}
|
|
1201
1201
|
adm.source.reverse();
|
|
1202
|
-
flags.reverse();
|
|
1203
|
-
adm.explicitObservables.clear();
|
|
1204
|
-
for (let i = 0; i < flags.length; i++) {
|
|
1205
|
-
if (flags[i]) adm.explicitObservables.add(i);
|
|
1206
|
-
}
|
|
1207
1202
|
adm.onArrayChanged(false, 0, adm.source.length);
|
|
1208
1203
|
return this;
|
|
1209
1204
|
},
|
|
1210
1205
|
sort(compareFn) {
|
|
1211
1206
|
const adm = getAdministration(this);
|
|
1212
|
-
adm.
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
value: this[i],
|
|
1217
|
-
stored: adm.source[i],
|
|
1218
|
-
observed: adm.explicitObservables.has(i)
|
|
1219
|
-
};
|
|
1220
|
-
}
|
|
1207
|
+
const pairs = adm.source.map((stored, i) => ({
|
|
1208
|
+
value: this[i],
|
|
1209
|
+
stored
|
|
1210
|
+
}));
|
|
1221
1211
|
const comparator = compareFn ?? ((a, b) => {
|
|
1222
1212
|
const as = String(a);
|
|
1223
1213
|
const bs = String(b);
|
|
1224
1214
|
return as < bs ? -1 : as > bs ? 1 : 0;
|
|
1225
1215
|
});
|
|
1226
1216
|
pairs.sort((a, b) => comparator(a.value, b.value));
|
|
1227
|
-
adm.explicitObservables.clear();
|
|
1228
1217
|
for (let i = 0; i < pairs.length; i++) {
|
|
1229
1218
|
adm.source[i] = pairs[i].stored;
|
|
1230
|
-
if (pairs[i].observed) adm.explicitObservables.add(i);
|
|
1231
1219
|
}
|
|
1232
1220
|
adm.onArrayChanged(false, 0, adm.source.length);
|
|
1233
1221
|
return this;
|
|
@@ -1243,17 +1231,7 @@ class ArrayAdministration extends Administration {
|
|
|
1243
1231
|
flat: createCopyMethod("flat"),
|
|
1244
1232
|
copyWithin(target, start, end) {
|
|
1245
1233
|
const adm = getAdministration(this);
|
|
1246
|
-
adm.syncExplicitObservablesFromSource();
|
|
1247
|
-
const flags = new Array(adm.source.length);
|
|
1248
|
-
for (let i = 0; i < flags.length; i++) {
|
|
1249
|
-
flags[i] = adm.explicitObservables.has(i);
|
|
1250
|
-
}
|
|
1251
1234
|
adm.source.copyWithin(target, start, end);
|
|
1252
|
-
flags.copyWithin(target, start, end);
|
|
1253
|
-
adm.explicitObservables.clear();
|
|
1254
|
-
for (let i = 0; i < flags.length; i++) {
|
|
1255
|
-
if (flags[i]) adm.explicitObservables.add(i);
|
|
1256
|
-
}
|
|
1257
1235
|
adm.onArrayChanged(false, 0, adm.source.length);
|
|
1258
1236
|
return this;
|
|
1259
1237
|
},
|
|
@@ -1287,23 +1265,20 @@ class ArrayAdministration extends Administration {
|
|
|
1287
1265
|
_getEffectiveValue(index) {
|
|
1288
1266
|
const value = this.source[index];
|
|
1289
1267
|
if (value && typeof value === "object" && !Object.isFrozen(value)) {
|
|
1290
|
-
if (this.
|
|
1291
|
-
const
|
|
1292
|
-
if (
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
if (
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
);
|
|
1300
|
-
}
|
|
1301
|
-
this.explicitObservables.delete(index);
|
|
1302
|
-
return value;
|
|
1268
|
+
if (this.observableSources.has(value)) {
|
|
1269
|
+
const adm = getAdministration(value);
|
|
1270
|
+
if (adm.proxy !== value) {
|
|
1271
|
+
const desc = Object.getOwnPropertyDescriptor(this.source, index);
|
|
1272
|
+
if (desc && !desc.configurable && !desc.writable) {
|
|
1273
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1274
|
+
console.warn(
|
|
1275
|
+
`r-state-tree: cannot return an observable proxy for arr[${index}] because it is a non-configurable, non-writable data property; returning the raw value to uphold Proxy invariants.`
|
|
1276
|
+
);
|
|
1303
1277
|
}
|
|
1278
|
+
return value;
|
|
1304
1279
|
}
|
|
1305
|
-
return existingAdm.proxy;
|
|
1306
1280
|
}
|
|
1281
|
+
return adm.proxy;
|
|
1307
1282
|
}
|
|
1308
1283
|
}
|
|
1309
1284
|
return value;
|
|
@@ -1312,23 +1287,17 @@ class ArrayAdministration extends Administration {
|
|
|
1312
1287
|
const values = this.source;
|
|
1313
1288
|
const targetValue = getSource(newValue);
|
|
1314
1289
|
const oldLength = values.length;
|
|
1290
|
+
this.trackValue(newValue);
|
|
1315
1291
|
let changed = true;
|
|
1316
1292
|
if (index < oldLength) {
|
|
1317
1293
|
const oldValue = values[index];
|
|
1318
|
-
|
|
1319
|
-
const newExplicit = isObservable(newValue);
|
|
1320
|
-
changed = !isObservable(oldValue) && oldExplicit !== newExplicit || (isObservable(oldValue) ? newValue !== oldValue : targetValue !== oldValue);
|
|
1294
|
+
changed = targetValue !== oldValue;
|
|
1321
1295
|
}
|
|
1322
1296
|
if (!changed) return true;
|
|
1323
1297
|
const result = Reflect.set(values, index, targetValue);
|
|
1324
1298
|
if (!result) return false;
|
|
1325
1299
|
const newLength = values.length;
|
|
1326
1300
|
const lengthChanged = newLength !== oldLength;
|
|
1327
|
-
if (isObservable(newValue)) {
|
|
1328
|
-
this.explicitObservables.add(index);
|
|
1329
|
-
} else {
|
|
1330
|
-
this.explicitObservables.delete(index);
|
|
1331
|
-
}
|
|
1332
1301
|
this.onArrayChanged(lengthChanged, index, 1);
|
|
1333
1302
|
return true;
|
|
1334
1303
|
}
|
|
@@ -1349,15 +1318,6 @@ class ArrayAdministration extends Administration {
|
|
|
1349
1318
|
const result = Reflect.set(this.source, "length", newLength);
|
|
1350
1319
|
if (!result) return false;
|
|
1351
1320
|
if (newLength < currentLength) {
|
|
1352
|
-
const toRemove = [];
|
|
1353
|
-
for (const index of this.explicitObservables) {
|
|
1354
|
-
if (index >= newLength) {
|
|
1355
|
-
toRemove.push(index);
|
|
1356
|
-
}
|
|
1357
|
-
}
|
|
1358
|
-
for (const index of toRemove) {
|
|
1359
|
-
this.explicitObservables.delete(index);
|
|
1360
|
-
}
|
|
1361
1321
|
this.onArrayChanged(true, newLength, currentLength - newLength);
|
|
1362
1322
|
} else {
|
|
1363
1323
|
this.onArrayChanged(true, currentLength, newLength - currentLength);
|
|
@@ -1367,13 +1327,10 @@ class ArrayAdministration extends Administration {
|
|
|
1367
1327
|
spliceWithArray(index, deleteCount, newItems) {
|
|
1368
1328
|
const length = this.source.length;
|
|
1369
1329
|
const newTargetItems = [];
|
|
1370
|
-
const newObservableIndices = [];
|
|
1371
1330
|
if (newItems) {
|
|
1372
1331
|
for (let i = 0; i < newItems.length; i++) {
|
|
1373
1332
|
newTargetItems[i] = getSource(newItems[i]);
|
|
1374
|
-
|
|
1375
|
-
newObservableIndices.push(i);
|
|
1376
|
-
}
|
|
1333
|
+
this.trackValue(newItems[i]);
|
|
1377
1334
|
}
|
|
1378
1335
|
}
|
|
1379
1336
|
if (index === void 0) index = 0;
|
|
@@ -1386,31 +1343,10 @@ class ArrayAdministration extends Administration {
|
|
|
1386
1343
|
for (let i = index; i < index + deleteCount; i++) {
|
|
1387
1344
|
removedItems.push(this._getEffectiveValue(i));
|
|
1388
1345
|
}
|
|
1389
|
-
for (let i = index; i < index + deleteCount; i++) {
|
|
1390
|
-
this.explicitObservables.delete(i);
|
|
1391
|
-
}
|
|
1392
|
-
const shift = (newItems?.length ?? 0) - deleteCount;
|
|
1393
|
-
if (shift !== 0) {
|
|
1394
|
-
const newExplicitObservables = /* @__PURE__ */ new Set();
|
|
1395
|
-
for (const idx of this.explicitObservables) {
|
|
1396
|
-
if (idx < index) {
|
|
1397
|
-
newExplicitObservables.add(idx);
|
|
1398
|
-
} else if (idx >= index + deleteCount) {
|
|
1399
|
-
newExplicitObservables.add(idx + shift);
|
|
1400
|
-
}
|
|
1401
|
-
}
|
|
1402
|
-
this.explicitObservables.clear();
|
|
1403
|
-
for (const idx of newExplicitObservables) {
|
|
1404
|
-
this.explicitObservables.add(idx);
|
|
1405
|
-
}
|
|
1406
|
-
}
|
|
1407
|
-
for (const relativeIdx of newObservableIndices) {
|
|
1408
|
-
this.explicitObservables.add(index + relativeIdx);
|
|
1409
|
-
}
|
|
1410
1346
|
this.spliceItemsIntoValues(index, deleteCount, newTargetItems);
|
|
1411
1347
|
if (deleteCount !== 0 || newTargetItems.length !== 0) {
|
|
1412
|
-
const
|
|
1413
|
-
const reindexing =
|
|
1348
|
+
const shift = (newItems?.length ?? 0) - deleteCount;
|
|
1349
|
+
const reindexing = shift !== 0 && index + deleteCount < length;
|
|
1414
1350
|
const count = reindexing ? Number.POSITIVE_INFINITY : Math.max(deleteCount ?? 0, newItems?.length ?? 0);
|
|
1415
1351
|
this.onArrayChanged(length !== this.source.length, index, count);
|
|
1416
1352
|
}
|
|
@@ -2437,19 +2373,7 @@ function getIdKey(Ctor) {
|
|
|
2437
2373
|
function getModelRefSnapshot(modelRef2) {
|
|
2438
2374
|
const Ctor = Object.getPrototypeOf(modelRef2).constructor;
|
|
2439
2375
|
const idKey = getIdKey(Ctor);
|
|
2440
|
-
|
|
2441
|
-
let id2 = getIdentifier(modelRef2);
|
|
2442
|
-
if (id2 === void 0) {
|
|
2443
|
-
const source2 = getSource(modelRef2);
|
|
2444
|
-
id2 = getIdentifier(source2);
|
|
2445
|
-
if (id2 === void 0) {
|
|
2446
|
-
const adm = getAdministration(modelRef2);
|
|
2447
|
-
if (adm && adm.proxy !== modelRef2) {
|
|
2448
|
-
id2 = getIdentifier(adm.proxy);
|
|
2449
|
-
}
|
|
2450
|
-
}
|
|
2451
|
-
}
|
|
2452
|
-
return { [idKey]: id2 };
|
|
2376
|
+
return idKey ? { [idKey]: getIdentifier(modelRef2) } : null;
|
|
2453
2377
|
}
|
|
2454
2378
|
function getSnapshotId(snapshot, Ctor) {
|
|
2455
2379
|
const idKey = getIdKey(Ctor);
|
|
@@ -2573,60 +2497,9 @@ class ModelAdministration extends PreactObjectAdministration {
|
|
|
2573
2497
|
modelsTraceUnsub = /* @__PURE__ */ new Map();
|
|
2574
2498
|
writeInProgress = /* @__PURE__ */ new Set();
|
|
2575
2499
|
computedSnapshot;
|
|
2576
|
-
snapshotAtom = createAtom();
|
|
2577
2500
|
snapshotMap = /* @__PURE__ */ new Map();
|
|
2578
2501
|
contextCache = /* @__PURE__ */ new Map();
|
|
2579
2502
|
parentName = null;
|
|
2580
|
-
/**
|
|
2581
|
-
* `@state` fields are shallow-reactive (property-level assignment triggers reactivity)
|
|
2582
|
-
* and participate in snapshots. Values stored in `@state` are not deep-wrapped.
|
|
2583
|
-
*
|
|
2584
|
-
* This helper walks a value and:
|
|
2585
|
-
* - observes any observable containers found (proxy or source) so in-place mutations
|
|
2586
|
-
* invalidate `getSnapshot()` / `toSnapshot()`
|
|
2587
|
-
* - avoids proxy traversal by preferring `getSource(...)`
|
|
2588
|
-
* - guards against cycles via `WeakSet`
|
|
2589
|
-
*/
|
|
2590
|
-
observeSnapshotValue(value, seen) {
|
|
2591
|
-
if (value == null) return;
|
|
2592
|
-
if (typeof value !== "object") return;
|
|
2593
|
-
if (!seen) seen = /* @__PURE__ */ new WeakSet();
|
|
2594
|
-
const obj = value;
|
|
2595
|
-
if (seen.has(obj)) return;
|
|
2596
|
-
seen.add(obj);
|
|
2597
|
-
const adm = getAdministration(obj);
|
|
2598
|
-
if (adm) {
|
|
2599
|
-
adm.reportObserved();
|
|
2600
|
-
}
|
|
2601
|
-
const src = getSource(value);
|
|
2602
|
-
if (src && typeof src === "object" && src !== value) {
|
|
2603
|
-
this.observeSnapshotValue(src, seen);
|
|
2604
|
-
return;
|
|
2605
|
-
}
|
|
2606
|
-
if (Array.isArray(value)) {
|
|
2607
|
-
for (let i = 0; i < value.length; i++) {
|
|
2608
|
-
this.observeSnapshotValue(value[i], seen);
|
|
2609
|
-
}
|
|
2610
|
-
return;
|
|
2611
|
-
}
|
|
2612
|
-
if (value instanceof Map) {
|
|
2613
|
-
value.forEach((v, k) => {
|
|
2614
|
-
this.observeSnapshotValue(k, seen);
|
|
2615
|
-
this.observeSnapshotValue(v, seen);
|
|
2616
|
-
});
|
|
2617
|
-
return;
|
|
2618
|
-
}
|
|
2619
|
-
if (value instanceof Set) {
|
|
2620
|
-
value.forEach((v) => this.observeSnapshotValue(v, seen));
|
|
2621
|
-
return;
|
|
2622
|
-
}
|
|
2623
|
-
if (value instanceof Date) {
|
|
2624
|
-
return;
|
|
2625
|
-
}
|
|
2626
|
-
for (const key of Object.keys(value)) {
|
|
2627
|
-
this.observeSnapshotValue(value[key], seen);
|
|
2628
|
-
}
|
|
2629
|
-
}
|
|
2630
2503
|
get parent() {
|
|
2631
2504
|
this.parentAtom.reportObserved();
|
|
2632
2505
|
return this._parent;
|
|
@@ -2662,7 +2535,6 @@ class ModelAdministration extends PreactObjectAdministration {
|
|
|
2662
2535
|
value,
|
|
2663
2536
|
this.proxy
|
|
2664
2537
|
);
|
|
2665
|
-
this.snapshotAtom.reportChanged();
|
|
2666
2538
|
});
|
|
2667
2539
|
}
|
|
2668
2540
|
}
|
|
@@ -2858,9 +2730,7 @@ class ModelAdministration extends PreactObjectAdministration {
|
|
|
2858
2730
|
return Object.keys(this.configuration).reduce((json, key) => {
|
|
2859
2731
|
switch (this.configuration[key].type) {
|
|
2860
2732
|
case ModelCfgTypes.state: {
|
|
2861
|
-
|
|
2862
|
-
this.observeSnapshotValue(value);
|
|
2863
|
-
json[key] = clone(getSource(value), key);
|
|
2733
|
+
json[key] = clone(this.proxy[key], key);
|
|
2864
2734
|
break;
|
|
2865
2735
|
}
|
|
2866
2736
|
case ModelCfgTypes.id:
|
|
@@ -3003,7 +2873,6 @@ class ModelAdministration extends PreactObjectAdministration {
|
|
|
3003
2873
|
getSnapshot() {
|
|
3004
2874
|
if (!this.computedSnapshot) {
|
|
3005
2875
|
this.computedSnapshot = createComputed(() => {
|
|
3006
|
-
this.snapshotAtom.reportObserved();
|
|
3007
2876
|
const json = this.toJSON();
|
|
3008
2877
|
configMap.set(json, this.configuration);
|
|
3009
2878
|
return json;
|
package/dist/r-state-tree.js
CHANGED
|
@@ -314,9 +314,7 @@ class ObjectAdministration extends Administration {
|
|
|
314
314
|
return Reflect.get(this.source, key, this.proxy);
|
|
315
315
|
}
|
|
316
316
|
set(key, value) {
|
|
317
|
-
return batch(() =>
|
|
318
|
-
return Reflect.set(this.source, key, value, this.proxy);
|
|
319
|
-
});
|
|
317
|
+
return batch(() => Reflect.set(this.source, key, value, this.proxy));
|
|
320
318
|
}
|
|
321
319
|
getComputed(key) {
|
|
322
320
|
if (!this.computedMap) this.computedMap = /* @__PURE__ */ new Map();
|
|
@@ -682,17 +680,7 @@ class CollectionAdministration extends Administration {
|
|
|
682
680
|
return collectionMethods[name];
|
|
683
681
|
}
|
|
684
682
|
if (typeof val === "function") {
|
|
685
|
-
return
|
|
686
|
-
if (process.env.NODE_ENV !== "production") {
|
|
687
|
-
console.warn(
|
|
688
|
-
`r-state-tree: Calling uninstrumented collection method "${String(
|
|
689
|
-
name
|
|
690
|
-
)}". Reactivity is not guaranteed for this call.`
|
|
691
|
-
);
|
|
692
|
-
}
|
|
693
|
-
const result = val.apply(adm.source, arguments);
|
|
694
|
-
return result === adm.source ? adm.proxy : result;
|
|
695
|
-
};
|
|
683
|
+
return val;
|
|
696
684
|
}
|
|
697
685
|
return val;
|
|
698
686
|
}
|
|
@@ -818,9 +806,6 @@ class CollectionAdministration extends Administration {
|
|
|
818
806
|
const target = getSource(value);
|
|
819
807
|
if (isObservable(value)) {
|
|
820
808
|
this.trackExplicitObservable(target);
|
|
821
|
-
} else {
|
|
822
|
-
this.untrackExplicitObservable(target);
|
|
823
|
-
this.untrackExplicitObservable(value);
|
|
824
809
|
}
|
|
825
810
|
if (!this.hasEntry(value)) {
|
|
826
811
|
this.source.add(target);
|
|
@@ -1053,15 +1038,40 @@ function isArrayIndexKey(key) {
|
|
|
1053
1038
|
return Number.isInteger(num) && num >= 0 && num < 4294967295 && // 2^32 - 1
|
|
1054
1039
|
String(num) === keyStr;
|
|
1055
1040
|
}
|
|
1041
|
+
function reportConflict() {
|
|
1042
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1043
|
+
throw new Error(
|
|
1044
|
+
"r-state-tree: Cannot assign the same object as both observable and raw source in the same array. The value will be treated as observable."
|
|
1045
|
+
);
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1056
1048
|
class ArrayAdministration extends Administration {
|
|
1057
1049
|
valuesMap;
|
|
1058
1050
|
keysAtom;
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1051
|
+
/**
|
|
1052
|
+
* Parent-based ownership tracking: sources assigned as observable.
|
|
1053
|
+
* Unlike index-based tracking, this doesn't require updates on reorder ops.
|
|
1054
|
+
*/
|
|
1055
|
+
observableSources = /* @__PURE__ */ new WeakSet();
|
|
1056
|
+
rawSources = /* @__PURE__ */ new WeakSet();
|
|
1057
|
+
/**
|
|
1058
|
+
* Track a value being assigned to this array.
|
|
1059
|
+
* Detects conflicts if same source is assigned as both observable and raw.
|
|
1060
|
+
*/
|
|
1061
|
+
trackValue(value) {
|
|
1062
|
+
if (value && typeof value === "object") {
|
|
1063
|
+
const source2 = getSource(value);
|
|
1063
1064
|
if (isObservable(value)) {
|
|
1064
|
-
this.
|
|
1065
|
+
if (this.rawSources.has(source2)) {
|
|
1066
|
+
reportConflict();
|
|
1067
|
+
}
|
|
1068
|
+
this.observableSources.add(source2);
|
|
1069
|
+
} else {
|
|
1070
|
+
if (this.observableSources.has(source2)) {
|
|
1071
|
+
reportConflict();
|
|
1072
|
+
} else {
|
|
1073
|
+
this.rawSources.add(source2);
|
|
1074
|
+
}
|
|
1065
1075
|
}
|
|
1066
1076
|
}
|
|
1067
1077
|
}
|
|
@@ -1118,7 +1128,6 @@ class ArrayAdministration extends Administration {
|
|
|
1118
1128
|
if (result && had && isIndex) {
|
|
1119
1129
|
const index = Number(name);
|
|
1120
1130
|
adm.onArrayChanged(true, index, 1);
|
|
1121
|
-
adm.explicitObservables.delete(index);
|
|
1122
1131
|
}
|
|
1123
1132
|
return result;
|
|
1124
1133
|
},
|
|
@@ -1144,16 +1153,12 @@ class ArrayAdministration extends Administration {
|
|
|
1144
1153
|
static methods = {
|
|
1145
1154
|
fill(value, start, end) {
|
|
1146
1155
|
const adm = getAdministration(this);
|
|
1147
|
-
|
|
1156
|
+
adm.trackValue(value);
|
|
1148
1157
|
const targetValue = getSource(value);
|
|
1149
1158
|
adm.source.fill(targetValue, start, end);
|
|
1150
1159
|
const length = adm.source.length;
|
|
1151
1160
|
const from = start == null ? 0 : start < 0 ? Math.max(length + start, 0) : start;
|
|
1152
1161
|
const to = end == null ? length : end < 0 ? Math.max(length + end, 0) : Math.min(end, length);
|
|
1153
|
-
for (let i = from; i < to; i++) {
|
|
1154
|
-
if (shouldTrack) adm.explicitObservables.add(i);
|
|
1155
|
-
else adm.explicitObservables.delete(i);
|
|
1156
|
-
}
|
|
1157
1162
|
if (from < to) {
|
|
1158
1163
|
adm.onArrayChanged(false, from, to - from);
|
|
1159
1164
|
}
|
|
@@ -1192,41 +1197,24 @@ class ArrayAdministration extends Administration {
|
|
|
1192
1197
|
},
|
|
1193
1198
|
reverse() {
|
|
1194
1199
|
const adm = getAdministration(this);
|
|
1195
|
-
adm.syncExplicitObservablesFromSource();
|
|
1196
|
-
const flags = new Array(adm.source.length);
|
|
1197
|
-
for (let i = 0; i < flags.length; i++) {
|
|
1198
|
-
flags[i] = adm.explicitObservables.has(i);
|
|
1199
|
-
}
|
|
1200
1200
|
adm.source.reverse();
|
|
1201
|
-
flags.reverse();
|
|
1202
|
-
adm.explicitObservables.clear();
|
|
1203
|
-
for (let i = 0; i < flags.length; i++) {
|
|
1204
|
-
if (flags[i]) adm.explicitObservables.add(i);
|
|
1205
|
-
}
|
|
1206
1201
|
adm.onArrayChanged(false, 0, adm.source.length);
|
|
1207
1202
|
return this;
|
|
1208
1203
|
},
|
|
1209
1204
|
sort(compareFn) {
|
|
1210
1205
|
const adm = getAdministration(this);
|
|
1211
|
-
adm.
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
value: this[i],
|
|
1216
|
-
stored: adm.source[i],
|
|
1217
|
-
observed: adm.explicitObservables.has(i)
|
|
1218
|
-
};
|
|
1219
|
-
}
|
|
1206
|
+
const pairs = adm.source.map((stored, i) => ({
|
|
1207
|
+
value: this[i],
|
|
1208
|
+
stored
|
|
1209
|
+
}));
|
|
1220
1210
|
const comparator = compareFn ?? ((a, b) => {
|
|
1221
1211
|
const as = String(a);
|
|
1222
1212
|
const bs = String(b);
|
|
1223
1213
|
return as < bs ? -1 : as > bs ? 1 : 0;
|
|
1224
1214
|
});
|
|
1225
1215
|
pairs.sort((a, b) => comparator(a.value, b.value));
|
|
1226
|
-
adm.explicitObservables.clear();
|
|
1227
1216
|
for (let i = 0; i < pairs.length; i++) {
|
|
1228
1217
|
adm.source[i] = pairs[i].stored;
|
|
1229
|
-
if (pairs[i].observed) adm.explicitObservables.add(i);
|
|
1230
1218
|
}
|
|
1231
1219
|
adm.onArrayChanged(false, 0, adm.source.length);
|
|
1232
1220
|
return this;
|
|
@@ -1242,17 +1230,7 @@ class ArrayAdministration extends Administration {
|
|
|
1242
1230
|
flat: createCopyMethod("flat"),
|
|
1243
1231
|
copyWithin(target, start, end) {
|
|
1244
1232
|
const adm = getAdministration(this);
|
|
1245
|
-
adm.syncExplicitObservablesFromSource();
|
|
1246
|
-
const flags = new Array(adm.source.length);
|
|
1247
|
-
for (let i = 0; i < flags.length; i++) {
|
|
1248
|
-
flags[i] = adm.explicitObservables.has(i);
|
|
1249
|
-
}
|
|
1250
1233
|
adm.source.copyWithin(target, start, end);
|
|
1251
|
-
flags.copyWithin(target, start, end);
|
|
1252
|
-
adm.explicitObservables.clear();
|
|
1253
|
-
for (let i = 0; i < flags.length; i++) {
|
|
1254
|
-
if (flags[i]) adm.explicitObservables.add(i);
|
|
1255
|
-
}
|
|
1256
1234
|
adm.onArrayChanged(false, 0, adm.source.length);
|
|
1257
1235
|
return this;
|
|
1258
1236
|
},
|
|
@@ -1286,23 +1264,20 @@ class ArrayAdministration extends Administration {
|
|
|
1286
1264
|
_getEffectiveValue(index) {
|
|
1287
1265
|
const value = this.source[index];
|
|
1288
1266
|
if (value && typeof value === "object" && !Object.isFrozen(value)) {
|
|
1289
|
-
if (this.
|
|
1290
|
-
const
|
|
1291
|
-
if (
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
if (
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
);
|
|
1299
|
-
}
|
|
1300
|
-
this.explicitObservables.delete(index);
|
|
1301
|
-
return value;
|
|
1267
|
+
if (this.observableSources.has(value)) {
|
|
1268
|
+
const adm = getAdministration(value);
|
|
1269
|
+
if (adm.proxy !== value) {
|
|
1270
|
+
const desc = Object.getOwnPropertyDescriptor(this.source, index);
|
|
1271
|
+
if (desc && !desc.configurable && !desc.writable) {
|
|
1272
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1273
|
+
console.warn(
|
|
1274
|
+
`r-state-tree: cannot return an observable proxy for arr[${index}] because it is a non-configurable, non-writable data property; returning the raw value to uphold Proxy invariants.`
|
|
1275
|
+
);
|
|
1302
1276
|
}
|
|
1277
|
+
return value;
|
|
1303
1278
|
}
|
|
1304
|
-
return existingAdm.proxy;
|
|
1305
1279
|
}
|
|
1280
|
+
return adm.proxy;
|
|
1306
1281
|
}
|
|
1307
1282
|
}
|
|
1308
1283
|
return value;
|
|
@@ -1311,23 +1286,17 @@ class ArrayAdministration extends Administration {
|
|
|
1311
1286
|
const values = this.source;
|
|
1312
1287
|
const targetValue = getSource(newValue);
|
|
1313
1288
|
const oldLength = values.length;
|
|
1289
|
+
this.trackValue(newValue);
|
|
1314
1290
|
let changed = true;
|
|
1315
1291
|
if (index < oldLength) {
|
|
1316
1292
|
const oldValue = values[index];
|
|
1317
|
-
|
|
1318
|
-
const newExplicit = isObservable(newValue);
|
|
1319
|
-
changed = !isObservable(oldValue) && oldExplicit !== newExplicit || (isObservable(oldValue) ? newValue !== oldValue : targetValue !== oldValue);
|
|
1293
|
+
changed = targetValue !== oldValue;
|
|
1320
1294
|
}
|
|
1321
1295
|
if (!changed) return true;
|
|
1322
1296
|
const result = Reflect.set(values, index, targetValue);
|
|
1323
1297
|
if (!result) return false;
|
|
1324
1298
|
const newLength = values.length;
|
|
1325
1299
|
const lengthChanged = newLength !== oldLength;
|
|
1326
|
-
if (isObservable(newValue)) {
|
|
1327
|
-
this.explicitObservables.add(index);
|
|
1328
|
-
} else {
|
|
1329
|
-
this.explicitObservables.delete(index);
|
|
1330
|
-
}
|
|
1331
1300
|
this.onArrayChanged(lengthChanged, index, 1);
|
|
1332
1301
|
return true;
|
|
1333
1302
|
}
|
|
@@ -1348,15 +1317,6 @@ class ArrayAdministration extends Administration {
|
|
|
1348
1317
|
const result = Reflect.set(this.source, "length", newLength);
|
|
1349
1318
|
if (!result) return false;
|
|
1350
1319
|
if (newLength < currentLength) {
|
|
1351
|
-
const toRemove = [];
|
|
1352
|
-
for (const index of this.explicitObservables) {
|
|
1353
|
-
if (index >= newLength) {
|
|
1354
|
-
toRemove.push(index);
|
|
1355
|
-
}
|
|
1356
|
-
}
|
|
1357
|
-
for (const index of toRemove) {
|
|
1358
|
-
this.explicitObservables.delete(index);
|
|
1359
|
-
}
|
|
1360
1320
|
this.onArrayChanged(true, newLength, currentLength - newLength);
|
|
1361
1321
|
} else {
|
|
1362
1322
|
this.onArrayChanged(true, currentLength, newLength - currentLength);
|
|
@@ -1366,13 +1326,10 @@ class ArrayAdministration extends Administration {
|
|
|
1366
1326
|
spliceWithArray(index, deleteCount, newItems) {
|
|
1367
1327
|
const length = this.source.length;
|
|
1368
1328
|
const newTargetItems = [];
|
|
1369
|
-
const newObservableIndices = [];
|
|
1370
1329
|
if (newItems) {
|
|
1371
1330
|
for (let i = 0; i < newItems.length; i++) {
|
|
1372
1331
|
newTargetItems[i] = getSource(newItems[i]);
|
|
1373
|
-
|
|
1374
|
-
newObservableIndices.push(i);
|
|
1375
|
-
}
|
|
1332
|
+
this.trackValue(newItems[i]);
|
|
1376
1333
|
}
|
|
1377
1334
|
}
|
|
1378
1335
|
if (index === void 0) index = 0;
|
|
@@ -1385,31 +1342,10 @@ class ArrayAdministration extends Administration {
|
|
|
1385
1342
|
for (let i = index; i < index + deleteCount; i++) {
|
|
1386
1343
|
removedItems.push(this._getEffectiveValue(i));
|
|
1387
1344
|
}
|
|
1388
|
-
for (let i = index; i < index + deleteCount; i++) {
|
|
1389
|
-
this.explicitObservables.delete(i);
|
|
1390
|
-
}
|
|
1391
|
-
const shift = (newItems?.length ?? 0) - deleteCount;
|
|
1392
|
-
if (shift !== 0) {
|
|
1393
|
-
const newExplicitObservables = /* @__PURE__ */ new Set();
|
|
1394
|
-
for (const idx of this.explicitObservables) {
|
|
1395
|
-
if (idx < index) {
|
|
1396
|
-
newExplicitObservables.add(idx);
|
|
1397
|
-
} else if (idx >= index + deleteCount) {
|
|
1398
|
-
newExplicitObservables.add(idx + shift);
|
|
1399
|
-
}
|
|
1400
|
-
}
|
|
1401
|
-
this.explicitObservables.clear();
|
|
1402
|
-
for (const idx of newExplicitObservables) {
|
|
1403
|
-
this.explicitObservables.add(idx);
|
|
1404
|
-
}
|
|
1405
|
-
}
|
|
1406
|
-
for (const relativeIdx of newObservableIndices) {
|
|
1407
|
-
this.explicitObservables.add(index + relativeIdx);
|
|
1408
|
-
}
|
|
1409
1345
|
this.spliceItemsIntoValues(index, deleteCount, newTargetItems);
|
|
1410
1346
|
if (deleteCount !== 0 || newTargetItems.length !== 0) {
|
|
1411
|
-
const
|
|
1412
|
-
const reindexing =
|
|
1347
|
+
const shift = (newItems?.length ?? 0) - deleteCount;
|
|
1348
|
+
const reindexing = shift !== 0 && index + deleteCount < length;
|
|
1413
1349
|
const count = reindexing ? Number.POSITIVE_INFINITY : Math.max(deleteCount ?? 0, newItems?.length ?? 0);
|
|
1414
1350
|
this.onArrayChanged(length !== this.source.length, index, count);
|
|
1415
1351
|
}
|
|
@@ -2436,19 +2372,7 @@ function getIdKey(Ctor) {
|
|
|
2436
2372
|
function getModelRefSnapshot(modelRef2) {
|
|
2437
2373
|
const Ctor = Object.getPrototypeOf(modelRef2).constructor;
|
|
2438
2374
|
const idKey = getIdKey(Ctor);
|
|
2439
|
-
|
|
2440
|
-
let id2 = getIdentifier(modelRef2);
|
|
2441
|
-
if (id2 === void 0) {
|
|
2442
|
-
const source2 = getSource(modelRef2);
|
|
2443
|
-
id2 = getIdentifier(source2);
|
|
2444
|
-
if (id2 === void 0) {
|
|
2445
|
-
const adm = getAdministration(modelRef2);
|
|
2446
|
-
if (adm && adm.proxy !== modelRef2) {
|
|
2447
|
-
id2 = getIdentifier(adm.proxy);
|
|
2448
|
-
}
|
|
2449
|
-
}
|
|
2450
|
-
}
|
|
2451
|
-
return { [idKey]: id2 };
|
|
2375
|
+
return idKey ? { [idKey]: getIdentifier(modelRef2) } : null;
|
|
2452
2376
|
}
|
|
2453
2377
|
function getSnapshotId(snapshot, Ctor) {
|
|
2454
2378
|
const idKey = getIdKey(Ctor);
|
|
@@ -2572,60 +2496,9 @@ class ModelAdministration extends PreactObjectAdministration {
|
|
|
2572
2496
|
modelsTraceUnsub = /* @__PURE__ */ new Map();
|
|
2573
2497
|
writeInProgress = /* @__PURE__ */ new Set();
|
|
2574
2498
|
computedSnapshot;
|
|
2575
|
-
snapshotAtom = createAtom();
|
|
2576
2499
|
snapshotMap = /* @__PURE__ */ new Map();
|
|
2577
2500
|
contextCache = /* @__PURE__ */ new Map();
|
|
2578
2501
|
parentName = null;
|
|
2579
|
-
/**
|
|
2580
|
-
* `@state` fields are shallow-reactive (property-level assignment triggers reactivity)
|
|
2581
|
-
* and participate in snapshots. Values stored in `@state` are not deep-wrapped.
|
|
2582
|
-
*
|
|
2583
|
-
* This helper walks a value and:
|
|
2584
|
-
* - observes any observable containers found (proxy or source) so in-place mutations
|
|
2585
|
-
* invalidate `getSnapshot()` / `toSnapshot()`
|
|
2586
|
-
* - avoids proxy traversal by preferring `getSource(...)`
|
|
2587
|
-
* - guards against cycles via `WeakSet`
|
|
2588
|
-
*/
|
|
2589
|
-
observeSnapshotValue(value, seen) {
|
|
2590
|
-
if (value == null) return;
|
|
2591
|
-
if (typeof value !== "object") return;
|
|
2592
|
-
if (!seen) seen = /* @__PURE__ */ new WeakSet();
|
|
2593
|
-
const obj = value;
|
|
2594
|
-
if (seen.has(obj)) return;
|
|
2595
|
-
seen.add(obj);
|
|
2596
|
-
const adm = getAdministration(obj);
|
|
2597
|
-
if (adm) {
|
|
2598
|
-
adm.reportObserved();
|
|
2599
|
-
}
|
|
2600
|
-
const src = getSource(value);
|
|
2601
|
-
if (src && typeof src === "object" && src !== value) {
|
|
2602
|
-
this.observeSnapshotValue(src, seen);
|
|
2603
|
-
return;
|
|
2604
|
-
}
|
|
2605
|
-
if (Array.isArray(value)) {
|
|
2606
|
-
for (let i = 0; i < value.length; i++) {
|
|
2607
|
-
this.observeSnapshotValue(value[i], seen);
|
|
2608
|
-
}
|
|
2609
|
-
return;
|
|
2610
|
-
}
|
|
2611
|
-
if (value instanceof Map) {
|
|
2612
|
-
value.forEach((v, k) => {
|
|
2613
|
-
this.observeSnapshotValue(k, seen);
|
|
2614
|
-
this.observeSnapshotValue(v, seen);
|
|
2615
|
-
});
|
|
2616
|
-
return;
|
|
2617
|
-
}
|
|
2618
|
-
if (value instanceof Set) {
|
|
2619
|
-
value.forEach((v) => this.observeSnapshotValue(v, seen));
|
|
2620
|
-
return;
|
|
2621
|
-
}
|
|
2622
|
-
if (value instanceof Date) {
|
|
2623
|
-
return;
|
|
2624
|
-
}
|
|
2625
|
-
for (const key of Object.keys(value)) {
|
|
2626
|
-
this.observeSnapshotValue(value[key], seen);
|
|
2627
|
-
}
|
|
2628
|
-
}
|
|
2629
2502
|
get parent() {
|
|
2630
2503
|
this.parentAtom.reportObserved();
|
|
2631
2504
|
return this._parent;
|
|
@@ -2661,7 +2534,6 @@ class ModelAdministration extends PreactObjectAdministration {
|
|
|
2661
2534
|
value,
|
|
2662
2535
|
this.proxy
|
|
2663
2536
|
);
|
|
2664
|
-
this.snapshotAtom.reportChanged();
|
|
2665
2537
|
});
|
|
2666
2538
|
}
|
|
2667
2539
|
}
|
|
@@ -2857,9 +2729,7 @@ class ModelAdministration extends PreactObjectAdministration {
|
|
|
2857
2729
|
return Object.keys(this.configuration).reduce((json, key) => {
|
|
2858
2730
|
switch (this.configuration[key].type) {
|
|
2859
2731
|
case ModelCfgTypes.state: {
|
|
2860
|
-
|
|
2861
|
-
this.observeSnapshotValue(value);
|
|
2862
|
-
json[key] = clone(getSource(value), key);
|
|
2732
|
+
json[key] = clone(this.proxy[key], key);
|
|
2863
2733
|
break;
|
|
2864
2734
|
}
|
|
2865
2735
|
case ModelCfgTypes.id:
|
|
@@ -3002,7 +2872,6 @@ class ModelAdministration extends PreactObjectAdministration {
|
|
|
3002
2872
|
getSnapshot() {
|
|
3003
2873
|
if (!this.computedSnapshot) {
|
|
3004
2874
|
this.computedSnapshot = createComputed(() => {
|
|
3005
|
-
this.snapshotAtom.reportObserved();
|
|
3006
2875
|
const json = this.toJSON();
|
|
3007
2876
|
configMap.set(json, this.configuration);
|
|
3008
2877
|
return json;
|
package/package.json
CHANGED
package/dist/computedProxy.d.ts
DELETED