@solidjs/signals 2.0.0-beta.17 → 2.0.0-beta.19
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 +4 -3
- package/dist/dev.js +2956 -646
- package/dist/node.cjs +6396 -3974
- package/dist/prod/affects.js +222 -0
- package/dist/prod/boundaries.js +568 -0
- package/dist/prod/core/action.js +83 -0
- package/dist/prod/core/async.js +394 -0
- package/dist/prod/core/constants.js +78 -0
- package/dist/prod/core/context.js +67 -0
- package/dist/prod/core/core.js +772 -0
- package/dist/prod/core/dev.js +3 -0
- package/dist/prod/core/effect.js +145 -0
- package/dist/prod/core/error.js +59 -0
- package/dist/prod/core/external.js +98 -0
- package/dist/prod/core/graph.js +91 -0
- package/dist/prod/core/heap.js +132 -0
- package/dist/prod/core/invariants.js +42 -0
- package/dist/prod/core/lanes.js +130 -0
- package/dist/prod/core/optimistic.js +265 -0
- package/dist/prod/core/owner.js +293 -0
- package/dist/prod/core/scheduler.js +689 -0
- package/dist/prod/core/verdict.js +293 -0
- package/dist/prod/index.js +45 -0
- package/dist/prod/map.js +264 -0
- package/dist/prod/signals.js +389 -0
- package/dist/prod/store/optimistic.js +149 -0
- package/dist/prod/store/projection.js +184 -0
- package/dist/prod/store/reconcile.js +392 -0
- package/dist/prod/store/store.js +739 -0
- package/dist/prod/store/storePath.js +103 -0
- package/dist/prod/store/utils.js +297 -0
- package/dist/types/affects.d.ts +47 -0
- package/dist/types/boundaries.d.ts +8 -8
- package/dist/types/core/async.d.ts +5 -2
- package/dist/types/core/constants.d.ts +8 -0
- package/dist/types/core/core.d.ts +12 -69
- package/dist/types/core/dev.d.ts +1 -1
- package/dist/types/core/external.d.ts +0 -30
- package/dist/types/core/heap.d.ts +8 -0
- package/dist/types/core/index.d.ts +3 -2
- package/dist/types/core/invariants.d.ts +10 -0
- package/dist/types/core/optimistic.d.ts +6 -0
- package/dist/types/core/owner.d.ts +8 -0
- package/dist/types/core/scheduler.d.ts +53 -5
- package/dist/types/core/types.d.ts +22 -5
- package/dist/types/core/verdict.d.ts +2 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/store/projection.d.ts +0 -1
- package/dist/types/store/store.d.ts +32 -14
- package/dist/types-cjs/affects.d.cts +47 -0
- package/dist/types-cjs/boundaries.d.cts +8 -8
- package/dist/types-cjs/core/async.d.cts +5 -2
- package/dist/types-cjs/core/constants.d.cts +8 -0
- package/dist/types-cjs/core/core.d.cts +12 -69
- package/dist/types-cjs/core/dev.d.cts +1 -1
- package/dist/types-cjs/core/external.d.cts +0 -30
- package/dist/types-cjs/core/heap.d.cts +8 -0
- package/dist/types-cjs/core/index.d.cts +3 -2
- package/dist/types-cjs/core/invariants.d.cts +10 -0
- package/dist/types-cjs/core/optimistic.d.cts +6 -0
- package/dist/types-cjs/core/owner.d.cts +8 -0
- package/dist/types-cjs/core/scheduler.d.cts +53 -5
- package/dist/types-cjs/core/types.d.cts +22 -5
- package/dist/types-cjs/core/verdict.d.cts +2 -0
- package/dist/types-cjs/index.d.cts +1 -0
- package/dist/types-cjs/store/projection.d.cts +0 -1
- package/dist/types-cjs/store/store.d.cts +32 -14
- package/package.json +8 -6
- package/dist/prod.js +0 -4406
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
import { STATUS_UNINITIALIZED, REACTIVE_DISPOSED, NOT_PENDING, REACTIVE_MANUAL_WRITE, STATUS_PENDING, REACTIVE_DIRTY, REACTIVE_CHECK } from "./constants.js";
|
|
2
|
+
|
|
3
|
+
import { context, setPendingCheckActive, read, optimisticSignal, setSignal, setLatestReadActive, pendingCheckActive, latestReadActive, stale, currentOptimisticLane, prepareComputed, tracking, setContextInternal, optimisticComputed } from "./core.js";
|
|
4
|
+
|
|
5
|
+
import { NotReadyError } from "./error.js";
|
|
6
|
+
|
|
7
|
+
import { link } from "./graph.js";
|
|
8
|
+
|
|
9
|
+
import { insertIntoHeap, queueFor } from "./heap.js";
|
|
10
|
+
|
|
11
|
+
import "./invariants.js";
|
|
12
|
+
|
|
13
|
+
import { hasActiveOverride, findLane } from "./lanes.js";
|
|
14
|
+
|
|
15
|
+
import { installOptimisticEngine } from "./optimistic.js";
|
|
16
|
+
|
|
17
|
+
import { GlobalQueue, clock, insertSubs, schedule } from "./scheduler.js";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The isPending()/latest() verdict layer, moved out of core.ts. Importing this
|
|
21
|
+
* module installs the companion-maintenance hooks on GlobalQueue; apps that
|
|
22
|
+
* never import isPending/latest never pay for any of it.
|
|
23
|
+
*/
|
|
24
|
+
// Companions (pending signals / latest shadows) are optimistic nodes: their
|
|
25
|
+
// writes go through the optimistic write path and their reversion rides the
|
|
26
|
+
// same lanes, so the verdict layer brings the engine with it.
|
|
27
|
+
installOptimisticEngine();
|
|
28
|
+
|
|
29
|
+
let pendingProbe = null;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Get or create the pending signal for a node (lazy).
|
|
33
|
+
* Used by isPending() to track pending state reactively.
|
|
34
|
+
*/ function getPendingSignal(e) {
|
|
35
|
+
if (!e.ye) {
|
|
36
|
+
// Start false, write true if pending - ensures reversion returns to false
|
|
37
|
+
e.ye = optimisticSignal(false, {
|
|
38
|
+
ownedWrite: true
|
|
39
|
+
});
|
|
40
|
+
e.ye.en = e;
|
|
41
|
+
if (computePendingState(e)) setSignal(e.ye, true);
|
|
42
|
+
}
|
|
43
|
+
return e.ye;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function collectPendingSources(e) {
|
|
47
|
+
if (!pendingProbe) return;
|
|
48
|
+
pendingProbe.sources.add(e);
|
|
49
|
+
const t = e.rt || e;
|
|
50
|
+
if (t !== e) pendingProbe.sources.add(t);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Adds a node to the active isPending() probe without reading it. The store's
|
|
55
|
+
* untracked-probe fallback (`witnessAffectsMark`) reaches this through
|
|
56
|
+
* `GlobalQueue._witnessAffects` — its callers guard on `pendingCheckActive`,
|
|
57
|
+
* which only flips inside `isPending()`, so the hook is always installed by
|
|
58
|
+
* the time it can fire.
|
|
59
|
+
*/ function witnessAffects(e) {
|
|
60
|
+
pendingProbe?.sources.add(e);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function quietPending(e) {
|
|
64
|
+
if (e.M) {
|
|
65
|
+
for (const t of e.M) if (!t.A) return false;
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
if (e.m) return e.m.A;
|
|
69
|
+
return e.A;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function newQuestionInFlight(e) {
|
|
73
|
+
return !!(e.i & STATUS_PENDING) && !(e.i & STATUS_UNINITIALIZED) && !quietPending(e);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function computePendingState(e) {
|
|
77
|
+
const t = e;
|
|
78
|
+
if (t.u & REACTIVE_DISPOSED) return false;
|
|
79
|
+
if (e.P) return true;
|
|
80
|
+
const n = e.rt;
|
|
81
|
+
if (e.en) {
|
|
82
|
+
const t = e.en;
|
|
83
|
+
if (t.P) return true;
|
|
84
|
+
const n = t.rt || t;
|
|
85
|
+
return newQuestionInFlight(n);
|
|
86
|
+
}
|
|
87
|
+
if (n && e.ge !== NOT_PENDING && !hasActiveOverride(e)) {
|
|
88
|
+
return !!(n.u & REACTIVE_MANUAL_WRITE) || !n.Ae && !(n.i & STATUS_PENDING) || !!(n.i & STATUS_PENDING) && quietPending(n);
|
|
89
|
+
}
|
|
90
|
+
if (e.ge !== NOT_PENDING && !(t.i & STATUS_UNINITIALIZED)) {
|
|
91
|
+
if (hasActiveOverride(e)) return !e.Ge || !e.Ge(e.ge, e.be);
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
return newQuestionInFlight(t);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function syncCompanions(e, t) {
|
|
98
|
+
if (e.ye) updatePendingSignal(e);
|
|
99
|
+
if (e.pe) setSignal(e.pe, t);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function updatePendingSignal(e) {
|
|
103
|
+
if (e.ye) {
|
|
104
|
+
setSignal(e.ye, computePendingState(e));
|
|
105
|
+
}
|
|
106
|
+
if (e.pe) updatePendingSignal(e.pe);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function updateChildCompanions(e) {
|
|
110
|
+
for (let t = e.G; t !== null; t = t.Ne) {
|
|
111
|
+
if (t.ye || t.pe) updatePendingSignal(t);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function repollDownstreamVerdicts(e) {
|
|
116
|
+
const t = new Set;
|
|
117
|
+
const visit = e => {
|
|
118
|
+
if (t.has(e)) return;
|
|
119
|
+
t.add(e);
|
|
120
|
+
if (e.ye || e.pe) updatePendingSignal(e);
|
|
121
|
+
for (let t = e.p; t !== null; t = t.de) visit(t.Ee);
|
|
122
|
+
for (let t = e.G ?? null; t !== null; t = t.Ne) {
|
|
123
|
+
visit(t);
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
visit(e);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function snapCompanionsToState(e) {
|
|
130
|
+
const t = e.ye;
|
|
131
|
+
if (t && (t.be === undefined || t.be === NOT_PENDING)) {
|
|
132
|
+
const n = computePendingState(e);
|
|
133
|
+
if (t.Ue !== n || t.ge !== NOT_PENDING) {
|
|
134
|
+
t.Ue = n;
|
|
135
|
+
t.ge = NOT_PENDING;
|
|
136
|
+
t.Ie = clock;
|
|
137
|
+
insertSubs(t);
|
|
138
|
+
schedule();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const n = e.pe;
|
|
142
|
+
if (n && !(n.u & REACTIVE_DISPOSED)) {
|
|
143
|
+
if ((n.be === undefined || n.be === NOT_PENDING) && n.ge === NOT_PENDING && !Object.is(n.Ue, e.Ue) && !(n.u & (REACTIVE_DIRTY | REACTIVE_CHECK))) {
|
|
144
|
+
n.u |= REACTIVE_DIRTY;
|
|
145
|
+
insertIntoHeap(n, queueFor(n));
|
|
146
|
+
insertSubs(n);
|
|
147
|
+
schedule();
|
|
148
|
+
}
|
|
149
|
+
snapCompanionsToState(n);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function getLatestValueComputed(e) {
|
|
154
|
+
if (!e.pe) {
|
|
155
|
+
const t = latestReadActive;
|
|
156
|
+
setLatestReadActive(false);
|
|
157
|
+
const n = pendingCheckActive;
|
|
158
|
+
setPendingCheckActive(false);
|
|
159
|
+
const i = context;
|
|
160
|
+
setContextInternal(null);
|
|
161
|
+
// Detach from owner so it isn't disposed with effects
|
|
162
|
+
e.pe = optimisticComputed(() => read(e));
|
|
163
|
+
e.pe.en = e;
|
|
164
|
+
// Parent-child lane relationship
|
|
165
|
+
setContextInternal(i);
|
|
166
|
+
setPendingCheckActive(n);
|
|
167
|
+
setLatestReadActive(t);
|
|
168
|
+
}
|
|
169
|
+
return e.pe;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/** The latest()-mode read path, installed as GlobalQueue._latestRead. */ function latestRead(e) {
|
|
173
|
+
const t = getLatestValueComputed(e);
|
|
174
|
+
const n = latestReadActive;
|
|
175
|
+
setLatestReadActive(false);
|
|
176
|
+
const i = e.be !== undefined && e.be !== NOT_PENDING ? e.be : e.Ue;
|
|
177
|
+
let r;
|
|
178
|
+
try {
|
|
179
|
+
r = read(t);
|
|
180
|
+
} catch (t) {
|
|
181
|
+
if (t instanceof NotReadyError && (!context || !(e.i & STATUS_UNINITIALIZED))) return i;
|
|
182
|
+
throw t;
|
|
183
|
+
} finally {
|
|
184
|
+
setLatestReadActive(n);
|
|
185
|
+
}
|
|
186
|
+
if (t.i & STATUS_PENDING) return i;
|
|
187
|
+
if (stale && currentOptimisticLane && t.Je) {
|
|
188
|
+
const e = findLane(t.Je);
|
|
189
|
+
const n = findLane(currentOptimisticLane);
|
|
190
|
+
if (e !== n && e.Pe.size > 0) {
|
|
191
|
+
return i;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return r;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/** The isPending()-probe read path, installed as GlobalQueue._pendingCheck. */ function pendingCheckRead(e, t, n, i) {
|
|
198
|
+
setPendingCheckActive(false);
|
|
199
|
+
if (typeof e.xe === "function") prepareComputed(e, true);
|
|
200
|
+
const r = n.i;
|
|
201
|
+
if (t && r & STATUS_PENDING && r & STATUS_UNINITIALIZED) {
|
|
202
|
+
if (tracking && e !== t) link(e, t);
|
|
203
|
+
setPendingCheckActive(true);
|
|
204
|
+
throw n.k;
|
|
205
|
+
}
|
|
206
|
+
collectPendingSources(e);
|
|
207
|
+
if (i) collectPendingSources(i);
|
|
208
|
+
setPendingCheckActive(true);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function recordFreshRead(e, t) {
|
|
212
|
+
if (pendingProbe !== null && e.ge !== NOT_PENDING && t === e.ge) pendingProbe.freshReads.add(e);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function applyReask(e, t) {
|
|
216
|
+
const n = !!(e.i & STATUS_PENDING);
|
|
217
|
+
const i = t && !(n && !e.A);
|
|
218
|
+
const r = n && e.A !== i;
|
|
219
|
+
e.A = i;
|
|
220
|
+
return r;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function latest(e) {
|
|
224
|
+
const t = latestReadActive;
|
|
225
|
+
setLatestReadActive(true);
|
|
226
|
+
try {
|
|
227
|
+
return e();
|
|
228
|
+
} finally {
|
|
229
|
+
setLatestReadActive(t);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function isPending(e) {
|
|
234
|
+
const t = pendingCheckActive;
|
|
235
|
+
const n = pendingProbe;
|
|
236
|
+
setPendingCheckActive(true);
|
|
237
|
+
const i = pendingProbe = {
|
|
238
|
+
found: false,
|
|
239
|
+
sources: new Set,
|
|
240
|
+
freshReads: new Set
|
|
241
|
+
};
|
|
242
|
+
const collectPending = () => {
|
|
243
|
+
setPendingCheckActive(false);
|
|
244
|
+
try {
|
|
245
|
+
i.sources.forEach(e => {
|
|
246
|
+
if (read(getPendingSignal(e)) && !i.freshReads.has(e)) i.found = true;
|
|
247
|
+
});
|
|
248
|
+
} finally {
|
|
249
|
+
setPendingCheckActive(true);
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
try {
|
|
253
|
+
e();
|
|
254
|
+
collectPending();
|
|
255
|
+
return i.found;
|
|
256
|
+
} catch (e) {
|
|
257
|
+
collectPending();
|
|
258
|
+
if (e instanceof NotReadyError) {
|
|
259
|
+
const t = !!(e.source?.i & STATUS_UNINITIALIZED);
|
|
260
|
+
if (i.found && !t) return true;
|
|
261
|
+
if (context && t) throw e;
|
|
262
|
+
}
|
|
263
|
+
return i.found;
|
|
264
|
+
} finally {
|
|
265
|
+
setPendingCheckActive(t);
|
|
266
|
+
pendingProbe = n;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Hook installation (same late-binding pattern as GlobalQueue._update /
|
|
271
|
+
// _propagateAffects): core call sites fire these behind the same guards the
|
|
272
|
+
// direct calls used, so behavior is identical once this module loads.
|
|
273
|
+
GlobalQueue._e = syncCompanions;
|
|
274
|
+
|
|
275
|
+
GlobalQueue._ = updatePendingSignal;
|
|
276
|
+
|
|
277
|
+
GlobalQueue.me = updateChildCompanions;
|
|
278
|
+
|
|
279
|
+
GlobalQueue.R = snapCompanionsToState;
|
|
280
|
+
|
|
281
|
+
GlobalQueue.Gt = latestRead;
|
|
282
|
+
|
|
283
|
+
GlobalQueue.Pt = pendingCheckRead;
|
|
284
|
+
|
|
285
|
+
GlobalQueue.vt = recordFreshRead;
|
|
286
|
+
|
|
287
|
+
GlobalQueue.tt = applyReask;
|
|
288
|
+
|
|
289
|
+
GlobalQueue.nt = repollDownstreamVerdicts;
|
|
290
|
+
|
|
291
|
+
GlobalQueue.Zt = witnessAffects;
|
|
292
|
+
|
|
293
|
+
export { isPending, latest };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export { ContextNotFoundError, NoOwnerError, NotReadyError } from "./core/error.js";
|
|
2
|
+
|
|
3
|
+
export { clearSnapshots, isEqual, markSnapshotScope, refresh, releaseSnapshotScope, runWithOwner, setSnapshotCapture, untrack } from "./core/core.js";
|
|
4
|
+
|
|
5
|
+
export { enableExternalSource } from "./core/external.js";
|
|
6
|
+
|
|
7
|
+
export { createOwner, createRoot, getNextChildId, getObserver, getOwner, isDisposed, peekNextChildId } from "./core/owner.js";
|
|
8
|
+
|
|
9
|
+
export { createContext, getContext, setContext } from "./core/context.js";
|
|
10
|
+
|
|
11
|
+
export { $REFRESH, SUPPORTS_PROXY } from "./core/constants.js";
|
|
12
|
+
|
|
13
|
+
import "./core/invariants.js";
|
|
14
|
+
|
|
15
|
+
export { enforceLoadingBoundary, flush, resetErrorHalt } from "./core/scheduler.js";
|
|
16
|
+
|
|
17
|
+
export { isPending, latest } from "./core/verdict.js";
|
|
18
|
+
|
|
19
|
+
import "./core/effect.js";
|
|
20
|
+
|
|
21
|
+
export { action } from "./core/action.js";
|
|
22
|
+
|
|
23
|
+
export { createEffect, createMemo, createOptimistic, createReaction, createRenderEffect, createSignal, createTrackedEffect, onCleanup, onSettled, resolve } from "./signals.js";
|
|
24
|
+
|
|
25
|
+
export { affects } from "./affects.js";
|
|
26
|
+
|
|
27
|
+
export { mapArray, repeat } from "./map.js";
|
|
28
|
+
|
|
29
|
+
export { $PROXY, $TARGET, $TRACK, createStore, isWrappable } from "./store/store.js";
|
|
30
|
+
|
|
31
|
+
export { createProjection } from "./store/projection.js";
|
|
32
|
+
|
|
33
|
+
export { createOptimisticStore } from "./store/optimistic.js";
|
|
34
|
+
|
|
35
|
+
export { reconcile } from "./store/reconcile.js";
|
|
36
|
+
|
|
37
|
+
export { storePath } from "./store/storePath.js";
|
|
38
|
+
|
|
39
|
+
export { deep, merge, omit, snapshot } from "./store/utils.js";
|
|
40
|
+
|
|
41
|
+
export { createErrorBoundary, createLoadingBoundary, createRevealOrder, flatten } from "./boundaries.js";
|
|
42
|
+
|
|
43
|
+
const DEV = undefined;
|
|
44
|
+
|
|
45
|
+
export { DEV };
|
package/dist/prod/map.js
ADDED
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import { computed, runWithOwner, signal, setSignal } from "./core/core.js";
|
|
2
|
+
|
|
3
|
+
import { createOwner } from "./core/owner.js";
|
|
4
|
+
|
|
5
|
+
import "./core/scheduler.js";
|
|
6
|
+
|
|
7
|
+
import { CONFIG_AUTO_DISPOSE } from "./core/constants.js";
|
|
8
|
+
|
|
9
|
+
import "./core/invariants.js";
|
|
10
|
+
|
|
11
|
+
import "./core/verdict.js";
|
|
12
|
+
|
|
13
|
+
import "./core/effect.js";
|
|
14
|
+
|
|
15
|
+
import { accessor } from "./signals.js";
|
|
16
|
+
|
|
17
|
+
import { $TRACK } from "./store/store.js";
|
|
18
|
+
|
|
19
|
+
function mapArray(t, s, i) {
|
|
20
|
+
const e = typeof i?.keyed === "function" ? i.keyed : undefined;
|
|
21
|
+
const h = s.length > 1;
|
|
22
|
+
const r = s;
|
|
23
|
+
const n = {
|
|
24
|
+
$t: createOwner(),
|
|
25
|
+
Xt: 0,
|
|
26
|
+
ts: t,
|
|
27
|
+
ss: [],
|
|
28
|
+
es: r,
|
|
29
|
+
hs: [],
|
|
30
|
+
rs: [],
|
|
31
|
+
ns: e,
|
|
32
|
+
cs: e || i?.keyed === false ? [] : undefined,
|
|
33
|
+
fs: h && i?.keyed !== false ? [] : undefined,
|
|
34
|
+
us: i?.keyed === false,
|
|
35
|
+
ps: i?.fallback
|
|
36
|
+
};
|
|
37
|
+
const o = computed(updateKeyedMap.bind(n));
|
|
38
|
+
// Untracked reads inside the internal owner resolve via _parentComputed; routing
|
|
39
|
+
// them through node lets store-proxy lookups see pending writes (not stale _value).
|
|
40
|
+
n.$t.Ct = o;
|
|
41
|
+
o.U &= ~CONFIG_AUTO_DISPOSE;
|
|
42
|
+
return accessor(o);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const pureOptions = {
|
|
46
|
+
ownedWrite: true
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
function updateKeyedMap() {
|
|
50
|
+
const t = this.ts() || [], s = t.length;
|
|
51
|
+
t[$TRACK];
|
|
52
|
+
// top level tracking
|
|
53
|
+
runWithOwner(this.$t, () => {
|
|
54
|
+
let i, e, h = this.cs ? this.us ? () => {
|
|
55
|
+
this.cs[e] = signal(t[e], pureOptions);
|
|
56
|
+
return this.es(accessor(this.cs[e]), e);
|
|
57
|
+
} : () => {
|
|
58
|
+
this.cs[e] = signal(t[e], pureOptions);
|
|
59
|
+
this.fs && (this.fs[e] = signal(e, pureOptions));
|
|
60
|
+
return this.es(accessor(this.cs[e]), this.fs ? accessor(this.fs[e]) : undefined);
|
|
61
|
+
} : this.fs ? () => {
|
|
62
|
+
const s = t[e];
|
|
63
|
+
this.fs[e] = signal(e, pureOptions);
|
|
64
|
+
return this.es(s, accessor(this.fs[e]));
|
|
65
|
+
} : () => {
|
|
66
|
+
const s = t[e];
|
|
67
|
+
return this.es(s);
|
|
68
|
+
};
|
|
69
|
+
// fast path for empty arrays
|
|
70
|
+
if (s === 0) {
|
|
71
|
+
if (this.Xt !== 0) {
|
|
72
|
+
this.$t.dispose(false);
|
|
73
|
+
this.rs = [];
|
|
74
|
+
this.ss = [];
|
|
75
|
+
this.hs = [];
|
|
76
|
+
this.Xt = 0;
|
|
77
|
+
this.cs && (this.cs = []);
|
|
78
|
+
this.fs && (this.fs = []);
|
|
79
|
+
}
|
|
80
|
+
if (this.ps && !this.hs[0]) {
|
|
81
|
+
// create fallback
|
|
82
|
+
this.hs[0] = runWithOwner(this.rs[0] = createOwner(), this.ps);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// fast path for new create
|
|
86
|
+
else if (this.Xt === 0) {
|
|
87
|
+
// dispose previous fallback
|
|
88
|
+
if (this.rs[0]) this.rs[0].dispose();
|
|
89
|
+
this.hs = new Array(s);
|
|
90
|
+
for (e = 0; e < s; e++) {
|
|
91
|
+
this.ss[e] = t[e];
|
|
92
|
+
this.hs[e] = runWithOwner(this.rs[e] = createOwner(), h);
|
|
93
|
+
}
|
|
94
|
+
this.Xt = s;
|
|
95
|
+
} else {
|
|
96
|
+
let r, n, o, a, c, f, u, p = new Array(s), l = new Array(s), w = this.cs ? new Array(s) : undefined, O = this.fs ? new Array(s) : undefined;
|
|
97
|
+
// skip common prefix
|
|
98
|
+
for (r = 0, n = Math.min(this.Xt, s); r < n && (this.ss[r] === t[r] || this.cs && compare(this.ns, this.ss[r], t[r])); r++) {
|
|
99
|
+
if (this.cs) setSignal(this.cs[r], t[r]);
|
|
100
|
+
}
|
|
101
|
+
// common suffix
|
|
102
|
+
for (n = this.Xt - 1, o = s - 1; n >= r && o >= r && (this.ss[n] === t[o] || this.cs && compare(this.ns, this.ss[n], t[o])); n--,
|
|
103
|
+
o--) {
|
|
104
|
+
p[o] = this.hs[n];
|
|
105
|
+
l[o] = this.rs[n];
|
|
106
|
+
w && (w[o] = this.cs[n]);
|
|
107
|
+
O && (O[o] = this.fs[n]);
|
|
108
|
+
}
|
|
109
|
+
// 0) prepare a map of all indices in newItems, scanning backwards so we encounter them in natural order
|
|
110
|
+
f = new Map;
|
|
111
|
+
u = new Array(o + 1);
|
|
112
|
+
for (e = o; e >= r; e--) {
|
|
113
|
+
a = t[e];
|
|
114
|
+
c = this.ns ? this.ns(a) : a;
|
|
115
|
+
i = f.get(c);
|
|
116
|
+
u[e] = i === undefined ? -1 : i;
|
|
117
|
+
f.set(c, e);
|
|
118
|
+
}
|
|
119
|
+
// 1) step through all old items and see if they can be found in the new set; if so, save them in a temp array and mark them moved; if not, exit them
|
|
120
|
+
for (i = r; i <= n; i++) {
|
|
121
|
+
a = this.ss[i];
|
|
122
|
+
c = this.ns ? this.ns(a) : a;
|
|
123
|
+
e = f.get(c);
|
|
124
|
+
if (e !== undefined && e !== -1) {
|
|
125
|
+
p[e] = this.hs[i];
|
|
126
|
+
l[e] = this.rs[i];
|
|
127
|
+
w && (w[e] = this.cs[i]);
|
|
128
|
+
O && (O[e] = this.fs[i]);
|
|
129
|
+
e = u[e];
|
|
130
|
+
f.set(c, e);
|
|
131
|
+
} else this.rs[i].dispose();
|
|
132
|
+
}
|
|
133
|
+
// 2) set all the new values, pulling from the temp array if copied, otherwise entering the new value
|
|
134
|
+
for (e = r; e < s; e++) {
|
|
135
|
+
if (e in p) {
|
|
136
|
+
this.hs[e] = p[e];
|
|
137
|
+
this.rs[e] = l[e];
|
|
138
|
+
if (w) {
|
|
139
|
+
this.cs[e] = w[e];
|
|
140
|
+
setSignal(this.cs[e], t[e]);
|
|
141
|
+
}
|
|
142
|
+
if (O) {
|
|
143
|
+
this.fs[e] = O[e];
|
|
144
|
+
setSignal(this.fs[e], e);
|
|
145
|
+
}
|
|
146
|
+
} else {
|
|
147
|
+
this.hs[e] = runWithOwner(this.rs[e] = createOwner(), h);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// 3) in case the new set is shorter than the old, set the length of the mapped array
|
|
151
|
+
this.hs = this.hs.slice(0, this.Xt = s);
|
|
152
|
+
// 4) save a copy of the mapped items for the next update
|
|
153
|
+
this.ss = t.slice(0);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
return this.hs;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Reactively renders a callback `count` times, reusing previously-rendered
|
|
161
|
+
* entries when only the count changes. Underlying helper for `<Repeat>`.
|
|
162
|
+
*
|
|
163
|
+
* - `options.from` — start index (default `0`); useful for offset/windowed
|
|
164
|
+
* rendering.
|
|
165
|
+
* - `options.fallback` — accessor returning a value to show when count is `0`.
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* ```ts
|
|
169
|
+
* const view = repeat(count, i => `Item ${i}`, { fallback: () => "empty" });
|
|
170
|
+
* ```
|
|
171
|
+
*
|
|
172
|
+
* @description https://docs.solidjs.com/reference/reactive-utilities/repeat
|
|
173
|
+
*/ function repeat(t, s, i) {
|
|
174
|
+
const e = s;
|
|
175
|
+
const h = computed(updateRepeat.bind({
|
|
176
|
+
$t: createOwner(),
|
|
177
|
+
Xt: 0,
|
|
178
|
+
ls: 0,
|
|
179
|
+
ws: t,
|
|
180
|
+
es: e,
|
|
181
|
+
rs: [],
|
|
182
|
+
hs: [],
|
|
183
|
+
Os: i?.from,
|
|
184
|
+
ps: i?.fallback
|
|
185
|
+
}));
|
|
186
|
+
h.U &= ~CONFIG_AUTO_DISPOSE;
|
|
187
|
+
return accessor(h);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function updateRepeat() {
|
|
191
|
+
const t = this.ws();
|
|
192
|
+
const s = this.Os?.() || 0;
|
|
193
|
+
runWithOwner(this.$t, () => {
|
|
194
|
+
if (t === 0) {
|
|
195
|
+
if (this.Xt !== 0) {
|
|
196
|
+
this.$t.dispose(false);
|
|
197
|
+
this.rs = [];
|
|
198
|
+
this.hs = [];
|
|
199
|
+
this.Xt = 0;
|
|
200
|
+
// Reset offset to match the cleared data. Without this, a subsequent
|
|
201
|
+
// nonzero render with a smaller `from` would enter the end-clear loop
|
|
202
|
+
// with `prevTo = stale_offset + 0` > `to` and dispose `_nodes[-1]`
|
|
203
|
+
// (#2767, repro 2).
|
|
204
|
+
this.ls = 0;
|
|
205
|
+
}
|
|
206
|
+
if (this.ps && !this.hs[0]) {
|
|
207
|
+
// create fallback
|
|
208
|
+
this.hs[0] = runWithOwner(this.rs[0] = createOwner(), this.ps);
|
|
209
|
+
}
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
const i = s + t;
|
|
213
|
+
const e = this.ls + this.Xt;
|
|
214
|
+
// remove fallback
|
|
215
|
+
if (this.Xt === 0 && this.rs[0]) this.rs[0].dispose();
|
|
216
|
+
// Disjoint windows have no rows to retain; replace them wholesale.
|
|
217
|
+
if (s >= e || i <= this.ls) {
|
|
218
|
+
for (let t = 0; t < this.Xt; t++) this.rs[t].dispose();
|
|
219
|
+
this.rs = new Array(t);
|
|
220
|
+
this.hs = new Array(t);
|
|
221
|
+
for (let i = 0; i < t; i++) this.hs[i] = runWithOwner(this.rs[i] = createOwner(), () => this.es(s + i));
|
|
222
|
+
this.ls = s;
|
|
223
|
+
this.Xt = t;
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
// clear the end
|
|
227
|
+
for (let t = i; t < e; t++) this.rs[t - this.ls].dispose();
|
|
228
|
+
if (this.ls < s) {
|
|
229
|
+
// clear beginning — `_nodes` is local-indexed, so the rows leaving the
|
|
230
|
+
// front sit at local positions 0..(from - _offset), clamped to old len.
|
|
231
|
+
const t = s - this.ls;
|
|
232
|
+
for (let s = 0; s < t && s < this.Xt; s++) this.rs[s].dispose();
|
|
233
|
+
// shift indexes
|
|
234
|
+
this.rs.splice(0, t);
|
|
235
|
+
this.hs.splice(0, t);
|
|
236
|
+
} else if (this.ls > s) {
|
|
237
|
+
// shift indexes
|
|
238
|
+
let i = e - this.ls - 1;
|
|
239
|
+
let h = this.ls - s;
|
|
240
|
+
this.rs.length = this.hs.length = t;
|
|
241
|
+
while (i >= h) {
|
|
242
|
+
this.rs[i] = this.rs[i - h];
|
|
243
|
+
this.hs[i] = this.hs[i - h];
|
|
244
|
+
i--;
|
|
245
|
+
}
|
|
246
|
+
for (let t = 0; t < h; t++) {
|
|
247
|
+
this.hs[t] = runWithOwner(this.rs[t] = createOwner(), () => this.es(t + s));
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
for (let t = e; t < i; t++) {
|
|
251
|
+
this.hs[t - s] = runWithOwner(this.rs[t - s] = createOwner(), () => this.es(t));
|
|
252
|
+
}
|
|
253
|
+
this.hs = this.hs.slice(0, t);
|
|
254
|
+
this.ls = s;
|
|
255
|
+
this.Xt = t;
|
|
256
|
+
});
|
|
257
|
+
return this.hs;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function compare(t, s, i) {
|
|
261
|
+
return t ? t(s) === t(i) : true;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export { mapArray, repeat };
|