@solidjs/signals 2.0.0-rc.1 → 2.0.0-rc.11
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/dev-shared.js +7155 -0
- package/dist/dev.attribution.js +3307 -0
- package/dist/dev.js +5765 -4496
- package/dist/observe/affects.js +129 -0
- package/dist/observe/attribution.js +7 -0
- package/dist/observe/boundaries.js +793 -0
- package/dist/observe/core/action.js +177 -0
- package/dist/observe/core/async.js +849 -0
- package/dist/observe/core/attribution-costs.js +66 -0
- package/dist/observe/core/attribution-feedback.js +280 -0
- package/dist/observe/core/attribution-hooks.js +83 -0
- package/dist/observe/core/attribution-queries.js +43 -0
- package/dist/observe/core/attribution.js +2904 -0
- package/dist/observe/core/constants.js +283 -0
- package/dist/{types-cjs/core/context.d.cts → observe/core/context.js} +37 -12
- package/dist/observe/core/core.js +1999 -0
- package/dist/observe/core/dev.js +343 -0
- package/dist/observe/core/effect.js +200 -0
- package/dist/observe/core/error-hooks.js +71 -0
- package/dist/observe/core/error.js +80 -0
- package/dist/observe/core/external.js +98 -0
- package/dist/observe/core/graph.js +155 -0
- package/dist/observe/core/heap.js +147 -0
- package/dist/observe/core/invariants.js +45 -0
- package/dist/observe/core/lanes.js +205 -0
- package/dist/observe/core/optimistic.js +669 -0
- package/dist/observe/core/owner.js +353 -0
- package/dist/observe/core/scheduler.js +1561 -0
- package/dist/observe/core/verdict.js +674 -0
- package/dist/observe/index.js +59 -0
- package/dist/observe/map.js +507 -0
- package/dist/observe/signals.js +731 -0
- package/dist/observe/store/index.js +44 -0
- package/dist/observe/store/next/optimistic.js +717 -0
- package/dist/observe/store/next/projection.js +266 -0
- package/dist/observe/store/next/reconcile.js +375 -0
- package/dist/observe/store/next/store.js +2480 -0
- package/dist/observe/store/next/target.js +51 -0
- package/dist/observe/store/store.js +331 -0
- package/dist/observe/store/storePath.js +103 -0
- package/dist/observe/store/utils.js +1070 -0
- package/dist/prod/affects.js +10 -9
- package/dist/prod/attribution.js +45 -0
- package/dist/prod/boundaries.js +388 -178
- package/dist/prod/core/action.js +65 -37
- package/dist/prod/core/async.js +378 -163
- package/dist/prod/core/attribution-hooks.js +3 -0
- package/dist/prod/core/constants.js +186 -1
- package/dist/prod/core/context.js +10 -16
- package/dist/prod/core/core.js +1546 -416
- package/dist/prod/core/dev.js +18 -1
- package/dist/prod/core/effect.js +119 -79
- package/dist/prod/core/error-hooks.js +71 -0
- package/dist/prod/core/error.js +13 -1
- package/dist/prod/core/external.js +4 -4
- package/dist/prod/core/graph.js +105 -54
- package/dist/prod/core/heap.js +72 -65
- package/dist/prod/core/invariants.js +3 -2
- package/dist/prod/core/lanes.js +117 -52
- package/dist/prod/core/optimistic.js +500 -104
- package/dist/prod/core/owner.js +131 -84
- package/dist/prod/core/scheduler.js +1012 -241
- package/dist/prod/core/verdict.js +417 -112
- package/dist/prod/index.js +20 -8
- package/dist/prod/map.js +355 -171
- package/dist/prod/signals.js +363 -32
- package/dist/prod/store/index.js +2 -0
- package/dist/prod/store/next/optimistic.js +530 -197
- package/dist/prod/store/next/projection.js +142 -57
- package/dist/prod/store/next/reconcile.js +149 -103
- package/dist/prod/store/next/store.js +1470 -346
- package/dist/prod/store/next/target.js +40 -9
- package/dist/prod/store/store.js +23 -19
- package/dist/prod/store/utils.js +997 -130
- package/dist/types/attribution.d.ts +19 -0
- package/dist/types/attribution.prod.d.ts +22 -0
- package/dist/types/boundaries.d.ts +78 -5
- package/dist/types/core/action.d.ts +12 -5
- package/dist/types/core/async.d.ts +3 -1
- package/dist/types/core/attribution-costs.d.ts +35 -0
- package/dist/types/core/attribution-feedback.d.ts +133 -0
- package/dist/types/core/attribution-hooks.d.ts +304 -0
- package/dist/types/core/attribution-queries.d.ts +24 -0
- package/dist/types/core/attribution.d.ts +892 -0
- package/dist/types/core/constants.d.ts +179 -0
- package/dist/types/core/core.d.ts +299 -25
- package/dist/types/core/dev.d.ts +421 -8
- package/dist/types/core/effect.d.ts +8 -1
- package/dist/types/core/error-hooks.d.ts +71 -0
- package/dist/types/core/error.d.ts +9 -0
- package/dist/types/core/graph.d.ts +23 -0
- package/dist/types/core/heap.d.ts +5 -3
- package/dist/types/core/index.d.ts +6 -3
- package/dist/types/core/invariants.d.ts +5 -1
- package/dist/types/core/lanes.d.ts +51 -19
- package/dist/types/core/owner.d.ts +15 -3
- package/dist/types/core/scheduler.d.ts +252 -1
- package/dist/types/core/types.d.ts +124 -41
- package/dist/types/index.d.ts +18 -5
- package/dist/types/map.d.ts +2 -0
- package/dist/types/signals.d.ts +145 -13
- package/dist/types/store/index.d.ts +7 -6
- package/dist/types/store/next/optimistic.d.ts +18 -13
- package/dist/types/store/next/projection.d.ts +5 -2
- package/dist/types/store/next/reconcile.d.ts +7 -0
- package/dist/types/store/next/store.d.ts +83 -11
- package/dist/types/store/next/target.d.ts +108 -11
- package/dist/types/store/store.d.ts +20 -11
- package/dist/types/store/utils.d.ts +188 -0
- package/package.json +31 -26
- package/dist/node.cjs +0 -8137
- package/dist/types/store/optimistic.d.ts +0 -45
- package/dist/types/store/projection.d.ts +0 -70
- package/dist/types/store/reconcile.d.ts +0 -46
- package/dist/types-cjs/affects.d.cts +0 -47
- package/dist/types-cjs/boundaries.d.cts +0 -175
- package/dist/types-cjs/core/action.d.cts +0 -64
- package/dist/types-cjs/core/async.d.cts +0 -21
- package/dist/types-cjs/core/constants.d.cts +0 -71
- package/dist/types-cjs/core/core.d.cts +0 -156
- package/dist/types-cjs/core/dev.d.cts +0 -64
- package/dist/types-cjs/core/effect.d.cts +0 -30
- package/dist/types-cjs/core/error.d.cts +0 -47
- package/dist/types-cjs/core/external.d.cts +0 -15
- package/dist/types-cjs/core/graph.d.cts +0 -5
- package/dist/types-cjs/core/heap.d.cts +0 -22
- package/dist/types-cjs/core/index.d.cts +0 -13
- package/dist/types-cjs/core/invariants.d.cts +0 -59
- package/dist/types-cjs/core/lanes.d.cts +0 -56
- package/dist/types-cjs/core/optimistic.d.cts +0 -6
- package/dist/types-cjs/core/owner.d.cts +0 -124
- package/dist/types-cjs/core/scheduler.d.cts +0 -172
- package/dist/types-cjs/core/types.d.cts +0 -148
- package/dist/types-cjs/core/verdict.d.cts +0 -2
- package/dist/types-cjs/index.d.cts +0 -10
- package/dist/types-cjs/map.d.cts +0 -69
- package/dist/types-cjs/package.json +0 -3
- package/dist/types-cjs/signals.d.cts +0 -624
- package/dist/types-cjs/store/index.d.cts +0 -19
- package/dist/types-cjs/store/next/optimistic.d.cts +0 -20
- package/dist/types-cjs/store/next/projection.d.cts +0 -24
- package/dist/types-cjs/store/next/reconcile.d.cts +0 -3
- package/dist/types-cjs/store/next/store.d.cts +0 -71
- package/dist/types-cjs/store/next/target.d.cts +0 -99
- package/dist/types-cjs/store/optimistic.d.cts +0 -45
- package/dist/types-cjs/store/projection.d.cts +0 -70
- package/dist/types-cjs/store/reconcile.d.cts +0 -46
- package/dist/types-cjs/store/store.d.cts +0 -138
- package/dist/types-cjs/store/storePath.d.cts +0 -58
- package/dist/types-cjs/store/utils.d.cts +0 -74
|
@@ -10,9 +10,9 @@ import "../../core/effect.js";
|
|
|
10
10
|
|
|
11
11
|
import { $TARGET, markRawIngest, isWrappable, rawValuesUsed, isRawValue, getWriteOverride } from "../store.js";
|
|
12
12
|
|
|
13
|
-
import { adoptPB, unwrapValue, notifyFold, targetsEqual, bumpDeep, notifyKeyValue, notifyKeyDiff, notifyFoldTail, hasAccessorFlag } from "./store.js";
|
|
13
|
+
import { materializePB, adoptPB, unwrapValue, notifyFold, targetsEqual, bumpDeep, notifyKeyValue, notifyKeyDiff, notifyFoldTail, hasAccessorFlag } from "./store.js";
|
|
14
14
|
|
|
15
|
-
import { storeNextLookup, optHooks,
|
|
15
|
+
import { isOwned, $OWNER, storeNextLookup, optHooks, lookupTarget } from "./target.js";
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Store rewrite — reconcile, the adoption channel (INTERNALS-STORE-STATE.md
|
|
@@ -37,7 +37,11 @@ import { storeNextLookup, optHooks, ownedRaw } from "./target.js";
|
|
|
37
37
|
if (t == null) throw new Error("");
|
|
38
38
|
const f = t?.[$TARGET];
|
|
39
39
|
if (f === undefined || f.px !== t) throw new Error("");
|
|
40
|
-
|
|
40
|
+
// Reconcile's diff walks need a REAL pending container — a prototype
|
|
41
|
+
// overlay (#3044) materializes to the clone path first (edge: reconcile
|
|
42
|
+
// inside a setter that already wrote this target).
|
|
43
|
+
if (f.ovl) materializePB(f);
|
|
44
|
+
let i = n === null ? null : typeof n === "string" ? e => e?.[n] : n;
|
|
41
45
|
// §7b chained backing: a projection derive returning a LIVE store proxy
|
|
42
46
|
// adopts the proxy itself as the backing — reads flow through the inner
|
|
43
47
|
// store's traps, so consumers subscribe to the inner graph and updates
|
|
@@ -50,8 +54,8 @@ import { storeNextLookup, optHooks, ownedRaw } from "./target.js";
|
|
|
50
54
|
adoptPB(f, e);
|
|
51
55
|
return;
|
|
52
56
|
}
|
|
53
|
-
const
|
|
54
|
-
if (
|
|
57
|
+
const l = unwrapValue(e);
|
|
58
|
+
if (i) {
|
|
55
59
|
// Root identity precondition — checked before ANY mutation, so a throwing
|
|
56
60
|
// reconcile is atomic by construction (RUL-12 ruling). Projections
|
|
57
61
|
// (replace=true) relax it: a root entity change merges in place — the
|
|
@@ -59,16 +63,18 @@ import { storeNextLookup, optHooks, ownedRaw } from "./target.js";
|
|
|
59
63
|
// key-matched across the entity change (proj R7: keyFn drops to
|
|
60
64
|
// positional so old-entity subtrees never merge into the new entity's).
|
|
61
65
|
const e = f.pb ?? f.v;
|
|
62
|
-
const t =
|
|
63
|
-
if (t !== undefined &&
|
|
66
|
+
const t = i(e);
|
|
67
|
+
if (t !== undefined && !sameKey(i(l), t)) {
|
|
64
68
|
if (!o) throw new Error("");
|
|
65
69
|
// Entity change: wholesale swap. The root proxy is stable for life
|
|
66
70
|
// (proj R5) but NOTHING below survives — children are never matched
|
|
67
71
|
// across an entity change even when their own keys align (proj R7).
|
|
68
72
|
// Displaced-raw unregistration (proj R10): the outgoing raw stops
|
|
69
73
|
// resolving to this proxy; re-handed later it wraps fresh.
|
|
70
|
-
|
|
71
|
-
|
|
74
|
+
const e = f.pb ?? f.v;
|
|
75
|
+
if (isOwned(e)) delete e[$OWNER]; // disown: wraps fresh if re-handed
|
|
76
|
+
else (f.fam?.map ?? storeNextLookup).delete(e);
|
|
77
|
+
adoptPB(f, l);
|
|
72
78
|
return;
|
|
73
79
|
}
|
|
74
80
|
}
|
|
@@ -78,141 +84,168 @@ import { storeNextLookup, optHooks, ownedRaw } from "./target.js";
|
|
|
78
84
|
// touched. Key-matched rows keep proxy identity by descending into the
|
|
79
85
|
// existing child targets instead of overriding their parent slots.
|
|
80
86
|
if (f.fam?.opt === true && !projectionWriteActive && !getWriteOverride()) {
|
|
81
|
-
optHooks.applyTentative(f,
|
|
87
|
+
optHooks.applyTentative(f, l, i);
|
|
82
88
|
return;
|
|
83
89
|
}
|
|
84
|
-
applyAdopt(f,
|
|
90
|
+
applyAdopt(f, l, i, o);
|
|
85
91
|
}
|
|
86
92
|
|
|
87
93
|
function applyAdopt(e, t, n, o = false) {
|
|
88
94
|
const f = e.pb ?? e.v;
|
|
89
95
|
// The sound identity skip (O7): same reference AND we never diverged it.
|
|
90
|
-
if (t === f && !
|
|
91
|
-
const
|
|
96
|
+
if (t === f && !isOwned(f)) return;
|
|
97
|
+
const i = e.fam;
|
|
92
98
|
// §6b (R28): the diff's previous-arrangement baseline is the LANE VIEW —
|
|
93
99
|
// optimistic rows must be visible to key matching so a landing carrying the
|
|
94
100
|
// same key recycles their proxies. Raw `prev` keeps the identity/ownership
|
|
95
101
|
// roles above; only matching reads the view.
|
|
96
|
-
const
|
|
102
|
+
const l = i?.opt === true ? optHooks.optimisticView(e, f) : f;
|
|
97
103
|
const r = Array.isArray(t);
|
|
98
104
|
// Plain stores notify inline AFTER the descent (child registrations feed
|
|
99
105
|
// the fold diff's identity-preservation check); projections keep deferred
|
|
100
106
|
// folds (downstream holds can form later in the flush).
|
|
101
|
-
const
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
107
|
+
const s = i === null;
|
|
108
|
+
const u = e.s === true;
|
|
109
|
+
// Node-notify base is the view the nodes were last told (#3296): a draft
|
|
110
|
+
// preceding this reconcile already moved them to its pending backing at
|
|
111
|
+
// setter exit (prev, materialized above), so diffing incoming against the
|
|
112
|
+
// committed backing would skip a key the draft changed and the reconcile
|
|
113
|
+
// restores — the node would commit the superseded draft value.
|
|
114
|
+
const a = f;
|
|
115
|
+
adoptPB(e, t, s);
|
|
105
116
|
// Shallow adoption: records are slot values — sticky raw-mark the incoming
|
|
106
117
|
// set (R41) and never descend; slot notification is the positional diff.
|
|
107
|
-
if (
|
|
108
|
-
if (Array.isArray(
|
|
109
|
-
if (
|
|
118
|
+
if (u) markRawIngest(t);
|
|
119
|
+
if (Array.isArray(l) !== r) {
|
|
120
|
+
if (s) notifyFold(e, a, t);
|
|
110
121
|
return;
|
|
111
122
|
}
|
|
112
123
|
if (r) {
|
|
113
|
-
const f =
|
|
124
|
+
const f = l;
|
|
114
125
|
const r = t;
|
|
115
126
|
// Fused array walk (eager mode): per-index notification rides the same
|
|
116
127
|
// loop as the descent (descend first — targetsEqual needs the child's
|
|
117
128
|
// re-registration, R9). Length, trailing removed indexes, and any other
|
|
118
129
|
// unvisited node keys land in the counted sweep below.
|
|
119
|
-
const
|
|
120
|
-
let
|
|
121
|
-
if (n && !
|
|
130
|
+
const c = s ? e.n : null;
|
|
131
|
+
let d = 0;
|
|
132
|
+
if (n && !u) {
|
|
122
133
|
// Positional-prefix fast path (legacy keyedMatch-walk parity): while
|
|
123
134
|
// rows key-match in place — the steady-state polling shape — descend
|
|
124
135
|
// directly with zero staging. The prevByKey map is built only for the
|
|
125
136
|
// misaligned remainder, and never at all on aligned ticks.
|
|
126
|
-
const
|
|
127
|
-
const
|
|
128
|
-
let
|
|
129
|
-
let
|
|
130
|
-
for (const y = Math.min(
|
|
131
|
-
const
|
|
132
|
-
const
|
|
137
|
+
const l = f.length;
|
|
138
|
+
const s = r.length;
|
|
139
|
+
let u = false;
|
|
140
|
+
let p = 0;
|
|
141
|
+
for (const y = Math.min(l, s); p < y; p++) {
|
|
142
|
+
const l = r[p];
|
|
143
|
+
const s = f[p];
|
|
133
144
|
// Routing heuristic only (aligned vs keyed remainder) — both routes
|
|
134
145
|
// notify identically and descend() is the one authoritative
|
|
135
146
|
// validator, so bare typeof gates suffice here; full isWrappable
|
|
136
147
|
// per row was the walk's dominant residual cost.
|
|
137
|
-
if (
|
|
148
|
+
if (s !== l && !(s !== null && typeof s === "object" && l !== null && typeof l === "object" && sameKey(n(s), n(l)))) break;
|
|
138
149
|
// misaligned: fall to the keyed remainder below
|
|
139
150
|
// Identity skip inline (FINDING-1 guard), then descend the pair.
|
|
140
|
-
if ((
|
|
141
|
-
if (e.dk !== null && !
|
|
151
|
+
if ((s !== l || l !== null && typeof l === "object" && isOwned(l)) && l !== null && typeof l === "object") descend(unwrapValue(s), l, n, i, o);
|
|
152
|
+
if (e.dk !== null && !u && !(l !== null && typeof l === "object" ? targetsEqual(s, l) : isEqual(s, l))) {
|
|
142
153
|
bumpDeep(e);
|
|
143
|
-
|
|
154
|
+
u = true;
|
|
144
155
|
}
|
|
145
|
-
if (
|
|
146
|
-
const e =
|
|
156
|
+
if (c !== null) {
|
|
157
|
+
const e = c[p];
|
|
147
158
|
if (e !== undefined) {
|
|
148
|
-
|
|
149
|
-
notifyKeyValue(e,
|
|
159
|
+
d++;
|
|
160
|
+
notifyKeyValue(e, p, a[p], l, a, t);
|
|
150
161
|
}
|
|
151
162
|
}
|
|
152
163
|
}
|
|
153
|
-
if (e.dk !== null && !
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
164
|
+
if (e.dk !== null && !u && p < r.length) bumpDeep(e);
|
|
165
|
+
const y = p;
|
|
166
|
+
// misalignment point (== nlen on aligned ticks)
|
|
167
|
+
let w = null;
|
|
168
|
+
for (;p < r.length; p++) {
|
|
169
|
+
const e = r[p];
|
|
157
170
|
// typeof gates route; descend validates (same contract as the prefix).
|
|
158
171
|
if (e !== null && typeof e === "object") {
|
|
159
172
|
const t = n(e);
|
|
160
|
-
let
|
|
173
|
+
let l;
|
|
161
174
|
if (t !== undefined) {
|
|
162
|
-
if (
|
|
163
|
-
|
|
164
|
-
|
|
175
|
+
if (w === null) {
|
|
176
|
+
// Occurrence-aware (re-audit 2, P1-5): duplicate keys queue
|
|
177
|
+
// their prev INDICES (rows can themselves be arrays, so index
|
|
178
|
+
// queues are the unambiguous encoding — same as buildRowOps)
|
|
179
|
+
// and each is consumed ONCE. First-wins would adopt two next
|
|
180
|
+
// rows into the SAME prev target while row ops retain two
|
|
181
|
+
// separate DOM rows (the second one stale).
|
|
182
|
+
w = new Map;
|
|
183
|
+
// From structStart, not 0 (re-audit 3, P1-2): prefix-aligned
|
|
184
|
+
// rows already adopted their incoming counterparts — re-offering
|
|
185
|
+
// them here let a duplicate key adopt a prefix row AGAIN while
|
|
186
|
+
// row ops (which correctly window from structStart) retained
|
|
187
|
+
// the later occurrence's DOM row against a never-adopted target.
|
|
188
|
+
for (let e = y; e < f.length; e++) {
|
|
165
189
|
const t = unwrapValue(f[e]);
|
|
166
190
|
if (t !== null && typeof t === "object") {
|
|
167
|
-
const
|
|
168
|
-
if (
|
|
191
|
+
const o = n(t);
|
|
192
|
+
if (o === undefined) continue;
|
|
193
|
+
const f = w.get(o);
|
|
194
|
+
if (f === undefined) w.set(o, e); else if (Array.isArray(f)) f.push(e); else w.set(o, [ f, e ]);
|
|
169
195
|
}
|
|
170
196
|
}
|
|
171
197
|
}
|
|
172
|
-
|
|
198
|
+
const e = w.get(t);
|
|
199
|
+
if (e === undefined) l = undefined; else if (Array.isArray(e)) {
|
|
200
|
+
l = unwrapValue(f[e.shift()]);
|
|
201
|
+
if (e.length === 1) w.set(t, e[0]);
|
|
202
|
+
} else {
|
|
203
|
+
l = unwrapValue(f[e]);
|
|
204
|
+
w.delete(t);
|
|
205
|
+
}
|
|
173
206
|
} else {
|
|
174
|
-
|
|
207
|
+
l = unwrapValue(f[p]);
|
|
175
208
|
// keyless item: positional fallback
|
|
176
209
|
}
|
|
177
|
-
descend(
|
|
210
|
+
descend(l, e, n, i, o);
|
|
178
211
|
}
|
|
179
|
-
if (
|
|
180
|
-
const e =
|
|
212
|
+
if (c !== null) {
|
|
213
|
+
const e = c[p];
|
|
181
214
|
if (e !== undefined) {
|
|
182
|
-
|
|
183
|
-
notifyKeyDiff(e,
|
|
215
|
+
d++;
|
|
216
|
+
notifyKeyDiff(e, p, a, t, false);
|
|
184
217
|
}
|
|
185
218
|
}
|
|
186
219
|
}
|
|
187
220
|
} else {
|
|
188
|
-
const
|
|
189
|
-
const
|
|
190
|
-
let
|
|
191
|
-
for (let y = 0; y <
|
|
192
|
-
const
|
|
193
|
-
if (!
|
|
194
|
-
if (e.dk !== null && !
|
|
221
|
+
const l = Math.min(f.length, r.length);
|
|
222
|
+
const s = r.length;
|
|
223
|
+
let p = false;
|
|
224
|
+
for (let y = 0; y < s; y++) {
|
|
225
|
+
const s = r[y];
|
|
226
|
+
if (!u && y < l && s !== null && typeof s === "object") descend(unwrapValue(f[y]), s, n, i, o);
|
|
227
|
+
if (e.dk !== null && !p && !(s !== null && typeof s === "object" ? targetsEqual(f[y], s) : isEqual(f[y], s))) {
|
|
195
228
|
bumpDeep(e);
|
|
196
|
-
|
|
229
|
+
p = true;
|
|
197
230
|
}
|
|
198
|
-
if (
|
|
199
|
-
const e =
|
|
231
|
+
if (c !== null) {
|
|
232
|
+
const e = c[y];
|
|
200
233
|
if (e !== undefined) {
|
|
201
|
-
|
|
202
|
-
notifyKeyDiff(e, y,
|
|
234
|
+
d++;
|
|
235
|
+
notifyKeyDiff(e, y, a, t, false);
|
|
203
236
|
}
|
|
204
237
|
}
|
|
205
238
|
}
|
|
206
239
|
}
|
|
207
|
-
if (
|
|
208
|
-
if (
|
|
209
|
-
for (const e of Reflect.ownKeys(
|
|
240
|
+
if (s) {
|
|
241
|
+
if (c !== null && d < e.nc) {
|
|
242
|
+
for (const e of Reflect.ownKeys(c)) {
|
|
210
243
|
// visited indexes are < nextRows.length; everything else sweeps
|
|
211
244
|
const n = typeof e === "string" ? +e : NaN;
|
|
212
|
-
if (!(n >= 0 && n < r.length)) notifyKeyDiff(
|
|
245
|
+
if (!(n >= 0 && n < r.length)) notifyKeyDiff(c[e], e, a, t, false);
|
|
213
246
|
}
|
|
214
247
|
}
|
|
215
|
-
notifyFoldTail(e,
|
|
248
|
+
notifyFoldTail(e, a, t);
|
|
216
249
|
}
|
|
217
250
|
return;
|
|
218
251
|
} else {
|
|
@@ -222,61 +255,62 @@ function applyAdopt(e, t, n, o = false) {
|
|
|
222
255
|
// slots must not notify, R9). This replaces the notifyFold re-walk that
|
|
223
256
|
// doubled dbmon's diff cost. for-in covers own enumerable string keys
|
|
224
257
|
// with no key-array allocation; symbols get a pass only when present.
|
|
225
|
-
const f =
|
|
258
|
+
const f = s ? e.n : null;
|
|
226
259
|
let r = 0;
|
|
227
|
-
let
|
|
260
|
+
let c = false;
|
|
228
261
|
// The per-key body is inlined on purpose (legacy applyStateFast parity:
|
|
229
262
|
// an extracted helper costs a call per key on the hottest object-diff
|
|
230
263
|
// site). Reference-identical values early-continue BEFORE any other
|
|
231
264
|
// work — sound only with the ownership guard (FINDING-1: an owned
|
|
232
265
|
// backing is setter-diverged and must still diff).
|
|
233
|
-
for (const
|
|
234
|
-
const
|
|
235
|
-
const
|
|
236
|
-
const y =
|
|
237
|
-
if (
|
|
238
|
-
if (f !== null && f[
|
|
266
|
+
for (const s in t) {
|
|
267
|
+
const d = t[s];
|
|
268
|
+
const p = a[s];
|
|
269
|
+
const y = d !== null && typeof d === "object";
|
|
270
|
+
if (p === d && (!y || !isOwned(d)) && (f === null || f[s] === undefined || !hasAccessorFlag(f[s]))) {
|
|
271
|
+
if (f !== null && f[s] !== undefined) r++;
|
|
239
272
|
continue;
|
|
240
273
|
}
|
|
241
|
-
if (y && !
|
|
274
|
+
if (y && !u) descend(unwrapValue(l[s]), d, n, i, o);
|
|
242
275
|
// Deep-witness (dk): value changes must notify even with NO per-key
|
|
243
276
|
// node — deep() subscribes one node per record. Checked after descend
|
|
244
277
|
// so in-place adoptions (same logical slot) don't bump; child records
|
|
245
278
|
// carry their own witness. One flag + null check when unused.
|
|
246
|
-
if (e.dk !== null && !
|
|
279
|
+
if (e.dk !== null && !c && !(y ? targetsEqual(p, d) : isEqual(p, d))) {
|
|
247
280
|
bumpDeep(e);
|
|
248
|
-
|
|
281
|
+
c = true;
|
|
249
282
|
}
|
|
250
283
|
if (f !== null) {
|
|
251
|
-
const e = f[
|
|
284
|
+
const e = f[s];
|
|
252
285
|
if (e !== undefined) {
|
|
253
286
|
r++;
|
|
254
|
-
notifyKeyValue(e,
|
|
287
|
+
notifyKeyValue(e, s, p, d, a, t);
|
|
255
288
|
}
|
|
256
289
|
}
|
|
257
290
|
}
|
|
258
|
-
const
|
|
259
|
-
for (let e = 0; e <
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
291
|
+
const d = Object.getOwnPropertySymbols(t);
|
|
292
|
+
for (let e = 0; e < d.length; e++) {
|
|
293
|
+
const s = d[e];
|
|
294
|
+
if (s === $OWNER) continue;
|
|
295
|
+
const c = t[s];
|
|
296
|
+
if (!u && c !== null && typeof c === "object") descend(unwrapValue(l[s]), c, n, i, o);
|
|
263
297
|
if (f !== null) {
|
|
264
|
-
const e = f[
|
|
298
|
+
const e = f[s];
|
|
265
299
|
if (e !== undefined) {
|
|
266
300
|
r++;
|
|
267
|
-
notifyKeyValue(e,
|
|
301
|
+
notifyKeyValue(e, s, a[s], c, a, t);
|
|
268
302
|
}
|
|
269
303
|
}
|
|
270
304
|
}
|
|
271
|
-
if (
|
|
305
|
+
if (s) {
|
|
272
306
|
// Deleted-key nodes (in the map but absent from incoming) — counted
|
|
273
307
|
// fast-out: when every node was visited, skip the sweep entirely.
|
|
274
308
|
if (f !== null && r < e.nc) {
|
|
275
309
|
for (const e of Reflect.ownKeys(f)) {
|
|
276
|
-
if (!hasOwnP.call(t, e)) notifyKeyDiff(f[e], e,
|
|
310
|
+
if (!hasOwnP.call(t, e)) notifyKeyDiff(f[e], e, a, t, false);
|
|
277
311
|
}
|
|
278
312
|
}
|
|
279
|
-
notifyFoldTail(e,
|
|
313
|
+
notifyFoldTail(e, a, t);
|
|
280
314
|
}
|
|
281
315
|
return;
|
|
282
316
|
}
|
|
@@ -284,14 +318,23 @@ function applyAdopt(e, t, n, o = false) {
|
|
|
284
318
|
|
|
285
319
|
const hasOwnP = Object.prototype.hasOwnProperty;
|
|
286
320
|
|
|
321
|
+
/** Setter-channel row ops (the fold site calls this for array targets with
|
|
322
|
+
* ops consumers): structural mutation through the setter — push/splice/index
|
|
323
|
+
/** Key equality for EVERY key comparison in this module (re-audit 2, P1-5):
|
|
324
|
+
* SameValueZero, matching the adoption window's Map-based matcher — NaN keys
|
|
325
|
+
* are equal to themselves, so aligned NaN rows stay aligned in the prefix
|
|
326
|
+
* walk instead of forever misaligning. */ function sameKey(e, t) {
|
|
327
|
+
return e === t || e !== e && t !== t;
|
|
328
|
+
}
|
|
329
|
+
|
|
287
330
|
function descend(e, t, n, o, f = false) {
|
|
288
331
|
if (e === null || typeof e !== "object" || t === null || typeof t !== "object") return;
|
|
289
332
|
// Lookup FIRST: a hit implies pv was wrappable and never raw-marked (only
|
|
290
333
|
// wrappables acquire targets; rawValues never wrap) — one WeakMap get
|
|
291
334
|
// replaces isWrappable(pv) + isRawValue(pv), and a miss prunes untracked
|
|
292
335
|
// subtrees before any further checks.
|
|
293
|
-
const
|
|
294
|
-
if (
|
|
336
|
+
const i = lookupTarget(e, o);
|
|
337
|
+
if (i === undefined) return;
|
|
295
338
|
// nothing proxied below this pair
|
|
296
339
|
// The NEW side still validates fully: a frozen/platform/markRaw'd incoming
|
|
297
340
|
// value is a leaf for reconcile — replaced by reference, never recursed
|
|
@@ -308,7 +351,10 @@ function descend(e, t, n, o, f = false) {
|
|
|
308
351
|
const f = n(t);
|
|
309
352
|
// Key mismatch detaches: the slot takes the new entity; the old proxy
|
|
310
353
|
// keeps its (old) backing and a fresh proxy wraps the new value on read.
|
|
311
|
-
|
|
354
|
+
// SameValueZero (re-audit 2, P1-5): NaN keys are self-equal — strict
|
|
355
|
+
// inequality detached every NaN-keyed slot on every tick while the
|
|
356
|
+
// Map-based row-ops matcher retained its DOM row (stale forever).
|
|
357
|
+
if (o !== undefined && f !== undefined && !sameKey(o, f)) return;
|
|
312
358
|
}
|
|
313
359
|
// Reachability pruning (§6d) is MODE-dependent, both pinned:
|
|
314
360
|
// - keyed matching descends only where subscriptions exist at/below (`d`) —
|
|
@@ -320,8 +366,8 @@ function descend(e, t, n, o, f = false) {
|
|
|
320
366
|
// UNCONDITIONALLY (proj R6: the slot keeps its proxy without needing a
|
|
321
367
|
// subscriber below); plain keyed reconcile detaches unobserved captures
|
|
322
368
|
// (recon-snap R18 — staleness is the pinned pruning contract).
|
|
323
|
-
if (!f && n !== null && !
|
|
324
|
-
applyAdopt(
|
|
369
|
+
if (!f && n !== null && !i.d) return;
|
|
370
|
+
applyAdopt(i, t, n, f);
|
|
325
371
|
}
|
|
326
372
|
|
|
327
|
-
export { reconcileNextState };
|
|
373
|
+
export { reconcileNextState, sameKey };
|