@solidjs/signals 2.0.0-rc.0 → 2.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/dev.js +2622 -2438
- package/dist/node.cjs +3770 -3571
- package/dist/prod/core/async.js +186 -132
- package/dist/prod/core/core.js +118 -107
- package/dist/prod/core/effect.js +13 -13
- package/dist/prod/core/external.js +1 -1
- package/dist/prod/core/graph.js +8 -8
- package/dist/prod/core/heap.js +24 -24
- package/dist/prod/core/lanes.js +3 -3
- package/dist/prod/core/optimistic.js +38 -21
- package/dist/prod/core/owner.js +21 -21
- package/dist/prod/core/scheduler.js +55 -47
- package/dist/prod/core/verdict.js +40 -40
- package/dist/prod/index.js +7 -7
- package/dist/prod/map.js +81 -79
- package/dist/prod/signals.js +20 -1
- package/dist/prod/store/index.js +36 -0
- package/dist/prod/store/next/optimistic.js +377 -0
- package/dist/prod/store/next/projection.js +172 -0
- package/dist/prod/store/next/reconcile.js +327 -0
- package/dist/prod/store/next/store.js +1232 -0
- package/dist/prod/store/next/target.js +20 -0
- package/dist/prod/store/store.js +123 -879
- package/dist/prod/store/utils.js +59 -186
- package/dist/types/core/core.d.ts +8 -0
- package/dist/types/core/dev.d.ts +1 -1
- package/dist/types/core/scheduler.d.ts +4 -2
- package/dist/types/signals.d.ts +19 -0
- package/dist/types/store/index.d.ts +15 -5
- package/dist/types/store/next/optimistic.d.ts +20 -0
- package/dist/types/store/next/projection.d.ts +24 -0
- package/dist/types/store/next/reconcile.d.ts +3 -0
- package/dist/types/store/next/store.d.ts +71 -0
- package/dist/types/store/next/target.d.ts +99 -0
- package/dist/types/store/store.d.ts +26 -101
- package/dist/types/store/utils.d.ts +0 -40
- package/dist/types-cjs/core/core.d.cts +8 -0
- package/dist/types-cjs/core/dev.d.cts +1 -1
- package/dist/types-cjs/core/scheduler.d.cts +4 -2
- package/dist/types-cjs/signals.d.cts +19 -0
- package/dist/types-cjs/store/index.d.cts +15 -5
- package/dist/types-cjs/store/next/optimistic.d.cts +20 -0
- package/dist/types-cjs/store/next/projection.d.cts +24 -0
- package/dist/types-cjs/store/next/reconcile.d.cts +3 -0
- package/dist/types-cjs/store/next/store.d.cts +71 -0
- package/dist/types-cjs/store/next/target.d.cts +99 -0
- package/dist/types-cjs/store/store.d.cts +26 -101
- package/dist/types-cjs/store/utils.d.cts +0 -40
- package/package.json +2 -1
- package/dist/prod/store/optimistic.js +0 -217
- package/dist/prod/store/projection.js +0 -231
- package/dist/prod/store/reconcile.js +0 -707
|
@@ -1,231 +0,0 @@
|
|
|
1
|
-
import { computed } from "../core/core.js";
|
|
2
|
-
|
|
3
|
-
import { getOwner } from "../core/owner.js";
|
|
4
|
-
|
|
5
|
-
import { setProjectionWriteActive } from "../core/scheduler.js";
|
|
6
|
-
|
|
7
|
-
import { handleAsync } from "../core/async.js";
|
|
8
|
-
|
|
9
|
-
import "../core/verdict.js";
|
|
10
|
-
|
|
11
|
-
import "../core/effect.js";
|
|
12
|
-
|
|
13
|
-
import { CONFIG_AUTO_DISPOSE } from "../core/constants.js";
|
|
14
|
-
|
|
15
|
-
import { reconcileState } from "./reconcile.js";
|
|
16
|
-
|
|
17
|
-
import { $TARGET, STORE_VALUE, storeSetter, STORE_WRAP, createStoreProxy, storeTraps, setWriteOverride, STORE_LOOKUP, STORE_SHALLOW, markRawIngest, STORE_FIREWALL } from "./store.js";
|
|
18
|
-
|
|
19
|
-
function createProjectionInternal(e, t, r) {
|
|
20
|
-
let o;
|
|
21
|
-
const n = new WeakMap;
|
|
22
|
-
// A shallow projection's children are raw and never wrapped, so the
|
|
23
|
-
// wrapper only ever runs for the root — flagging unconditionally is safe.
|
|
24
|
-
const i = !!r?.shallow;
|
|
25
|
-
const wrapper = e => {
|
|
26
|
-
e[STORE_WRAP] = wrapProjection;
|
|
27
|
-
e[STORE_LOOKUP] = n;
|
|
28
|
-
if (i) {
|
|
29
|
-
e[STORE_SHALLOW] = true;
|
|
30
|
-
markRawIngest(e[STORE_VALUE]);
|
|
31
|
-
}
|
|
32
|
-
Object.defineProperty(e, STORE_FIREWALL, {
|
|
33
|
-
get() {
|
|
34
|
-
return o;
|
|
35
|
-
},
|
|
36
|
-
configurable: true
|
|
37
|
-
});
|
|
38
|
-
};
|
|
39
|
-
const wrapProjection = e => {
|
|
40
|
-
if (n.has(e)) return n.get(e);
|
|
41
|
-
if (e[$TARGET]?.[STORE_WRAP] === wrapProjection) return e;
|
|
42
|
-
const t = createStoreProxy(e, storeTraps, wrapper);
|
|
43
|
-
n.set(e, t);
|
|
44
|
-
return t;
|
|
45
|
-
};
|
|
46
|
-
const c = wrapProjection(t);
|
|
47
|
-
// seedLoadingValue: the firewall is born committed (the seed is commit #0);
|
|
48
|
-
// the internal handleAsync serves it during the derive's first flight. The
|
|
49
|
-
// node's own value channel is void, so the loading value itself is
|
|
50
|
-
// `undefined` — presence of the key is what flips the mode.
|
|
51
|
-
let s;
|
|
52
|
-
if (r?.seedLoadingValue) s = {
|
|
53
|
-
loadingValue: undefined
|
|
54
|
-
};
|
|
55
|
-
o = computed(() => {
|
|
56
|
-
if (!o) o = getOwner();
|
|
57
|
-
runProjectionComputed(c, e, r?.key === undefined ? "id" : r.key);
|
|
58
|
-
}, s);
|
|
59
|
-
o.T &= ~CONFIG_AUTO_DISPOSE;
|
|
60
|
-
return {
|
|
61
|
-
store: c,
|
|
62
|
-
node: o
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Creates a derived (projected) store. Like `createMemo` but for stores: the
|
|
68
|
-
* derive function receives a mutable draft and either mutates it in place
|
|
69
|
-
* (canonical) or returns a new value. Either way the result is reconciled
|
|
70
|
-
* against the previous draft by `options.key` (default `"id"`), so surviving
|
|
71
|
-
* items keep their proxy identity — only added/removed items are
|
|
72
|
-
* created/disposed.
|
|
73
|
-
*
|
|
74
|
-
* If the derive returns a different entity than the one currently held (the
|
|
75
|
-
* `/users/1` → `/users/2` shape), the store swaps to it rather than merging,
|
|
76
|
-
* and nothing below it is treated as surviving.
|
|
77
|
-
*
|
|
78
|
-
* Returns the projected store directly (no setter — reads only).
|
|
79
|
-
*
|
|
80
|
-
* Use this when you want the structural-sharing / per-property tracking
|
|
81
|
-
* behaviour of a store on top of a derived computation. For simple read-only
|
|
82
|
-
* derivations, `createMemo` is lighter.
|
|
83
|
-
*
|
|
84
|
-
* @param fn receives the current draft; mutate it in place or return new
|
|
85
|
-
* data. Return is convenient for filter/derive shapes where mutation is
|
|
86
|
-
* awkward.
|
|
87
|
-
* @param seed the backing store value to wrap and reconcile into
|
|
88
|
-
* @param options `ProjectionOptions` — `name`, `key`. `key` defaults to
|
|
89
|
-
* `"id"`; specify it only when your data uses a different identity field
|
|
90
|
-
* (e.g. `{ key: "uuid" }` or `{ key: u => u.slug }`), or `null` to merge
|
|
91
|
-
* positionally with no keyed pass.
|
|
92
|
-
*
|
|
93
|
-
* @example
|
|
94
|
-
* ```ts
|
|
95
|
-
* // Mutation form — update individual fields on the draft.
|
|
96
|
-
* const summary = createProjection<{ total: number; active: number }>(
|
|
97
|
-
* draft => {
|
|
98
|
-
* draft.total = users().length;
|
|
99
|
-
* draft.active = users().filter(u => u.active).length;
|
|
100
|
-
* },
|
|
101
|
-
* { total: 0, active: 0 }
|
|
102
|
-
* );
|
|
103
|
-
*
|
|
104
|
-
* // Return form — produce a derived collection. Reconciled by `id` so each
|
|
105
|
-
* // surviving user keeps the same store identity across recomputes.
|
|
106
|
-
* const activeUsers = createProjection<User[]>(
|
|
107
|
-
* () => allUsers().filter(u => u.active),
|
|
108
|
-
* []
|
|
109
|
-
* );
|
|
110
|
-
* ```
|
|
111
|
-
*
|
|
112
|
-
* @see {@link https://github.com/solidjs/x-reactivity#createprojection}
|
|
113
|
-
*/ function createProjection(e, t, r) {
|
|
114
|
-
return createProjectionInternal(e, t, r).store;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Shared projection computed body used by both `createProjection` and the derived
|
|
119
|
-
* form of `createOptimisticStore`. Encapsulates the write-trap draft, `storeSetter`
|
|
120
|
-
* wrapping, the `handleAsync` subscription with a setter callback, and the commit
|
|
121
|
-
* path (which must always go through `storeSetter` so the `writeOnly` guard is
|
|
122
|
-
* engaged during `reconcile`'s property reads).
|
|
123
|
-
*
|
|
124
|
-
* `wrapCommit` is invoked for every commit (sync return and each async yield) and
|
|
125
|
-
* lets callers layer extra context around the write — e.g. the optimistic store
|
|
126
|
-
* re-enters `setProjectionWriteActive` so reconciles target `STORE_OVERRIDE`
|
|
127
|
-
* instead of `STORE_OPTIMISTIC_OVERRIDE` even when an async yield fires outside
|
|
128
|
-
* the outer `setProjectionWriteActive` scope.
|
|
129
|
-
*/ function runProjectionComputed(e, t, r, o, n) {
|
|
130
|
-
const i = getOwner();
|
|
131
|
-
let c = false;
|
|
132
|
-
let s;
|
|
133
|
-
// Open loading window (seedLoadingValue): the observable store IS commit #0
|
|
134
|
-
// for the whole first flight, so the derive works a detached shadow of the
|
|
135
|
-
// seed — draft writes (pre-await, or between yields) land on the shadow and
|
|
136
|
-
// cannot tear through to readers (#2988; store reads resolve from the live
|
|
137
|
-
// backing, and the born-committed firewall removed the status gate that hid
|
|
138
|
-
// windowless drafts). Every commit point — sync return, each yield, the
|
|
139
|
-
// async landing — reconciles the shadow through the normal commit path, so
|
|
140
|
-
// a fully-sync derive still lands immediately (commit #0 superseded before
|
|
141
|
-
// any observer runs, same as a sync answer superseding loadingValue). The
|
|
142
|
-
// JSON round-trip matches the server's frozen-seed copy (seedLock): a
|
|
143
|
-
// loading-window seed is renderable data by contract. Optimistic note:
|
|
144
|
-
// onDraftWrite (override clearing) shifts from write-time to commit-time
|
|
145
|
-
// for the shadow run — an invisible draft write must not clobber a visible
|
|
146
|
-
// optimistic override mid-window.
|
|
147
|
-
const u = i.Ee ? JSON.parse(JSON.stringify(e[$TARGET][STORE_VALUE])) : null;
|
|
148
|
-
const a = new Proxy(e, createWriteTraps(() => !c || i.Te === s, n));
|
|
149
|
-
storeSetter(a, n => {
|
|
150
|
-
s = t(u ?? n);
|
|
151
|
-
c = true;
|
|
152
|
-
const commit = t => {
|
|
153
|
-
// Shadow run: a void/self return is the mutation form — the shadow
|
|
154
|
-
// carries the writes and is what commits. Commit a detached snapshot,
|
|
155
|
-
// never the shadow itself: reconcile adopts a new root value by
|
|
156
|
-
// identity, and handing it the live shadow would fuse the draft to the
|
|
157
|
-
// observable store — later shadow writes would mutate the backing
|
|
158
|
-
// silently and the next yield would diff the shadow against itself.
|
|
159
|
-
if (u && (t === undefined || t === u)) t = JSON.parse(JSON.stringify(u));
|
|
160
|
-
if (t === n || t === undefined) return;
|
|
161
|
-
const write = () => storeSetter(e, e => reconcileState(t, e, r, true));
|
|
162
|
-
o ? o(write) : write();
|
|
163
|
-
};
|
|
164
|
-
const a = handleAsync(i, s, commit);
|
|
165
|
-
// A still-open window after handleAsync means the return was the
|
|
166
|
-
// commit-#0 fall-through, not a landing — real landings arrive through
|
|
167
|
-
// the setter. A closed one is a genuine sync landing (windowless nodes
|
|
168
|
-
// were never open); commit it.
|
|
169
|
-
if (!i.Ee) commit(a);
|
|
170
|
-
});
|
|
171
|
-
return i;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
function createWriteTraps(e, t) {
|
|
175
|
-
const r = {
|
|
176
|
-
get(e, t) {
|
|
177
|
-
let o;
|
|
178
|
-
setWriteOverride(true);
|
|
179
|
-
setProjectionWriteActive(true);
|
|
180
|
-
try {
|
|
181
|
-
o = e[t];
|
|
182
|
-
} finally {
|
|
183
|
-
setWriteOverride(false);
|
|
184
|
-
setProjectionWriteActive(false);
|
|
185
|
-
}
|
|
186
|
-
if (t === $TARGET) return o;
|
|
187
|
-
return typeof o === "object" && o !== null ? new Proxy(o, r) : o;
|
|
188
|
-
},
|
|
189
|
-
has(e, t) {
|
|
190
|
-
let r;
|
|
191
|
-
setWriteOverride(true);
|
|
192
|
-
setProjectionWriteActive(true);
|
|
193
|
-
try {
|
|
194
|
-
r = t in e;
|
|
195
|
-
} finally {
|
|
196
|
-
setWriteOverride(false);
|
|
197
|
-
setProjectionWriteActive(false);
|
|
198
|
-
}
|
|
199
|
-
return r;
|
|
200
|
-
},
|
|
201
|
-
set(r, o, n) {
|
|
202
|
-
if (e && !e()) return true;
|
|
203
|
-
setWriteOverride(true);
|
|
204
|
-
setProjectionWriteActive(true);
|
|
205
|
-
try {
|
|
206
|
-
r[o] = n;
|
|
207
|
-
t?.();
|
|
208
|
-
} finally {
|
|
209
|
-
setWriteOverride(false);
|
|
210
|
-
setProjectionWriteActive(false);
|
|
211
|
-
}
|
|
212
|
-
return true;
|
|
213
|
-
},
|
|
214
|
-
deleteProperty(r, o) {
|
|
215
|
-
if (e && !e()) return true;
|
|
216
|
-
setWriteOverride(true);
|
|
217
|
-
setProjectionWriteActive(true);
|
|
218
|
-
try {
|
|
219
|
-
delete r[o];
|
|
220
|
-
t?.();
|
|
221
|
-
} finally {
|
|
222
|
-
setWriteOverride(false);
|
|
223
|
-
setProjectionWriteActive(false);
|
|
224
|
-
}
|
|
225
|
-
return true;
|
|
226
|
-
}
|
|
227
|
-
};
|
|
228
|
-
return r;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
export { createProjection, createProjectionInternal, createWriteTraps, runProjectionComputed };
|