@solidjs/signals 2.0.0-rc.17 → 2.0.0-rc.18
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 +296 -191
- package/dist/dev.attribution.js +16 -16
- package/dist/dev.js +527 -311
- package/dist/observe/core/async.js +148 -115
- package/dist/observe/core/constants.js +3 -1
- package/dist/observe/core/core.js +27 -27
- package/dist/observe/core/effect.js +29 -32
- package/dist/observe/core/graph.js +5 -5
- package/dist/observe/core/owner.js +7 -7
- package/dist/observe/core/scheduler.js +23 -12
- package/dist/observe/core/verdict.js +2 -2
- package/dist/observe/deferred.js +16 -13
- package/dist/observe/from.js +248 -0
- package/dist/observe/index.js +2 -0
- package/dist/observe/store/reconcile.js +137 -121
- package/dist/observe/store/store.js +595 -618
- package/dist/observe/store/target.js +1 -5
- package/dist/prod/core/async.js +209 -176
- package/dist/prod/core/constants.js +3 -1
- package/dist/prod/core/core.js +33 -33
- package/dist/prod/core/effect.js +24 -27
- package/dist/prod/core/graph.js +2 -2
- package/dist/prod/core/lanes.js +14 -14
- package/dist/prod/core/scheduler.js +35 -24
- package/dist/prod/core/truth.js +4 -4
- package/dist/prod/core/verdict.js +7 -7
- package/dist/prod/deferred.js +17 -14
- package/dist/prod/from.js +248 -0
- package/dist/prod/index.js +2 -0
- package/dist/prod/store/optimistic.js +1 -1
- package/dist/prod/store/reconcile.js +137 -121
- package/dist/prod/store/store.js +94 -117
- package/dist/prod/store/target.js +13 -17
- package/dist/types/core/async.d.ts +12 -2
- package/dist/types/core/constants.d.ts +5 -0
- package/dist/types/core/core.d.ts +19 -3
- package/dist/types/core/scheduler.d.ts +15 -3
- package/dist/types/from.d.ts +47 -0
- package/dist/types/index.d.ts +1 -0
- package/package.json +1 -1
package/dist/dev.js
CHANGED
|
@@ -64,123 +64,128 @@ import {
|
|
|
64
64
|
a8 as link,
|
|
65
65
|
a9 as pullComputed,
|
|
66
66
|
aa as strictRead,
|
|
67
|
-
ab as
|
|
68
|
-
ac as
|
|
69
|
-
ad as
|
|
70
|
-
ae as
|
|
71
|
-
af as
|
|
72
|
-
ag as
|
|
73
|
-
ah as
|
|
74
|
-
ai as
|
|
75
|
-
aj as
|
|
76
|
-
ak as
|
|
77
|
-
al as
|
|
78
|
-
am as
|
|
79
|
-
an as
|
|
80
|
-
ao as
|
|
81
|
-
ap as
|
|
82
|
-
aq as
|
|
83
|
-
ar as
|
|
84
|
-
as as
|
|
85
|
-
at as
|
|
86
|
-
au as
|
|
87
|
-
av as
|
|
88
|
-
aw as
|
|
89
|
-
ax as
|
|
90
|
-
ay as
|
|
91
|
-
az as
|
|
92
|
-
aA as
|
|
93
|
-
aB as
|
|
94
|
-
aC as
|
|
95
|
-
aD as
|
|
96
|
-
aE as
|
|
97
|
-
aF as
|
|
98
|
-
aG as
|
|
99
|
-
aH as
|
|
100
|
-
aI as
|
|
101
|
-
aJ as
|
|
102
|
-
aK as
|
|
103
|
-
aL as
|
|
104
|
-
aM as
|
|
105
|
-
aN as
|
|
106
|
-
aO as
|
|
107
|
-
aP as
|
|
108
|
-
aQ as
|
|
109
|
-
aR as
|
|
110
|
-
aS as
|
|
111
|
-
aT as
|
|
112
|
-
aU as
|
|
113
|
-
aV as
|
|
114
|
-
aW as
|
|
115
|
-
aX as
|
|
116
|
-
aY as
|
|
117
|
-
aZ as
|
|
118
|
-
a_ as
|
|
119
|
-
a$ as
|
|
120
|
-
b0 as
|
|
121
|
-
b1 as
|
|
122
|
-
b2 as
|
|
123
|
-
b3 as
|
|
124
|
-
b4 as
|
|
125
|
-
b5 as
|
|
126
|
-
b6 as
|
|
127
|
-
b7 as
|
|
128
|
-
b8 as
|
|
129
|
-
b9 as
|
|
130
|
-
ba as
|
|
131
|
-
bb as
|
|
132
|
-
bc as
|
|
133
|
-
bd as
|
|
134
|
-
be as
|
|
135
|
-
bf as
|
|
136
|
-
bg as
|
|
137
|
-
bh as
|
|
138
|
-
bi as
|
|
139
|
-
bj as
|
|
140
|
-
bk as
|
|
141
|
-
bl as
|
|
142
|
-
bm as
|
|
143
|
-
bn as
|
|
144
|
-
bo as
|
|
145
|
-
bp as
|
|
146
|
-
bq as
|
|
147
|
-
br as
|
|
148
|
-
bs as
|
|
149
|
-
bt as
|
|
150
|
-
bu as
|
|
151
|
-
bv as
|
|
152
|
-
bw as
|
|
153
|
-
bx as
|
|
154
|
-
by as
|
|
155
|
-
bz as
|
|
156
|
-
bA as
|
|
157
|
-
bB as
|
|
158
|
-
bC as
|
|
159
|
-
bD as
|
|
160
|
-
bE as
|
|
161
|
-
bF as
|
|
162
|
-
bG as
|
|
163
|
-
bH as
|
|
164
|
-
bI as
|
|
165
|
-
bJ as
|
|
166
|
-
bK as
|
|
167
|
-
bL as
|
|
168
|
-
bM as
|
|
169
|
-
bN as
|
|
170
|
-
bO as
|
|
171
|
-
bP as
|
|
67
|
+
ab as strictReadActive,
|
|
68
|
+
ac as warnStrictReadUntracked,
|
|
69
|
+
ad as staleReader,
|
|
70
|
+
ae as globalQueue,
|
|
71
|
+
af as joinPass,
|
|
72
|
+
ag as markLateLinker,
|
|
73
|
+
ah as spectating,
|
|
74
|
+
ai as unflushedValue,
|
|
75
|
+
aj as CONFIG_STAGED_ERROR,
|
|
76
|
+
ak as stagedReaders,
|
|
77
|
+
al as bornInto,
|
|
78
|
+
am as enterAction,
|
|
79
|
+
an as setEffectCallback,
|
|
80
|
+
ao as exitAction,
|
|
81
|
+
ap as isThenable,
|
|
82
|
+
aq as actionDepth,
|
|
83
|
+
ar as flush,
|
|
84
|
+
as as setQuestion,
|
|
85
|
+
at as emitDiagnostic,
|
|
86
|
+
au as enterCallback,
|
|
87
|
+
av as exitCallback,
|
|
88
|
+
aw as getOwner,
|
|
89
|
+
ax as inEffectCallback,
|
|
90
|
+
ay as effectCallbackEvent,
|
|
91
|
+
az as setExternalHooks,
|
|
92
|
+
aA as signal,
|
|
93
|
+
aB as setSignal,
|
|
94
|
+
aC as cleanup,
|
|
95
|
+
aD as read,
|
|
96
|
+
aE as DEV$1,
|
|
97
|
+
aF as CONFIG_TRANSPARENT,
|
|
98
|
+
aG as NoOwnerError,
|
|
99
|
+
aH as ContextNotFoundError,
|
|
100
|
+
aI as createEffectNode,
|
|
101
|
+
aJ as recompute,
|
|
102
|
+
aK as EFFECT_USER,
|
|
103
|
+
aL as reportDiagnostic,
|
|
104
|
+
aM as computed,
|
|
105
|
+
aN as staleValues,
|
|
106
|
+
aO as CONFIG_AUTO_DISPOSE,
|
|
107
|
+
aP as EFFECT_TRACKED,
|
|
108
|
+
aQ as heldRunHook,
|
|
109
|
+
aR as unwrapStatusError,
|
|
110
|
+
aS as setStrictRead,
|
|
111
|
+
aT as queueEvent,
|
|
112
|
+
aU as StatusError,
|
|
113
|
+
aV as trimStaleDeps,
|
|
114
|
+
aW as haltReactivityAt,
|
|
115
|
+
aX as strictReadEvent,
|
|
116
|
+
aY as setTrackedQueueCallback,
|
|
117
|
+
aZ as setEffectStatusNotify,
|
|
118
|
+
a_ as _hitUnhandledAsync,
|
|
119
|
+
a$ as resetUnhandledAsync,
|
|
120
|
+
b0 as ROOT_ERROR_HOOK,
|
|
121
|
+
b1 as registerGraph,
|
|
122
|
+
b2 as runWithOwner,
|
|
123
|
+
b3 as setMemo,
|
|
124
|
+
b4 as $REFRESH,
|
|
125
|
+
b5 as markRefresh,
|
|
126
|
+
b6 as createRoot,
|
|
127
|
+
b7 as getObserver,
|
|
128
|
+
b8 as dispose,
|
|
129
|
+
b9 as TimeoutError,
|
|
130
|
+
ba as untrack,
|
|
131
|
+
bb as dirtyQueue,
|
|
132
|
+
bc as CONFIG_REDERIVE,
|
|
133
|
+
bd as passTx,
|
|
134
|
+
be as CONFIG_FRESH_READ,
|
|
135
|
+
bf as createOwner,
|
|
136
|
+
bg as writeHook,
|
|
137
|
+
bh as REACTIVE_WRITE_IN_OWNED_SCOPE_SIGNAL_MESSAGE,
|
|
138
|
+
bi as ownedScopeWriteMessage,
|
|
139
|
+
bj as isEqual,
|
|
140
|
+
bk as CONFIG_MANUAL_WRITE,
|
|
141
|
+
bl as snapshotCaptureActive,
|
|
142
|
+
bm as captureWriteSnapshot,
|
|
143
|
+
bn as notePromotedWrite,
|
|
144
|
+
bo as slotSignal,
|
|
145
|
+
bp as stagedScreen,
|
|
146
|
+
bq as CONFIG_PROMOTED,
|
|
147
|
+
br as setSlotUnobserved,
|
|
148
|
+
bs as installStoreHooks,
|
|
149
|
+
bt as joinPassTx,
|
|
150
|
+
bu as asyncTailFlights,
|
|
151
|
+
bv as untrackDepth,
|
|
152
|
+
bw as checkPostAwaitRead,
|
|
153
|
+
bx as disposalDepth,
|
|
154
|
+
by as insertIntoHeap,
|
|
155
|
+
bz as isDisposed,
|
|
156
|
+
bA as handleAsync,
|
|
157
|
+
bB as addPendingSource,
|
|
158
|
+
bC as propagateStatus,
|
|
159
|
+
bD as forEachDependent,
|
|
160
|
+
bE as settlePendingSource,
|
|
161
|
+
bF as joinPassAt,
|
|
162
|
+
bG as notifyEpoch,
|
|
163
|
+
bH as SUPPORTS_PROXY,
|
|
164
|
+
bI as releaseMarksHook,
|
|
165
|
+
bJ as installMarkHooks,
|
|
166
|
+
bK as CONFIG_LAGS,
|
|
167
|
+
bL as REACTIVE_REASK,
|
|
168
|
+
bM as onSupersede,
|
|
169
|
+
bN as haltReactivity,
|
|
170
|
+
bO as heldUnder,
|
|
171
|
+
bP as unhold,
|
|
172
|
+
bQ as laneStageHook,
|
|
173
|
+
bR as REACTIVE_ZOMBIE,
|
|
174
|
+
bS as installBoundaryHooks,
|
|
175
|
+
bT as CAUGHT_REARMED,
|
|
176
|
+
bU as OBSERVE$1
|
|
172
177
|
} from "./dev-shared.js";
|
|
173
178
|
export {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
179
|
+
bV as clearSnapshots,
|
|
180
|
+
bW as enforceLoadingBoundary,
|
|
181
|
+
bX as getNextChildId,
|
|
182
|
+
bY as markSnapshotScope,
|
|
183
|
+
bZ as peekNextChildId,
|
|
184
|
+
b_ as releaseSnapshotScope,
|
|
185
|
+
b$ as resetErrorHalt,
|
|
186
|
+
c0 as setConsoleFooter,
|
|
187
|
+
c1 as setSnapshotCapture,
|
|
188
|
+
c2 as setWriteHook
|
|
184
189
|
} from "./dev-shared.js";
|
|
185
190
|
|
|
186
191
|
// Truth reads (`until`, `refresh`; CONFIG_AUTHORITATIVE) over lane nodes.
|
|
@@ -1350,7 +1355,7 @@ function verdictValue(el, c) {
|
|
|
1350
1355
|
// verdict read as on any untracked read; the pending throw they add for a
|
|
1351
1356
|
// plain read does not apply — a verdict read is a sanctioned read of a
|
|
1352
1357
|
// pending node (an uninitialized one still throws NotReady below).
|
|
1353
|
-
if (strictRead)
|
|
1358
|
+
if (strictRead && strictReadActive())
|
|
1354
1359
|
warnStrictReadUntracked(strictRead, {
|
|
1355
1360
|
ownerId: c?.id,
|
|
1356
1361
|
ownerName: c?._name,
|
|
@@ -1583,21 +1588,23 @@ function action(genFn) {
|
|
|
1583
1588
|
// it may have been called from — a root created in it (`until`,
|
|
1584
1589
|
// `resolve`) is deliberate (PRIMITIVE_IN_EFFECT_CALLBACK is off).
|
|
1585
1590
|
let effectCallback = false;
|
|
1591
|
+
let effectEvent;
|
|
1586
1592
|
{
|
|
1587
1593
|
enterCallback();
|
|
1588
1594
|
effectCallback = inEffectCallback;
|
|
1595
|
+
effectEvent = effectCallbackEvent;
|
|
1589
1596
|
setEffectCallback(false);
|
|
1590
1597
|
}
|
|
1591
1598
|
try {
|
|
1592
1599
|
r = err ? it.throw(v) : it.next(v);
|
|
1593
1600
|
} catch (e) {
|
|
1594
1601
|
exitAction();
|
|
1595
|
-
(exitCallback(), setEffectCallback(effectCallback));
|
|
1602
|
+
(exitCallback(), setEffectCallback(effectCallback, effectEvent));
|
|
1596
1603
|
if (attrHooks !== null) attrHooks.actionStepEnd(it);
|
|
1597
1604
|
return done(undefined, e, true);
|
|
1598
1605
|
}
|
|
1599
1606
|
exitAction();
|
|
1600
|
-
(exitCallback(), setEffectCallback(effectCallback));
|
|
1607
|
+
(exitCallback(), setEffectCallback(effectCallback, effectEvent));
|
|
1601
1608
|
if (attrHooks !== null) attrHooks.actionStepEnd(it);
|
|
1602
1609
|
// A rejected iterator result (async generators) means the error already
|
|
1603
1610
|
// escaped the generator body — it is completed, and throwing back in
|
|
@@ -1887,10 +1894,9 @@ function effect(compute, effect, error, options) {
|
|
|
1887
1894
|
);
|
|
1888
1895
|
}
|
|
1889
1896
|
}
|
|
1890
|
-
function notifyEffectStatus(
|
|
1891
|
-
|
|
1892
|
-
const
|
|
1893
|
-
const actualError = error !== undefined ? error : this._x?._error;
|
|
1897
|
+
function notifyEffectStatus() {
|
|
1898
|
+
const actualStatus = this._statusFlags;
|
|
1899
|
+
const actualError = this._x?._error;
|
|
1894
1900
|
if (actualStatus & STATUS_ERROR) {
|
|
1895
1901
|
globalQueue.notify(this, STATUS_PENDING, 0);
|
|
1896
1902
|
if (this._type === EFFECT_USER) {
|
|
@@ -1898,24 +1904,22 @@ function notifyEffectStatus(status, error) {
|
|
|
1898
1904
|
// queue it like the effect function. It runs in the same imperative,
|
|
1899
1905
|
// writable scope and throws escalate the same way. No payload is queued — the node already carries `_statusFlags`/`_error`,
|
|
1900
1906
|
// and the runner dispatches on them, so a recovery before the effect
|
|
1901
|
-
// phase takes the success arm instead.
|
|
1902
|
-
//
|
|
1903
|
-
// re-propagates unblocked at commit.
|
|
1907
|
+
// phase takes the success arm instead. (Re-read: the boundary
|
|
1908
|
+
// notify above can run a redraw.)
|
|
1904
1909
|
if (this._statusFlags & STATUS_ERROR) {
|
|
1905
1910
|
this._modified = true;
|
|
1906
1911
|
globalQueue.enqueue(this._type, (this._boundRunEffect ??= runEffect.bind(null, this)));
|
|
1907
1912
|
}
|
|
1908
1913
|
return;
|
|
1909
1914
|
}
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
}
|
|
1915
|
+
// Dev locates the halt at the node that threw: the StatusError's
|
|
1916
|
+
// source, upstream of this effect when a computed failed.
|
|
1917
|
+
escalate(
|
|
1918
|
+
this,
|
|
1919
|
+
unwrapStatusError(actualError),
|
|
1920
|
+
actualError,
|
|
1921
|
+
actualError instanceof StatusError ? actualError.source : this
|
|
1922
|
+
);
|
|
1919
1923
|
} else if (this._type === EFFECT_RENDER) {
|
|
1920
1924
|
globalQueue.notify(this, STATUS_PENDING | STATUS_ERROR, actualStatus, actualError);
|
|
1921
1925
|
if (_hitUnhandledAsync && resetUnhandledAsync()) {
|
|
@@ -1944,6 +1948,14 @@ function notifyEffectStatus(status, error) {
|
|
|
1944
1948
|
}
|
|
1945
1949
|
}
|
|
1946
1950
|
}
|
|
1951
|
+
/** An effect's error no boundary takes halts the system (boundary-or-halt):
|
|
1952
|
+
* halted with `cause`, `thrown` rethrown; dev locates it at `subject`. */
|
|
1953
|
+
function escalate(node, cause, thrown = cause, subject = node) {
|
|
1954
|
+
if (!globalQueue.notify(node, STATUS_ERROR, STATUS_ERROR)) {
|
|
1955
|
+
haltReactivityAt(cause, subject);
|
|
1956
|
+
throw thrown;
|
|
1957
|
+
}
|
|
1958
|
+
}
|
|
1947
1959
|
function runEffect(node, type) {
|
|
1948
1960
|
if (!node._modified || node._flags & REACTIVE_DISPOSED) return;
|
|
1949
1961
|
// A queued run behind a fallback (boundaries.ts) waits for the reveal: a
|
|
@@ -1978,10 +1990,7 @@ function runEffect(node, type) {
|
|
|
1978
1990
|
})
|
|
1979
1991
|
: console.error(err);
|
|
1980
1992
|
} catch (error) {
|
|
1981
|
-
|
|
1982
|
-
haltReactivityAt(error, node);
|
|
1983
|
-
throw error;
|
|
1984
|
-
}
|
|
1993
|
+
escalate(node, error);
|
|
1985
1994
|
}
|
|
1986
1995
|
return;
|
|
1987
1996
|
}
|
|
@@ -1989,9 +1998,13 @@ function runEffect(node, type) {
|
|
|
1989
1998
|
// the compute pass that produced `_value` was clean, so its tail still goes.
|
|
1990
1999
|
const cleanPass = node._x?._error == null;
|
|
1991
2000
|
let prevStrictRead = false;
|
|
2001
|
+
let prevStrictReadEvent;
|
|
1992
2002
|
{
|
|
1993
|
-
|
|
1994
|
-
|
|
2003
|
+
prevStrictReadEvent = strictReadEvent;
|
|
2004
|
+
// A run outside a queue (a render effect's first run at creation) records
|
|
2005
|
+
// no event: its callback is the compiler's DOM writes.
|
|
2006
|
+
prevStrictRead = setStrictRead("an effect callback", queueEvent);
|
|
2007
|
+
setEffectCallback(true, queueEvent);
|
|
1995
2008
|
enterCallback();
|
|
1996
2009
|
}
|
|
1997
2010
|
// Observe tier, like its `effectRunEnd` twin below: the frame the engine
|
|
@@ -2014,13 +2027,10 @@ function runEffect(node, type) {
|
|
|
2014
2027
|
} catch (error) {
|
|
2015
2028
|
ext(node)._error = new StatusError(node, error);
|
|
2016
2029
|
node._statusFlags |= STATUS_ERROR;
|
|
2017
|
-
|
|
2018
|
-
haltReactivityAt(error, node);
|
|
2019
|
-
throw error;
|
|
2020
|
-
}
|
|
2030
|
+
escalate(node, error);
|
|
2021
2031
|
} finally {
|
|
2022
2032
|
{
|
|
2023
|
-
setStrictRead(prevStrictRead);
|
|
2033
|
+
setStrictRead(prevStrictRead, prevStrictReadEvent);
|
|
2024
2034
|
setEffectCallback(false);
|
|
2025
2035
|
exitCallback();
|
|
2026
2036
|
}
|
|
@@ -2210,9 +2220,6 @@ function lookupTarget(raw, fam) {
|
|
|
2210
2220
|
const owner = raw[$OWNER];
|
|
2211
2221
|
return owner !== undefined && owner.fam === fam ? owner : (fam?.map ?? storeLookup).get(raw);
|
|
2212
2222
|
}
|
|
2213
|
-
function devAssertNeverUserMutation(target) {
|
|
2214
|
-
return;
|
|
2215
|
-
}
|
|
2216
2223
|
/** Sticky descendants flag up the parent chain (§6d): adoption descends
|
|
2217
2224
|
* into a changed child pair only where a target with nodes exists below. */
|
|
2218
2225
|
function markDescendants(target) {
|
|
@@ -3835,7 +3842,7 @@ function wrap(value, parent = null, parentKey = null, fam = parent?.fam ?? null)
|
|
|
3835
3842
|
const existing = lookupTarget(value, fam);
|
|
3836
3843
|
if (existing !== undefined) return existing.px;
|
|
3837
3844
|
const t = value[$TARGET];
|
|
3838
|
-
if (t
|
|
3845
|
+
if (t?.px === value) {
|
|
3839
3846
|
// Foreign-family proxies re-wrap into THIS family (writes stay isolated);
|
|
3840
3847
|
// same-family and plain-store proxies pass through.
|
|
3841
3848
|
if (fam === null || t.fam === fam) return value;
|
|
@@ -3907,7 +3914,7 @@ function asBacking(v) {
|
|
|
3907
3914
|
* pending backing is never "equal" to the committed one); a lane value is
|
|
3908
3915
|
* an arrangement (`LaneView`), judged by the optimistic machinery. */
|
|
3909
3916
|
const containerEquals = function (a, b) {
|
|
3910
|
-
return a === b ||
|
|
3917
|
+
return a === b || !!optHooks?.arrangement(this._host, a, b);
|
|
3911
3918
|
};
|
|
3912
3919
|
function sameLogicalSlot(target, a, b) {
|
|
3913
3920
|
if (a === null || typeof a !== "object" || b === null || typeof b !== "object") return false;
|
|
@@ -3924,10 +3931,10 @@ function releaseSlot(node) {
|
|
|
3924
3931
|
if (t.k === node) t.k = null;
|
|
3925
3932
|
} else if (key === $DEEP) {
|
|
3926
3933
|
if (t.dk === node) t.dk = null;
|
|
3927
|
-
} else if (t.n
|
|
3934
|
+
} else if (t.n?.[key] === node) {
|
|
3928
3935
|
delete t.n[key];
|
|
3929
3936
|
t.nc--;
|
|
3930
|
-
} else if (t.h
|
|
3937
|
+
} else if (t.h?.[key] === node) delete t.h[key];
|
|
3931
3938
|
// The family's index keeps only targets that still carry a node.
|
|
3932
3939
|
if (
|
|
3933
3940
|
t.fam !== null &&
|
|
@@ -4008,12 +4015,7 @@ function getNode(
|
|
|
4008
4015
|
accKnown === -1 ? isOwnAccessor(pb ?? target.v, key) : accKnown === 1
|
|
4009
4016
|
));
|
|
4010
4017
|
if (pb !== null && !created.acc)
|
|
4011
|
-
bornStaged(
|
|
4012
|
-
target,
|
|
4013
|
-
created,
|
|
4014
|
-
target.del !== null && target.del.has(key) ? undefined : pb[key],
|
|
4015
|
-
key
|
|
4016
|
-
);
|
|
4018
|
+
bornStaged(target, created, target.del?.has(key) ? undefined : pb[key], key);
|
|
4017
4019
|
// Attribution-only: name store property nodes by path segment so
|
|
4018
4020
|
// attribution chains and wide-scope warnings read "store.todos" (or
|
|
4019
4021
|
// "todos.title" when the store was declared with a name), not
|
|
@@ -4038,8 +4040,7 @@ function getHasNode(target, key) {
|
|
|
4038
4040
|
if (node === undefined) {
|
|
4039
4041
|
const created = (node = slotSignal(key in committed(target), isEqual, target, key, false));
|
|
4040
4042
|
const pb = target.pb;
|
|
4041
|
-
if (pb !== null)
|
|
4042
|
-
bornStaged(target, created, key in pb && !(target.del !== null && target.del.has(key)), key);
|
|
4043
|
+
if (pb !== null) bornStaged(target, created, key in pb && !target.del?.has(key), key);
|
|
4043
4044
|
if (attrHooks !== null) stampNodeOwner(created, target);
|
|
4044
4045
|
nodes[key] = node;
|
|
4045
4046
|
noteNode(target, created, key);
|
|
@@ -4213,7 +4214,7 @@ function scanAccessorsOnce(target) {
|
|
|
4213
4214
|
const keys = Reflect.ownKeys(src);
|
|
4214
4215
|
let plain = Object.getPrototypeOf(src) === Object.prototype;
|
|
4215
4216
|
for (const key of keys) {
|
|
4216
|
-
if (
|
|
4217
|
+
if (isOwnAccessor(src, key)) {
|
|
4217
4218
|
target.a = true;
|
|
4218
4219
|
plain = false;
|
|
4219
4220
|
break;
|
|
@@ -4238,7 +4239,7 @@ const plainProto = o => {
|
|
|
4238
4239
|
* container at flatten so its shape stays fast (#3689). */
|
|
4239
4240
|
function overlayRebuilds(t, pb) {
|
|
4240
4241
|
if (t.kc > OVERLAY_REBUILD_MAX_KEYS) return false;
|
|
4241
|
-
if (t.del
|
|
4242
|
+
if (t.del?.size) return true;
|
|
4242
4243
|
const wk = t.wk;
|
|
4243
4244
|
if (wk !== null && wk !== WK_ALL && wk.u === undefined && wk.size <= OVERLAY_REBUILD_MIN_ADDS)
|
|
4244
4245
|
return false;
|
|
@@ -4252,18 +4253,14 @@ function overlayRebuilds(t, pb) {
|
|
|
4252
4253
|
function materializePB(target) {
|
|
4253
4254
|
const pb = target.pb;
|
|
4254
4255
|
if (!target.ovl) return pb;
|
|
4255
|
-
const clone =
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
}
|
|
4261
|
-
for (const key of Reflect.ownKeys(pb))
|
|
4262
|
-
target.sc === 2 ? (clone[key] = pb[key]) : copyOwn(clone, pb, key);
|
|
4256
|
+
const clone = overlayOnto(
|
|
4257
|
+
target,
|
|
4258
|
+
target.sc === 2 ? wideClone(target.v, target) : cloneRaw(target.v, target),
|
|
4259
|
+
pb
|
|
4260
|
+
);
|
|
4263
4261
|
target.pb = clone;
|
|
4264
|
-
target.ovl = false;
|
|
4265
4262
|
// The staging IS the pending backing: re-point the container node.
|
|
4266
|
-
if (target.k
|
|
4263
|
+
if (target.k?._pendingValue === pb) target.k._pendingValue = clone;
|
|
4267
4264
|
return clone;
|
|
4268
4265
|
}
|
|
4269
4266
|
/** The batch's pending backing, created on the first draft write: an overlay
|
|
@@ -4315,7 +4312,6 @@ function privatizeCommitted(target) {
|
|
|
4315
4312
|
target.ch = false;
|
|
4316
4313
|
if (target.u) {
|
|
4317
4314
|
privatizeCommitted(target.u);
|
|
4318
|
-
devAssertNeverUserMutation(target.u.v);
|
|
4319
4315
|
const pv = target.u.v;
|
|
4320
4316
|
const slot = parentSlotKey(target, before);
|
|
4321
4317
|
if (pv[slot] === before) pv[slot] = target.v;
|
|
@@ -4339,16 +4335,19 @@ function parentSlotKey(target, expected) {
|
|
|
4339
4335
|
* place — the backing keeps its identity. */
|
|
4340
4336
|
function flattenOverlay(t, pb) {
|
|
4341
4337
|
privatizeCommitted(t);
|
|
4342
|
-
|
|
4343
|
-
|
|
4338
|
+
overlayOnto(t, t.v, pb); // the caller (`foldTarget`) closes the staging
|
|
4339
|
+
}
|
|
4340
|
+
/** An overlay's own keys and deletions onto `to` (the two are disjoint: a
|
|
4341
|
+
* write un-deletes its key); the overlay is closed. */
|
|
4342
|
+
function overlayOnto(t, to, pb) {
|
|
4343
|
+
for (const key of Reflect.ownKeys(pb)) t.sc === 2 ? (to[key] = pb[key]) : copyOwn(to, pb, key);
|
|
4344
4344
|
if (t.del !== null) {
|
|
4345
|
-
for (const key of t.del) delete
|
|
4345
|
+
for (const key of t.del) delete to[key];
|
|
4346
4346
|
t.kc -= t.del.size;
|
|
4347
4347
|
t.del = null;
|
|
4348
4348
|
}
|
|
4349
|
-
t.pb = null;
|
|
4350
4349
|
t.ovl = false;
|
|
4351
|
-
|
|
4350
|
+
return to;
|
|
4352
4351
|
}
|
|
4353
4352
|
/** Adoption (a setter's returned replacement; reconcile and projection
|
|
4354
4353
|
* landings in S3): the incoming object becomes the backing by reference at
|
|
@@ -4387,7 +4386,7 @@ function adoptPB(target, incoming, notify = true) {
|
|
|
4387
4386
|
target.a = false;
|
|
4388
4387
|
target.wk = null; // adoption supersedes staged trap writes
|
|
4389
4388
|
const owner = incoming[$OWNER];
|
|
4390
|
-
if (owner
|
|
4389
|
+
if (owner?.fam === target.fam) incoming[$OWNER] = target;
|
|
4391
4390
|
else setLookup(incoming, target);
|
|
4392
4391
|
if (notify && base !== incoming) notifyFold(target, base, incoming);
|
|
4393
4392
|
}
|
|
@@ -4484,7 +4483,7 @@ function drainFolds() {
|
|
|
4484
4483
|
* landing) read it. */
|
|
4485
4484
|
GlobalQueue._slotFlight = n => {
|
|
4486
4485
|
const fam = n._host?.fam;
|
|
4487
|
-
return
|
|
4486
|
+
return (fam?.node?._statusFlags & STATUS_PENDING) !== 0;
|
|
4488
4487
|
};
|
|
4489
4488
|
/** Core asks (lanes.ts `covered`): the value a slot node's guess covered.
|
|
4490
4489
|
* A chained link's committed value is the inner store's at the last
|
|
@@ -4495,8 +4494,8 @@ GlobalQueue._slotCovered = n => {
|
|
|
4495
4494
|
if (t.ch) {
|
|
4496
4495
|
const key = n._key;
|
|
4497
4496
|
const inner = t.v;
|
|
4498
|
-
if (t.h
|
|
4499
|
-
else if (t.n
|
|
4497
|
+
if (t.h?.[key] === n) n._value = untrack(() => key in inner);
|
|
4498
|
+
else if (t.n?.[key] === n) n._value = untrack(() => unwrapValue(inner[key]));
|
|
4500
4499
|
}
|
|
4501
4500
|
return n._value;
|
|
4502
4501
|
};
|
|
@@ -4529,12 +4528,8 @@ function foldTarget(t, old) {
|
|
|
4529
4528
|
const k = t.k;
|
|
4530
4529
|
const pb = t.pb;
|
|
4531
4530
|
if (pb !== null) {
|
|
4532
|
-
if (pb === t.v)
|
|
4533
|
-
|
|
4534
|
-
// the adopted object (shared ownership — never cloned).
|
|
4535
|
-
t.pb = null;
|
|
4536
|
-
t.wk = null;
|
|
4537
|
-
} else if (
|
|
4531
|
+
if (pb === t.v);
|
|
4532
|
+
else if (
|
|
4538
4533
|
t.ovl &&
|
|
4539
4534
|
(t.v !== old || (!overlayRebuilds(t, pb) && k?._x?._snapshotValue !== old))
|
|
4540
4535
|
) {
|
|
@@ -4557,26 +4552,19 @@ function foldTarget(t, old) {
|
|
|
4557
4552
|
else delete v[key];
|
|
4558
4553
|
}
|
|
4559
4554
|
} else {
|
|
4560
|
-
for (const key of Reflect.ownKeys(pb))
|
|
4561
|
-
const d = Object.getOwnPropertyDescriptor(pb, key);
|
|
4562
|
-
if (d.get || d.set || !d.enumerable || !d.writable || !d.configurable)
|
|
4563
|
-
Object.defineProperty(v, key, d);
|
|
4564
|
-
else if (d.value !== old[key] || !hasOwn$1.call(old, key)) v[key] = d.value;
|
|
4565
|
-
}
|
|
4555
|
+
for (const key of Reflect.ownKeys(pb)) copyOwn(v, pb, key);
|
|
4566
4556
|
for (const key of Reflect.ownKeys(old)) {
|
|
4567
4557
|
if (!hasOwn$1.call(pb, key)) delete v[key];
|
|
4568
4558
|
}
|
|
4569
4559
|
}
|
|
4570
|
-
t.pb = null;
|
|
4571
|
-
t.wk = null;
|
|
4572
4560
|
} else {
|
|
4573
4561
|
// The clone (or adopted object) becomes the committed backing
|
|
4574
4562
|
// (path copy below).
|
|
4575
4563
|
t.v = t.ovl ? materializePB(t) : pb;
|
|
4576
4564
|
t.ch = t.v[$TARGET] !== undefined;
|
|
4577
|
-
t.pb = null;
|
|
4578
|
-
t.wk = null;
|
|
4579
4565
|
}
|
|
4566
|
+
t.pb = null;
|
|
4567
|
+
t.wk = null; // the written-keys window closes with the commit
|
|
4580
4568
|
}
|
|
4581
4569
|
if (k !== null) {
|
|
4582
4570
|
// The node's committed value is the backing. A container nobody
|
|
@@ -4591,7 +4579,6 @@ function foldTarget(t, old) {
|
|
|
4591
4579
|
const slot = parentSlotKey(t, old);
|
|
4592
4580
|
if (t.u.v[slot] === old) {
|
|
4593
4581
|
privatizeCommitted(t.u);
|
|
4594
|
-
devAssertNeverUserMutation(t.u.v);
|
|
4595
4582
|
t.u.v[slot] = t.v;
|
|
4596
4583
|
}
|
|
4597
4584
|
}
|
|
@@ -4619,7 +4606,7 @@ function reportReplacedContainers(t, old, pb, writtenKeys) {
|
|
|
4619
4606
|
const owner = storeRootOwner(t);
|
|
4620
4607
|
for (const key of keys) {
|
|
4621
4608
|
if ((isArray && key === "length") || key === $OWNER) continue;
|
|
4622
|
-
if (t.del
|
|
4609
|
+
if (t.del?.has(key)) continue;
|
|
4623
4610
|
const ov = unwrapValue(old[key]);
|
|
4624
4611
|
const nv = unwrapValue(pb[key]);
|
|
4625
4612
|
if (
|
|
@@ -4767,7 +4754,7 @@ function notifyWrites(t) {
|
|
|
4767
4754
|
if (od?.get || od?.set || !isEqual(od?.value, nd.value)) setSignal(node, () => nd.value);
|
|
4768
4755
|
continue;
|
|
4769
4756
|
}
|
|
4770
|
-
const nv = t.del
|
|
4757
|
+
const nv = t.del?.has(key) ? undefined : pb[key];
|
|
4771
4758
|
setSignal(node, () => nv);
|
|
4772
4759
|
if (t.fam !== null) {
|
|
4773
4760
|
// The derive's write is a derivation; a user setter's is a proposal
|
|
@@ -4785,13 +4772,13 @@ function notifyWrites(t) {
|
|
|
4785
4772
|
for (const key of keys) {
|
|
4786
4773
|
const node = has[key];
|
|
4787
4774
|
if (node !== undefined) {
|
|
4788
|
-
setSignal(node, key in pb && !
|
|
4775
|
+
setSignal(node, key in pb && !t.del?.has(key));
|
|
4789
4776
|
if (t.fam !== null) holdWithDerive(t, node);
|
|
4790
4777
|
}
|
|
4791
4778
|
}
|
|
4792
4779
|
}
|
|
4793
4780
|
if (t.dk !== null) {
|
|
4794
|
-
if (t.del
|
|
4781
|
+
if (t.del?.size) bumpDeep(t);
|
|
4795
4782
|
else
|
|
4796
4783
|
for (const key of writtenKeys ?? Reflect.ownKeys(pb)) {
|
|
4797
4784
|
if (key === $OWNER) continue;
|
|
@@ -4811,7 +4798,7 @@ function notifyWrites(t) {
|
|
|
4811
4798
|
if (k !== null && (k._subs !== null || k._config & CONFIG_OVERRIDE)) {
|
|
4812
4799
|
let changed;
|
|
4813
4800
|
if (t.ovl) {
|
|
4814
|
-
changed = t.del
|
|
4801
|
+
changed = !!t.del?.size;
|
|
4815
4802
|
if (!changed) {
|
|
4816
4803
|
for (const key of Reflect.ownKeys(pb)) {
|
|
4817
4804
|
if (!hasOwn$1.call(old, key)) {
|
|
@@ -4966,7 +4953,7 @@ function serveShallow(target, key, v) {
|
|
|
4966
4953
|
function draftServe(target, proxy) {
|
|
4967
4954
|
if (writeScopes !== null && inDraft(target)) {
|
|
4968
4955
|
const ct = proxy?.[$TARGET];
|
|
4969
|
-
if (ct
|
|
4956
|
+
if (ct?.v !== undefined) writeScopes.add(scopeKey(ct));
|
|
4970
4957
|
}
|
|
4971
4958
|
return proxy;
|
|
4972
4959
|
}
|
|
@@ -5009,13 +4996,7 @@ function readSource(target, key, shape = false) {
|
|
|
5009
4996
|
// sees — the lanes' values and the tick's own guesses over the truth
|
|
5010
4997
|
// (#3665), never a staging awaiting its fold: the draft is born on the
|
|
5011
4998
|
// read (and notified at the setter's exit like any).
|
|
5012
|
-
if (
|
|
5013
|
-
userWrite &&
|
|
5014
|
-
target.fam !== null &&
|
|
5015
|
-
target.fam.opt === true &&
|
|
5016
|
-
!pendingNotify.has(target) &&
|
|
5017
|
-
inDraft(target)
|
|
5018
|
-
) {
|
|
4999
|
+
if (userWrite && target.fam?.opt === true && !pendingNotify.has(target) && inDraft(target)) {
|
|
5019
5000
|
const draft = ensurePB(target);
|
|
5020
5001
|
pendingNotify.add(target);
|
|
5021
5002
|
return draft;
|
|
@@ -5054,7 +5035,7 @@ function readSource(target, key, shape = false) {
|
|
|
5054
5035
|
// it).
|
|
5055
5036
|
if (key !== undefined) {
|
|
5056
5037
|
const leaf = target.n?.[key];
|
|
5057
|
-
if (leaf
|
|
5038
|
+
if (leaf?._config & CONFIG_OVERRIDE) return committed(target);
|
|
5058
5039
|
}
|
|
5059
5040
|
const held = k !== null && (k._config & CONFIG_HELD) !== 0;
|
|
5060
5041
|
// A held container: the hold's unit is the key (#3706). A key the HELD
|
|
@@ -5168,18 +5149,14 @@ function adoptChild(target, key) {
|
|
|
5168
5149
|
// A raw-marked value wraps to itself, a proxy to its own target: neither
|
|
5169
5150
|
// is a fresh target around `ov`.
|
|
5170
5151
|
const ct = wrap(ov, target, key)[$TARGET];
|
|
5171
|
-
if (ct
|
|
5152
|
+
if (ct?.v !== ov) return false;
|
|
5172
5153
|
adoptPB(ct, nv, false);
|
|
5173
5154
|
holdNode(getContainerNode(ct), txOf(k));
|
|
5174
5155
|
return true;
|
|
5175
5156
|
}
|
|
5176
5157
|
/** A family target's unheld staging, read with no pass (a handler). */
|
|
5177
5158
|
function familyAhead(target) {
|
|
5178
|
-
return (
|
|
5179
|
-
target.fam !== null &&
|
|
5180
|
-
context === null &&
|
|
5181
|
-
!(target.k !== null && target.k._config & CONFIG_HELD)
|
|
5182
|
-
);
|
|
5159
|
+
return target.fam !== null && context === null && !(target.k?._config & CONFIG_HELD);
|
|
5183
5160
|
}
|
|
5184
5161
|
/** Did this batch change `key` — value (slot equality), presence, and (for
|
|
5185
5162
|
* a `shape` reader — a descriptor read, a node's hold) enumerability or
|
|
@@ -5204,7 +5181,7 @@ function changedBetween(target, v, pb, key, shape) {
|
|
|
5204
5181
|
!plainProto(v)
|
|
5205
5182
|
)
|
|
5206
5183
|
return true;
|
|
5207
|
-
if (target.del
|
|
5184
|
+
if (target.del?.has(key)) return key in v;
|
|
5208
5185
|
const inNew = hasOwn$1.call(pb, key) || (target.ovl && hasOwn$1.call(target.v, key));
|
|
5209
5186
|
if (inNew !== hasOwn$1.call(v, key)) return true;
|
|
5210
5187
|
if (!inNew) return false;
|
|
@@ -5385,7 +5362,7 @@ function enumerationSource(target) {
|
|
|
5385
5362
|
* draft's (it composed already), not a derive's write-override read (the
|
|
5386
5363
|
* derive composes on the truth). */
|
|
5387
5364
|
function optRead(target) {
|
|
5388
|
-
return target.fam
|
|
5365
|
+
return target.fam?.opt === true && !inDraft(target) && !writeOverride;
|
|
5389
5366
|
}
|
|
5390
5367
|
/** Pollution keys are never served from the prototype (core R30). */
|
|
5391
5368
|
const UNSAFE_KEYS = new Set(["__proto__", "prototype", "constructor"]);
|
|
@@ -5511,7 +5488,7 @@ const traps = {
|
|
|
5511
5488
|
const src = readSource(target, key);
|
|
5512
5489
|
// Overlay delete (#3044): a prototype overlay cannot shadow a delete, so
|
|
5513
5490
|
// deleted keys are tracked aside and read as absent in the pending view.
|
|
5514
|
-
if (
|
|
5491
|
+
if (src === target.pb && target.del?.has(key)) {
|
|
5515
5492
|
if (!inDraft(target) && getObserver() !== null) read(getNode(target, key));
|
|
5516
5493
|
return undefined;
|
|
5517
5494
|
}
|
|
@@ -5539,7 +5516,8 @@ const traps = {
|
|
|
5539
5516
|
!inDraft(target) &&
|
|
5540
5517
|
typeof key === "string" &&
|
|
5541
5518
|
key !== "then" &&
|
|
5542
|
-
getObserver() === null
|
|
5519
|
+
getObserver() === null &&
|
|
5520
|
+
strictReadActive()
|
|
5543
5521
|
) {
|
|
5544
5522
|
warnStrictReadUntracked(strictRead, {
|
|
5545
5523
|
nodeName: key,
|
|
@@ -5643,7 +5621,7 @@ const traps = {
|
|
|
5643
5621
|
if (guessed !== undefined) return guessed;
|
|
5644
5622
|
}
|
|
5645
5623
|
}
|
|
5646
|
-
return key in src && !(
|
|
5624
|
+
return key in src && !(src === target.pb && target.del?.has(key));
|
|
5647
5625
|
},
|
|
5648
5626
|
ownKeys(target) {
|
|
5649
5627
|
if (verdict !== null && affectsHooks !== null && getObserver() === null)
|
|
@@ -5690,8 +5668,7 @@ const traps = {
|
|
|
5690
5668
|
},
|
|
5691
5669
|
set(target, key, value) {
|
|
5692
5670
|
const draft = inDraft(target);
|
|
5693
|
-
|
|
5694
|
-
if (!draft && !override) {
|
|
5671
|
+
if (!draft && !writeOverride) {
|
|
5695
5672
|
warnWriteOutsideSetter(target, key, "set");
|
|
5696
5673
|
return true;
|
|
5697
5674
|
}
|
|
@@ -5717,17 +5694,8 @@ const traps = {
|
|
|
5717
5694
|
touch(target, key);
|
|
5718
5695
|
if (!(key in pb)) target.kc++;
|
|
5719
5696
|
}
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
value: uv,
|
|
5723
|
-
writable: true,
|
|
5724
|
-
enumerable: true,
|
|
5725
|
-
configurable: true
|
|
5726
|
-
});
|
|
5727
|
-
if (target.del !== null) target.del.delete(key);
|
|
5728
|
-
return true;
|
|
5729
|
-
}
|
|
5730
|
-
if (target.ovl && target.sc !== 2 && !hasOwn$1.call(pb, key)) {
|
|
5697
|
+
const unsafe = UNSAFE_KEYS.has(key);
|
|
5698
|
+
if (unsafe || (target.ovl && target.sc !== 2 && !hasOwn$1.call(pb, key))) {
|
|
5731
5699
|
Object.defineProperty(pb, key, {
|
|
5732
5700
|
value: uv,
|
|
5733
5701
|
writable: true,
|
|
@@ -5735,15 +5703,15 @@ const traps = {
|
|
|
5735
5703
|
configurable: true
|
|
5736
5704
|
});
|
|
5737
5705
|
} else pb[key] = uv;
|
|
5738
|
-
|
|
5706
|
+
target.del?.delete(key);
|
|
5707
|
+
if (unsafe) return true;
|
|
5739
5708
|
if (target.s && uv !== null && typeof uv === "object") markRawOne(uv);
|
|
5740
|
-
if (
|
|
5709
|
+
if (!draft) notifyWrites(target); // a write-override write
|
|
5741
5710
|
return true;
|
|
5742
5711
|
},
|
|
5743
5712
|
defineProperty(target, key, desc) {
|
|
5744
5713
|
const draft = inDraft(target);
|
|
5745
|
-
|
|
5746
|
-
if (!draft && !override) {
|
|
5714
|
+
if (!draft && !writeOverride) {
|
|
5747
5715
|
warnWriteOutsideSetter(target, key, "defineProperty");
|
|
5748
5716
|
return true;
|
|
5749
5717
|
}
|
|
@@ -5754,14 +5722,13 @@ const traps = {
|
|
|
5754
5722
|
if (target.a || !(desc.enumerable && desc.writable && desc.configurable)) target.sc = 1;
|
|
5755
5723
|
touch(target, key);
|
|
5756
5724
|
Object.defineProperty(pb, key, desc);
|
|
5757
|
-
|
|
5758
|
-
if (
|
|
5725
|
+
target.del?.delete(key);
|
|
5726
|
+
if (!draft) notifyWrites(target); // a write-override write
|
|
5759
5727
|
return true;
|
|
5760
5728
|
},
|
|
5761
5729
|
deleteProperty(target, key) {
|
|
5762
5730
|
const draft = inDraft(target);
|
|
5763
|
-
|
|
5764
|
-
if (!draft && !override) {
|
|
5731
|
+
if (!draft && !writeOverride) {
|
|
5765
5732
|
warnWriteOutsideSetter(target, key, "deleteProperty");
|
|
5766
5733
|
return true;
|
|
5767
5734
|
}
|
|
@@ -5782,7 +5749,7 @@ const traps = {
|
|
|
5782
5749
|
committed || target.kc--;
|
|
5783
5750
|
}
|
|
5784
5751
|
if (committed) (target.del ??= new Set()).add(key);
|
|
5785
|
-
if (
|
|
5752
|
+
if (!draft) notifyWrites(target); // a write-override write
|
|
5786
5753
|
return true;
|
|
5787
5754
|
}
|
|
5788
5755
|
};
|
|
@@ -5943,17 +5910,17 @@ function createStore$1(initialValue, options) {
|
|
|
5943
5910
|
* slot-patch channel (collected row bodies) over per-record registration. */
|
|
5944
5911
|
function storeIsShallow(proxy) {
|
|
5945
5912
|
const t = proxy?.[$TARGET];
|
|
5946
|
-
return t
|
|
5913
|
+
return t?.s === true;
|
|
5947
5914
|
}
|
|
5948
5915
|
/** True when `proxy` belongs to a projection family (S3). */
|
|
5949
5916
|
function storeHasFamily(proxy) {
|
|
5950
5917
|
const t = proxy?.[$TARGET];
|
|
5951
|
-
return t
|
|
5918
|
+
return t?.fam != null;
|
|
5952
5919
|
}
|
|
5953
5920
|
/** True when `proxy` belongs to an OPTIMISTIC family (S4). */
|
|
5954
5921
|
function storeHasOptimisticFamily(proxy) {
|
|
5955
5922
|
const t = proxy?.[$TARGET];
|
|
5956
|
-
return t
|
|
5923
|
+
return t?.fam?.opt === true;
|
|
5957
5924
|
}
|
|
5958
5925
|
// ---------------------------------------------------------------------------
|
|
5959
5926
|
// enumeration views (one visibility rule for the traps AND the deep walk)
|
|
@@ -5962,7 +5929,7 @@ function visibleKeys(target, src) {
|
|
|
5962
5929
|
if (target.ovl && src === target.pb) {
|
|
5963
5930
|
keys = Reflect.ownKeys(target.v);
|
|
5964
5931
|
const del = target.del;
|
|
5965
|
-
if (del
|
|
5932
|
+
if (del?.size) keys = keys.filter(key => !del.has(key));
|
|
5966
5933
|
for (const key of Reflect.ownKeys(src)) {
|
|
5967
5934
|
if (!hasOwn$1.call(target.v, key)) keys.push(key);
|
|
5968
5935
|
}
|
|
@@ -5979,7 +5946,7 @@ function visibleKeys(target, src) {
|
|
|
5979
5946
|
function visibleDescriptor(target, src, key) {
|
|
5980
5947
|
let desc = Object.getOwnPropertyDescriptor(src, key);
|
|
5981
5948
|
if (target.ovl && src === target.pb) {
|
|
5982
|
-
if (target.del
|
|
5949
|
+
if (target.del?.has(key)) return undefined;
|
|
5983
5950
|
if (desc === undefined) desc = Object.getOwnPropertyDescriptor(target.v, key);
|
|
5984
5951
|
}
|
|
5985
5952
|
return desc;
|
|
@@ -5990,7 +5957,7 @@ function visibleDescriptor(target, src, key) {
|
|
|
5990
5957
|
* witness (one node per record, not one per path), then snapshots. */
|
|
5991
5958
|
function deep$1(value) {
|
|
5992
5959
|
const t0 = value?.[$TARGET];
|
|
5993
|
-
if (t0
|
|
5960
|
+
if (t0?.px !== value) return value;
|
|
5994
5961
|
const visited = new Set();
|
|
5995
5962
|
const childTarget = (t, child, key) => {
|
|
5996
5963
|
let ct = lookupTarget(child, t.fam);
|
|
@@ -6232,8 +6199,8 @@ const storePath = /* @__PURE__ */ Object.assign(
|
|
|
6232
6199
|
*/
|
|
6233
6200
|
function reconcileState(value, state, key, replace = false) {
|
|
6234
6201
|
if (state == null) throw new Error("Cannot reconcile null or undefined state");
|
|
6235
|
-
const t = state
|
|
6236
|
-
if (t
|
|
6202
|
+
const t = state[$TARGET];
|
|
6203
|
+
if (t?.px !== state) throw new Error("reconcile target is not a store proxy");
|
|
6237
6204
|
const keyFn = key === null ? null : typeof key === "string" ? item => item?.[key] : key;
|
|
6238
6205
|
// A user's reconcile on an optimistic family (S4): not an adoption of
|
|
6239
6206
|
// truth but an optimistic edit — the keyed diff is written into the draft
|
|
@@ -6258,9 +6225,8 @@ function reconcileState(value, state, key, replace = false) {
|
|
|
6258
6225
|
if (!replace) throw new Error("Cannot reconcile states with different identity");
|
|
6259
6226
|
// A different entity at the root: the old backing is disowned (wraps
|
|
6260
6227
|
// fresh if re-handed) and the new one adopted whole.
|
|
6261
|
-
|
|
6262
|
-
|
|
6263
|
-
else (t.fam?.map ?? storeLookup).delete(out);
|
|
6228
|
+
if (isOwned(prev)) delete prev[$OWNER];
|
|
6229
|
+
else (t.fam?.map ?? storeLookup).delete(prev);
|
|
6264
6230
|
adoptPB(t, incoming);
|
|
6265
6231
|
return;
|
|
6266
6232
|
}
|
|
@@ -6276,50 +6242,42 @@ function applyAdopt(t, incoming, keyFn, proj = false) {
|
|
|
6276
6242
|
// as present through its prototype; materialized first — `adoptPB` does
|
|
6277
6243
|
// so anyway, after the base was taken — so a deletion the draft made is
|
|
6278
6244
|
// a deletion here (#3743: the presence and value diffs both read `old`).
|
|
6279
|
-
const
|
|
6280
|
-
if (incoming ===
|
|
6281
|
-
const fam = t.fam;
|
|
6245
|
+
const old = t.ovl ? materializePB(t) : (t.pb ?? t.v);
|
|
6246
|
+
if (incoming === old && !isOwned(old)) return;
|
|
6282
6247
|
// Q-D: a landing on an optimistic family is reconciled against the VIEW
|
|
6283
6248
|
// — key matching from the arrangement the guesses made (R28), so a row
|
|
6284
6249
|
// the guess added keeps its proxy when the server returns it.
|
|
6285
|
-
const prevView = fam?.opt === true ? optHooks.view(t,
|
|
6250
|
+
const prevView = t.fam?.opt === true ? optHooks.view(t, old) : old;
|
|
6286
6251
|
const nextArr = Array.isArray(incoming);
|
|
6287
6252
|
const shallow = t.s === true;
|
|
6288
|
-
const old = prev;
|
|
6289
6253
|
adoptPB(t, incoming, false);
|
|
6290
6254
|
if (shallow) markRawIngest(incoming);
|
|
6255
|
+
// The deep witness is bumped once per adoption (none to bump: done).
|
|
6256
|
+
let bumped = t.dk === null;
|
|
6291
6257
|
if (Array.isArray(prevView) !== nextArr) {
|
|
6292
6258
|
notifyFold(t, old, incoming);
|
|
6293
6259
|
return;
|
|
6294
6260
|
}
|
|
6295
6261
|
if (nextArr) {
|
|
6296
|
-
const prevRows = prevView;
|
|
6297
|
-
const nextRows = incoming;
|
|
6298
6262
|
const nodes = t.n;
|
|
6299
6263
|
let nodesHit = 0;
|
|
6300
6264
|
if (keyFn && !shallow) {
|
|
6301
|
-
const plen =
|
|
6302
|
-
const nlen =
|
|
6303
|
-
let dkBumpedA = false;
|
|
6265
|
+
const plen = prevView.length;
|
|
6266
|
+
const nlen = incoming.length;
|
|
6304
6267
|
let i = 0;
|
|
6305
6268
|
// Aligned prefix: same row (by reference or key) at the same index.
|
|
6306
6269
|
for (const end = Math.min(plen, nlen); i < end; i++) {
|
|
6307
|
-
const nv =
|
|
6308
|
-
const pvRaw =
|
|
6270
|
+
const nv = incoming[i];
|
|
6271
|
+
const pvRaw = prevView[i];
|
|
6309
6272
|
if (pvRaw !== nv && !sameRow$1(pvRaw, nv, keyFn)) break; // misaligned: fall to the keyed remainder below
|
|
6273
|
+
if (nv !== null && typeof nv === "object" && (pvRaw !== nv || isOwned(nv)))
|
|
6274
|
+
descend(unwrapValue(pvRaw), nv, keyFn, proj, t, i);
|
|
6310
6275
|
if (
|
|
6311
|
-
|
|
6312
|
-
nv !== null &&
|
|
6313
|
-
typeof nv === "object"
|
|
6314
|
-
)
|
|
6315
|
-
descend(unwrapValue(pvRaw), nv, keyFn, fam, proj);
|
|
6316
|
-
if (
|
|
6317
|
-
t.dk !== null &&
|
|
6318
|
-
!dkBumpedA &&
|
|
6276
|
+
!bumped &&
|
|
6319
6277
|
!(nv !== null && typeof nv === "object" ? targetsEqual(pvRaw, nv) : isEqual(pvRaw, nv))
|
|
6320
6278
|
) {
|
|
6321
6279
|
bumpDeep(t);
|
|
6322
|
-
|
|
6280
|
+
bumped = true;
|
|
6323
6281
|
}
|
|
6324
6282
|
if (nodes !== null) {
|
|
6325
6283
|
const node = nodes[i];
|
|
@@ -6329,19 +6287,19 @@ function applyAdopt(t, incoming, keyFn, proj = false) {
|
|
|
6329
6287
|
}
|
|
6330
6288
|
}
|
|
6331
6289
|
}
|
|
6332
|
-
if (
|
|
6290
|
+
if (!bumped && i < incoming.length) bumpDeep(t);
|
|
6333
6291
|
const structStart = i; // misalignment point (== nlen on aligned ticks)
|
|
6334
6292
|
let prevByKey = null;
|
|
6335
|
-
for (; i <
|
|
6336
|
-
const nv =
|
|
6293
|
+
for (; i < incoming.length; i++) {
|
|
6294
|
+
const nv = incoming[i];
|
|
6337
6295
|
if (nv !== null && typeof nv === "object") {
|
|
6338
6296
|
const nk = keyFn(nv);
|
|
6339
6297
|
let pv;
|
|
6340
6298
|
if (nk !== undefined) {
|
|
6341
6299
|
if (prevByKey === null) {
|
|
6342
6300
|
prevByKey = new Map();
|
|
6343
|
-
for (let j = structStart; j <
|
|
6344
|
-
const p = unwrapValue(
|
|
6301
|
+
for (let j = structStart; j < prevView.length; j++) {
|
|
6302
|
+
const p = unwrapValue(prevView[j]);
|
|
6345
6303
|
if (p !== null && typeof p === "object") {
|
|
6346
6304
|
const pk = keyFn(p);
|
|
6347
6305
|
if (pk === undefined) continue;
|
|
@@ -6355,16 +6313,16 @@ function applyAdopt(t, incoming, keyFn, proj = false) {
|
|
|
6355
6313
|
const m = prevByKey.get(nk);
|
|
6356
6314
|
if (m === undefined) pv = undefined;
|
|
6357
6315
|
else if (Array.isArray(m)) {
|
|
6358
|
-
pv = unwrapValue(
|
|
6316
|
+
pv = unwrapValue(prevView[m.shift()]);
|
|
6359
6317
|
if (m.length === 1) prevByKey.set(nk, m[0]);
|
|
6360
6318
|
} else {
|
|
6361
|
-
pv = unwrapValue(
|
|
6319
|
+
pv = unwrapValue(prevView[m]);
|
|
6362
6320
|
prevByKey.delete(nk);
|
|
6363
6321
|
}
|
|
6364
6322
|
} else {
|
|
6365
|
-
pv = unwrapValue(
|
|
6323
|
+
pv = unwrapValue(prevView[i]); // keyless item: positional fallback
|
|
6366
6324
|
}
|
|
6367
|
-
descend(pv, nv, keyFn,
|
|
6325
|
+
descend(pv, nv, keyFn, proj, t, i);
|
|
6368
6326
|
}
|
|
6369
6327
|
if (nodes !== null) {
|
|
6370
6328
|
const node = nodes[i];
|
|
@@ -6375,22 +6333,20 @@ function applyAdopt(t, incoming, keyFn, proj = false) {
|
|
|
6375
6333
|
}
|
|
6376
6334
|
}
|
|
6377
6335
|
} else {
|
|
6378
|
-
const dlen = Math.min(
|
|
6379
|
-
const nlen =
|
|
6380
|
-
let dkBumpedP = false;
|
|
6336
|
+
const dlen = Math.min(prevView.length, incoming.length);
|
|
6337
|
+
const nlen = incoming.length;
|
|
6381
6338
|
for (let i = 0; i < nlen; i++) {
|
|
6382
|
-
const nvP =
|
|
6339
|
+
const nvP = incoming[i];
|
|
6383
6340
|
if (!shallow && i < dlen && nvP !== null && typeof nvP === "object")
|
|
6384
|
-
descend(unwrapValue(
|
|
6341
|
+
descend(unwrapValue(prevView[i]), nvP, keyFn, proj, t, i);
|
|
6385
6342
|
if (
|
|
6386
|
-
|
|
6387
|
-
!dkBumpedP &&
|
|
6343
|
+
!bumped &&
|
|
6388
6344
|
!(nvP !== null && typeof nvP === "object"
|
|
6389
|
-
? targetsEqual(
|
|
6390
|
-
: isEqual(
|
|
6345
|
+
? targetsEqual(prevView[i], nvP)
|
|
6346
|
+
: isEqual(prevView[i], nvP))
|
|
6391
6347
|
) {
|
|
6392
6348
|
bumpDeep(t);
|
|
6393
|
-
|
|
6349
|
+
bumped = true;
|
|
6394
6350
|
}
|
|
6395
6351
|
if (nodes !== null) {
|
|
6396
6352
|
const node = nodes[i];
|
|
@@ -6405,7 +6361,7 @@ function applyAdopt(t, incoming, keyFn, proj = false) {
|
|
|
6405
6361
|
if (nodes !== null && nodesHit < t.nc) {
|
|
6406
6362
|
for (const key of Reflect.ownKeys(nodes)) {
|
|
6407
6363
|
const idx = typeof key === "string" ? +key : NaN;
|
|
6408
|
-
if (!(idx >= 0 && idx <
|
|
6364
|
+
if (!(idx >= 0 && idx < incoming.length))
|
|
6409
6365
|
notifyKeyDiff(nodes[key], key, old, incoming, false);
|
|
6410
6366
|
}
|
|
6411
6367
|
}
|
|
@@ -6414,7 +6370,6 @@ function applyAdopt(t, incoming, keyFn, proj = false) {
|
|
|
6414
6370
|
}
|
|
6415
6371
|
const nodes = t.n;
|
|
6416
6372
|
let nodesHit = 0;
|
|
6417
|
-
let dkBumped = false;
|
|
6418
6373
|
for (const k in incoming) {
|
|
6419
6374
|
const nv = incoming[k];
|
|
6420
6375
|
const ov = old[k];
|
|
@@ -6424,13 +6379,13 @@ function applyAdopt(t, incoming, keyFn, proj = false) {
|
|
|
6424
6379
|
(!isObj || !isOwned(nv)) &&
|
|
6425
6380
|
(nodes === null || nodes[k] === undefined || !hasAccessorFlag(nodes[k]))
|
|
6426
6381
|
) {
|
|
6427
|
-
if (nodes
|
|
6382
|
+
if (nodes?.[k] !== undefined) nodesHit++;
|
|
6428
6383
|
continue;
|
|
6429
6384
|
}
|
|
6430
|
-
if (isObj && !shallow) descend(unwrapValue(prevView[k]), nv, keyFn,
|
|
6431
|
-
if (
|
|
6385
|
+
if (isObj && !shallow) descend(unwrapValue(prevView[k]), nv, keyFn, proj, t, k);
|
|
6386
|
+
if (!bumped && !(isObj ? targetsEqual(ov, nv) : isEqual(ov, nv))) {
|
|
6432
6387
|
bumpDeep(t);
|
|
6433
|
-
|
|
6388
|
+
bumped = true;
|
|
6434
6389
|
}
|
|
6435
6390
|
if (nodes !== null) {
|
|
6436
6391
|
const node = nodes[k];
|
|
@@ -6446,7 +6401,7 @@ function applyAdopt(t, incoming, keyFn, proj = false) {
|
|
|
6446
6401
|
if (k === $OWNER) continue;
|
|
6447
6402
|
const nv = incoming[k];
|
|
6448
6403
|
if (!shallow && nv !== null && typeof nv === "object")
|
|
6449
|
-
descend(unwrapValue(old[k]), nv, keyFn,
|
|
6404
|
+
descend(unwrapValue(old[k]), nv, keyFn, proj, t, k);
|
|
6450
6405
|
if (nodes !== null) {
|
|
6451
6406
|
const node = nodes[k];
|
|
6452
6407
|
if (node !== undefined) {
|
|
@@ -6466,16 +6421,39 @@ function applyAdopt(t, incoming, keyFn, proj = false) {
|
|
|
6466
6421
|
const hasOwnP = Object.prototype.hasOwnProperty;
|
|
6467
6422
|
/** Descend into a changed child pair — only where something is proxied
|
|
6468
6423
|
* below (§6d), never into a raw-marked leaf, never across array/object or a
|
|
6469
|
-
* key mismatch (that is a replacement, handled by the parent's slot).
|
|
6470
|
-
|
|
6471
|
-
|
|
6472
|
-
|
|
6424
|
+
* key mismatch (that is a replacement, handled by the parent's slot).
|
|
6425
|
+
*
|
|
6426
|
+
* A raw in both frames (the same objects swapped, reordered or shifted,
|
|
6427
|
+
* #4001) must not leave two slots on one row. A raw already a live row keeps
|
|
6428
|
+
* it at the slot it moved to; a row's `pk` follows the slot it sits at (a
|
|
6429
|
+
* move or a pairing writes it), so a row whose raw is at that slot of the
|
|
6430
|
+
* incoming frame is spoken for and not paired again here; a raw still
|
|
6431
|
+
* resolving to a row that moved on drops the lookup (it wraps fresh, or is
|
|
6432
|
+
* paired here). One lookup of `nv` on the common path, no allocation. */
|
|
6433
|
+
function descend(pv, nv, keyFn, proj, t, k) {
|
|
6434
|
+
// `nv` is an object at every call site.
|
|
6435
|
+
if (pv === null || typeof pv !== "object") return;
|
|
6436
|
+
const fam = t.fam;
|
|
6437
|
+
nv = unwrapValue(nv);
|
|
6438
|
+
let ct = lookupTarget(pv, fam);
|
|
6439
|
+
const nt = lookupTarget(nv, fam);
|
|
6440
|
+
if (ct !== undefined && ct.pk !== k) {
|
|
6441
|
+
if (ct.pk != k && t.v[ct.pk] === ct.v) ct = undefined;
|
|
6442
|
+
else if (ct.u === t) ct.pk = k;
|
|
6443
|
+
}
|
|
6444
|
+
if (nt !== undefined && nt !== ct) {
|
|
6445
|
+
if (nt.v === nv) {
|
|
6446
|
+
if (nt.u === t) nt.pk = k;
|
|
6447
|
+
return;
|
|
6448
|
+
}
|
|
6449
|
+
(fam?.map ?? storeLookup).delete(nv);
|
|
6450
|
+
}
|
|
6473
6451
|
if (ct === undefined) return; // nothing proxied below this pair
|
|
6474
6452
|
if (!isWrappable(nv)) return;
|
|
6475
6453
|
if (rawValuesUsed && isRawValue(nv)) return;
|
|
6476
|
-
nv = unwrapValue(nv);
|
|
6477
6454
|
if (Array.isArray(pv) !== Array.isArray(nv)) return;
|
|
6478
|
-
|
|
6455
|
+
// An array slot was paired by key already (or both rows are keyless).
|
|
6456
|
+
if (typeof k !== "number" && keyFn) {
|
|
6479
6457
|
const pk = keyFn(pv);
|
|
6480
6458
|
const nk = keyFn(nv);
|
|
6481
6459
|
if (pk !== undefined && nk !== undefined && !sameKey(pk, nk)) return;
|
|
@@ -8911,6 +8889,7 @@ function createDeferred(fn, options) {
|
|
|
8911
8889
|
// The wrapping form: an unready source parks the node in the window,
|
|
8912
8890
|
// and the wait is its flight until the source's settle re-runs it.
|
|
8913
8891
|
if (open && e instanceof NotReadyError) ask(e);
|
|
8892
|
+
else land(flight);
|
|
8914
8893
|
throw e;
|
|
8915
8894
|
}
|
|
8916
8895
|
if (open && typeof r === "object" && r !== null) {
|
|
@@ -8931,7 +8910,11 @@ function createDeferred(fn, options) {
|
|
|
8931
8910
|
// promise, as for a plain flight: verdict and value in one flush.
|
|
8932
8911
|
next: v => {
|
|
8933
8912
|
const p = it.next(v);
|
|
8934
|
-
if (first)
|
|
8913
|
+
if (first) {
|
|
8914
|
+
first = false;
|
|
8915
|
+
if (isThenable(p)) p.then(done, done);
|
|
8916
|
+
else done();
|
|
8917
|
+
}
|
|
8935
8918
|
return p;
|
|
8936
8919
|
},
|
|
8937
8920
|
return: v => it.return?.(v) ?? Promise.resolve({ done: true, value: v })
|
|
@@ -8946,6 +8929,238 @@ function createDeferred(fn, options) {
|
|
|
8946
8929
|
);
|
|
8947
8930
|
}
|
|
8948
8931
|
|
|
8932
|
+
// `from` — a push source (callback subscription, Observable, AsyncIterable)
|
|
8933
|
+
// as an AsyncIterable a computation can return or `for await` over:
|
|
8934
|
+
//
|
|
8935
|
+
// const value = createMemo(() => from(source));
|
|
8936
|
+
//
|
|
8937
|
+
// A subscription keeps the latest value: values that arrive between pulls
|
|
8938
|
+
// coalesce. An AsyncIterable streams through unchanged. Either way the source
|
|
8939
|
+
// opens when the result is iterated and closes on return(), on supersede (the
|
|
8940
|
+
// owning computation re-runs) and on owner disposal, whichever comes first.
|
|
8941
|
+
function toSubscribe(source) {
|
|
8942
|
+
if (typeof source === "function") return source;
|
|
8943
|
+
// TC39 / RxJS interop: `Symbol.observable` (or "@@observable") returns the observable.
|
|
8944
|
+
// Read per call, not at module scope, so the module stays side-effect free.
|
|
8945
|
+
const $$observable = Symbol.observable;
|
|
8946
|
+
const interop = ($$observable && source?.[$$observable]) ?? source?.["@@observable"];
|
|
8947
|
+
const obs = typeof interop === "function" ? interop.call(source) : source;
|
|
8948
|
+
if (obs && typeof obs.subscribe === "function")
|
|
8949
|
+
return (next, error, complete) => obs.subscribe({ next, error, complete });
|
|
8950
|
+
return null;
|
|
8951
|
+
}
|
|
8952
|
+
const DONE = { value: undefined, done: true };
|
|
8953
|
+
/**
|
|
8954
|
+
* Ties an iterator's `finish` to the computation iterating it. Solid reaches
|
|
8955
|
+
* an iterator's return() only when the compute returns the iterable directly.
|
|
8956
|
+
* Inside an async generator the generator's own return() is queued behind its
|
|
8957
|
+
* pending `await`, and owner cleanups wait for the replacing pass to commit,
|
|
8958
|
+
* so close on supersede, with owner disposal as the backstop. No owner (an
|
|
8959
|
+
* async compute iterating it after its first `await`, or plain iteration):
|
|
8960
|
+
* no registration and no diagnostic, so only return() closes it. Scopes that
|
|
8961
|
+
* forbid cleanups rely on supersede and return().
|
|
8962
|
+
*/
|
|
8963
|
+
function bindToOwner(finish) {
|
|
8964
|
+
const owner = getOwner();
|
|
8965
|
+
if (!owner) return;
|
|
8966
|
+
onSupersede(finish);
|
|
8967
|
+
if (!(owner._config & CONFIG_CHILDREN_FORBIDDEN)) cleanup(finish);
|
|
8968
|
+
}
|
|
8969
|
+
/**
|
|
8970
|
+
* An AsyncIterable as a stream bound to the iterating computation: every
|
|
8971
|
+
* value passes through (no coalescing). `finish` calls the inner return()
|
|
8972
|
+
* once and settles pending pulls as done, so a `for await` over it exits as
|
|
8973
|
+
* soon as the computation re-runs — even when the inner iterator is an async
|
|
8974
|
+
* generator whose own return() the language queues behind its pending
|
|
8975
|
+
* `await`.
|
|
8976
|
+
*/
|
|
8977
|
+
function wrapIterable(source) {
|
|
8978
|
+
return {
|
|
8979
|
+
[Symbol.asyncIterator]() {
|
|
8980
|
+
const it = source[Symbol.asyncIterator]();
|
|
8981
|
+
let closed = false;
|
|
8982
|
+
const pending = new Set();
|
|
8983
|
+
const finish = () => {
|
|
8984
|
+
if (closed) return DONE;
|
|
8985
|
+
closed = true;
|
|
8986
|
+
for (const resolve of pending) resolve(DONE);
|
|
8987
|
+
pending.clear();
|
|
8988
|
+
try {
|
|
8989
|
+
const returned = it.return?.();
|
|
8990
|
+
if (isThenable(returned)) returned.then(undefined, () => {});
|
|
8991
|
+
} catch {}
|
|
8992
|
+
return DONE;
|
|
8993
|
+
};
|
|
8994
|
+
bindToOwner(finish);
|
|
8995
|
+
return {
|
|
8996
|
+
next(...args) {
|
|
8997
|
+
if (closed) return Promise.resolve(DONE);
|
|
8998
|
+
const step = it.next(...args);
|
|
8999
|
+
// A bare result (the producer's buffered fast path) passes through.
|
|
9000
|
+
if (!isThenable(step)) return step;
|
|
9001
|
+
return new Promise((resolve, reject) => {
|
|
9002
|
+
pending.add(resolve);
|
|
9003
|
+
step.then(
|
|
9004
|
+
r => pending.delete(resolve) && resolve(r),
|
|
9005
|
+
e => pending.delete(resolve) && reject(e)
|
|
9006
|
+
);
|
|
9007
|
+
});
|
|
9008
|
+
},
|
|
9009
|
+
return() {
|
|
9010
|
+
return Promise.resolve(finish());
|
|
9011
|
+
}
|
|
9012
|
+
};
|
|
9013
|
+
}
|
|
9014
|
+
};
|
|
9015
|
+
}
|
|
9016
|
+
const toCleanup = t =>
|
|
9017
|
+
typeof t === "function"
|
|
9018
|
+
? t
|
|
9019
|
+
: t && typeof t.unsubscribe === "function"
|
|
9020
|
+
? () => t.unsubscribe()
|
|
9021
|
+
: () => {};
|
|
9022
|
+
/**
|
|
9023
|
+
* Converts a callback subscription, an Observable or an AsyncIterable into an
|
|
9024
|
+
* AsyncIterable for a Solid computation. A subscription keeps only the latest
|
|
9025
|
+
* value, and a value the source emits during `subscribe` is served without a
|
|
9026
|
+
* loading frame; an AsyncIterable streams every value through.
|
|
9027
|
+
*
|
|
9028
|
+
* The source closes on supersede — the owning computation re-running — and
|
|
9029
|
+
* on owner disposal. Inside an async generator memo that holds for a
|
|
9030
|
+
* `for await` that starts before the first `await`; one that starts after it
|
|
9031
|
+
* has no owner to bind to, so its source closes only when the loop ends.
|
|
9032
|
+
* Prefer returning `from(...)` from its own memo, with awaited inputs read
|
|
9033
|
+
* from upstream memos and transforms done in a downstream memo.
|
|
9034
|
+
*
|
|
9035
|
+
* Iterate the result with `for await` or return it from a computation: its
|
|
9036
|
+
* `next()` returns an already-buffered value as a bare result, not a promise.
|
|
9037
|
+
*
|
|
9038
|
+
* @example
|
|
9039
|
+
* ```ts
|
|
9040
|
+
* const position = createMemo(() =>
|
|
9041
|
+
* from<Position>((next, error) => {
|
|
9042
|
+
* const id = navigator.geolocation.watchPosition(next, error);
|
|
9043
|
+
* return () => navigator.geolocation.clearWatch(id);
|
|
9044
|
+
* })
|
|
9045
|
+
* );
|
|
9046
|
+
* const ticks = createMemo(() => from(interval$(rate())));
|
|
9047
|
+
* ```
|
|
9048
|
+
*/
|
|
9049
|
+
function from(source) {
|
|
9050
|
+
const subscribe = toSubscribe(source);
|
|
9051
|
+
if (!subscribe) {
|
|
9052
|
+
if (source && typeof source[Symbol.asyncIterator] === "function") return wrapIterable(source);
|
|
9053
|
+
throw new TypeError("from(): expected a subscribe function, an Observable or an AsyncIterable");
|
|
9054
|
+
}
|
|
9055
|
+
return {
|
|
9056
|
+
[Symbol.asyncIterator]() {
|
|
9057
|
+
let latest;
|
|
9058
|
+
let has = false;
|
|
9059
|
+
let done = false;
|
|
9060
|
+
let failed = false;
|
|
9061
|
+
let failure;
|
|
9062
|
+
let waiting = null;
|
|
9063
|
+
let unsubscribe = null;
|
|
9064
|
+
let closed = false;
|
|
9065
|
+
const close = () => {
|
|
9066
|
+
if (closed) return;
|
|
9067
|
+
closed = true;
|
|
9068
|
+
done = true;
|
|
9069
|
+
const c = unsubscribe;
|
|
9070
|
+
unsubscribe = null;
|
|
9071
|
+
// A throwing unsubscribe must not escape: at supersede this runs
|
|
9072
|
+
// inside flush(), ahead of the replacing pass (the returned-iterator
|
|
9073
|
+
// path swallows it the same way).
|
|
9074
|
+
try {
|
|
9075
|
+
c?.();
|
|
9076
|
+
} catch {}
|
|
9077
|
+
};
|
|
9078
|
+
const settle = () => {
|
|
9079
|
+
if (!waiting) return;
|
|
9080
|
+
const w = waiting;
|
|
9081
|
+
if (has) {
|
|
9082
|
+
waiting = null;
|
|
9083
|
+
has = false;
|
|
9084
|
+
w.resolve({ value: latest, done: false });
|
|
9085
|
+
} else if (failed) {
|
|
9086
|
+
waiting = null;
|
|
9087
|
+
failed = false;
|
|
9088
|
+
w.reject(failure);
|
|
9089
|
+
} else if (done) {
|
|
9090
|
+
waiting = null;
|
|
9091
|
+
w.resolve({ value: undefined, done: true });
|
|
9092
|
+
}
|
|
9093
|
+
};
|
|
9094
|
+
const teardown = subscribe(
|
|
9095
|
+
value => {
|
|
9096
|
+
if (done) return;
|
|
9097
|
+
latest = value;
|
|
9098
|
+
has = true;
|
|
9099
|
+
settle();
|
|
9100
|
+
},
|
|
9101
|
+
err => {
|
|
9102
|
+
if (done) return;
|
|
9103
|
+
failed = true;
|
|
9104
|
+
failure = err;
|
|
9105
|
+
done = true;
|
|
9106
|
+
settle();
|
|
9107
|
+
close();
|
|
9108
|
+
},
|
|
9109
|
+
() => {
|
|
9110
|
+
if (done) return;
|
|
9111
|
+
done = true;
|
|
9112
|
+
settle();
|
|
9113
|
+
close();
|
|
9114
|
+
}
|
|
9115
|
+
);
|
|
9116
|
+
unsubscribe = toCleanup(teardown);
|
|
9117
|
+
// Completed or errored during subscribe: release what it just returned.
|
|
9118
|
+
if (closed) {
|
|
9119
|
+
const c = unsubscribe;
|
|
9120
|
+
unsubscribe = null;
|
|
9121
|
+
try {
|
|
9122
|
+
c();
|
|
9123
|
+
} catch {}
|
|
9124
|
+
}
|
|
9125
|
+
// Idempotent: return(), supersede and disposal may all reach it.
|
|
9126
|
+
const finish = () => {
|
|
9127
|
+
close();
|
|
9128
|
+
has = false;
|
|
9129
|
+
if (waiting) {
|
|
9130
|
+
const w = waiting;
|
|
9131
|
+
waiting = null;
|
|
9132
|
+
w.resolve(DONE);
|
|
9133
|
+
}
|
|
9134
|
+
return DONE;
|
|
9135
|
+
};
|
|
9136
|
+
bindToOwner(finish);
|
|
9137
|
+
return {
|
|
9138
|
+
next() {
|
|
9139
|
+
// A buffered value is returned as a bare result, not a promise: the
|
|
9140
|
+
// iterator consumer lands it in the same pass, so a source that
|
|
9141
|
+
// emits during subscribe (BehaviorSubject-style) shows its value
|
|
9142
|
+
// with no loading frame. `for await` accepts either form.
|
|
9143
|
+
if (has) {
|
|
9144
|
+
has = false;
|
|
9145
|
+
return { value: latest, done: false };
|
|
9146
|
+
}
|
|
9147
|
+
if (failed) {
|
|
9148
|
+
failed = false;
|
|
9149
|
+
return Promise.reject(failure);
|
|
9150
|
+
}
|
|
9151
|
+
if (done) return Promise.resolve({ value: undefined, done: true });
|
|
9152
|
+
return new Promise((resolve, reject) => {
|
|
9153
|
+
waiting = { resolve, reject };
|
|
9154
|
+
});
|
|
9155
|
+
},
|
|
9156
|
+
return() {
|
|
9157
|
+
return Promise.resolve(finish());
|
|
9158
|
+
}
|
|
9159
|
+
};
|
|
9160
|
+
}
|
|
9161
|
+
};
|
|
9162
|
+
}
|
|
9163
|
+
|
|
8949
9164
|
// CARVE 4: `flatten` lived in boundaries.ts but is the general children
|
|
8950
9165
|
// resolver the renderers (`web`, `universal`, `solid`'s `children()`) walk
|
|
8951
9166
|
// through — not a boundary feature. Moved verbatim so the boundary carve
|
|
@@ -9984,6 +10199,7 @@ export {
|
|
|
9984
10199
|
enableExternalSource,
|
|
9985
10200
|
flatten,
|
|
9986
10201
|
flush,
|
|
10202
|
+
from,
|
|
9987
10203
|
getContext,
|
|
9988
10204
|
getObserver,
|
|
9989
10205
|
getOwner,
|