@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,103 @@
|
|
|
1
|
+
import { isWrappable, ownEnumerableKeys } from "./store.js";
|
|
2
|
+
|
|
3
|
+
const DELETE = Symbol(0);
|
|
4
|
+
|
|
5
|
+
function isPrototypePollutionKey(t) {
|
|
6
|
+
return t === "__proto__" || t === "constructor" || t === "prototype";
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function updatePath(t, e, o = 0) {
|
|
10
|
+
let r, n = t;
|
|
11
|
+
if (o < e.length - 1) {
|
|
12
|
+
r = e[o];
|
|
13
|
+
const i = typeof r;
|
|
14
|
+
const f = Array.isArray(t);
|
|
15
|
+
if (i === "string" && isPrototypePollutionKey(r)) return;
|
|
16
|
+
if (Array.isArray(r)) {
|
|
17
|
+
for (let n = 0; n < r.length; n++) {
|
|
18
|
+
e[o] = r[n];
|
|
19
|
+
updatePath(t, e, o);
|
|
20
|
+
}
|
|
21
|
+
e[o] = r;
|
|
22
|
+
return;
|
|
23
|
+
} else if (f && i === "function") {
|
|
24
|
+
for (let n = 0; n < t.length; n++) {
|
|
25
|
+
if (r(t[n], n)) {
|
|
26
|
+
e[o] = n;
|
|
27
|
+
updatePath(t, e, o);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
e[o] = r;
|
|
31
|
+
return;
|
|
32
|
+
} else if (f && i === "object") {
|
|
33
|
+
const {from: n = 0, to: i = t.length - 1, by: f = 1} = r;
|
|
34
|
+
for (let r = n; r <= i; r += f) {
|
|
35
|
+
e[o] = r;
|
|
36
|
+
updatePath(t, e, o);
|
|
37
|
+
}
|
|
38
|
+
e[o] = r;
|
|
39
|
+
return;
|
|
40
|
+
} else if (o < e.length - 2) {
|
|
41
|
+
updatePath(t[r], e, o + 1);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
n = t[r];
|
|
45
|
+
}
|
|
46
|
+
let i = e[e.length - 1];
|
|
47
|
+
if (typeof i === "function") {
|
|
48
|
+
i = i(n);
|
|
49
|
+
if (i === n) return;
|
|
50
|
+
}
|
|
51
|
+
if (r === undefined && i == undefined) return;
|
|
52
|
+
if (i === DELETE) {
|
|
53
|
+
delete t[r];
|
|
54
|
+
} else if (r === undefined || isWrappable(n) && isWrappable(i) && !Array.isArray(i)) {
|
|
55
|
+
const e = r !== undefined ? t[r] : t;
|
|
56
|
+
const o = ownEnumerableKeys(i);
|
|
57
|
+
for (let t = 0; t < o.length; t++) {
|
|
58
|
+
const r = o[t];
|
|
59
|
+
if (typeof r === "string" && isPrototypePollutionKey(r)) continue;
|
|
60
|
+
const n = Object.getOwnPropertyDescriptor(i, r);
|
|
61
|
+
if (n.get || n.set) Object.defineProperty(e, r, n); else e[r] = n.value;
|
|
62
|
+
}
|
|
63
|
+
} else {
|
|
64
|
+
t[r] = i;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Path-based setter helper for `createStore`. Call `storePath(...path, value)`
|
|
70
|
+
* to produce a draft-mutating function suitable for passing to `setStore`.
|
|
71
|
+
*
|
|
72
|
+
* The canonical setter form in Solid 2.0 is the draft-mutating callback
|
|
73
|
+
* (`setStore(s => { s.user.name = "Ada"; })`). `storePath` is a backwards-
|
|
74
|
+
* compatibility helper for users porting from Solid 1.x's
|
|
75
|
+
* `setStore("user", "name", "Ada")` style — it's optional and you can mix the
|
|
76
|
+
* two styles freely.
|
|
77
|
+
*
|
|
78
|
+
* Path parts can be:
|
|
79
|
+
* - a single key — `"user"`, `0`
|
|
80
|
+
* - an array of keys — `[0, 1, 2]`
|
|
81
|
+
* - a range over an array — `{ from?, to?, by? }`
|
|
82
|
+
* - a filter `(item, index) => boolean` for arrays
|
|
83
|
+
*
|
|
84
|
+
* The final argument is the new value or an updater `(prev) => next`. Use
|
|
85
|
+
* `storePath.DELETE` to remove a property.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```ts
|
|
89
|
+
* const [state, setState] = createStore({ user: { name: "Ada" }, todos: [] });
|
|
90
|
+
*
|
|
91
|
+
* setState(storePath("user", "name", "Grace"));
|
|
92
|
+
* setState(storePath("todos", t => !t.done, "done", true)); // mark all undone as done
|
|
93
|
+
* setState(storePath("user", "nickname", storePath.DELETE));
|
|
94
|
+
* ```
|
|
95
|
+
*/ const storePath = /* @__PURE__ */ Object.assign(function storePath(...t) {
|
|
96
|
+
return e => {
|
|
97
|
+
updatePath(e, t);
|
|
98
|
+
};
|
|
99
|
+
}, {
|
|
100
|
+
DELETE: DELETE
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
export { storePath };
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import { pendingCheckActive } from "../core/core.js";
|
|
2
|
+
|
|
3
|
+
import { SUPPORTS_PROXY } from "../core/constants.js";
|
|
4
|
+
|
|
5
|
+
import "../core/scheduler.js";
|
|
6
|
+
|
|
7
|
+
import "../core/invariants.js";
|
|
8
|
+
|
|
9
|
+
import "../core/verdict.js";
|
|
10
|
+
|
|
11
|
+
import "../core/effect.js";
|
|
12
|
+
|
|
13
|
+
import { createMemo } from "../signals.js";
|
|
14
|
+
|
|
15
|
+
import { ownEnumerableKeys, $PROXY, isWrappable, $TARGET, trackSelf, witnessAffectsMark, mergedOverlay, STORE_VALUE, storeLookup, STORE_LOOKUP, $DELETED, wrap, getKeys, getPropertyDescriptor, $TRACK } from "./store.js";
|
|
16
|
+
|
|
17
|
+
function snapshotImpl(e, t, r, n) {
|
|
18
|
+
let o, s, c, i, f, u;
|
|
19
|
+
if (!isWrappable(e)) return e;
|
|
20
|
+
if (r && r.has(e)) return r.get(e);
|
|
21
|
+
if (!r) r = new Map;
|
|
22
|
+
if (o = e[$TARGET] || n?.get(e)?.[$TARGET]) {
|
|
23
|
+
if (t) {
|
|
24
|
+
trackSelf(o, $TRACK);
|
|
25
|
+
// A tracked walk reads THROUGH the record without touching the proxy
|
|
26
|
+
// traps — witness the record's affects() channel like a trap read would.
|
|
27
|
+
if (pendingCheckActive) witnessAffectsMark(o);
|
|
28
|
+
}
|
|
29
|
+
c = mergedOverlay(o);
|
|
30
|
+
s = Array.isArray(o[STORE_VALUE]);
|
|
31
|
+
r.set(e, c ? i = s ? [] : Object.create(Object.getPrototypeOf(o[STORE_VALUE])) : o[STORE_VALUE]);
|
|
32
|
+
e = o[STORE_VALUE];
|
|
33
|
+
n = o[STORE_LOOKUP] ?? storeLookup;
|
|
34
|
+
} else {
|
|
35
|
+
s = Array.isArray(e);
|
|
36
|
+
r.set(e, e);
|
|
37
|
+
}
|
|
38
|
+
if (s) {
|
|
39
|
+
const s = c?.length ?? e.length;
|
|
40
|
+
for (let p = 0; p < s; p++) {
|
|
41
|
+
u = c && p in c ? c[p] : e[p];
|
|
42
|
+
if (u === $DELETED) continue;
|
|
43
|
+
if (t && isWrappable(u)) wrap(u, o);
|
|
44
|
+
if ((f = snapshotImpl(u, t, r, n)) !== u || i) {
|
|
45
|
+
if (!i) r.set(e, i = [ ...e ]);
|
|
46
|
+
i[p] = f;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Deleted trailing slots are skipped above, so restore length to preserve
|
|
50
|
+
// holes instead of truncating the copy (#2846) — mirrors unwrapStoreValue.
|
|
51
|
+
if (i) i.length = s;
|
|
52
|
+
} else if (!c) {
|
|
53
|
+
// Specialized walk for the common no-overlay case (from #2756): the own
|
|
54
|
+
// descriptor gives the value directly, so each property is read once with
|
|
55
|
+
// no overlay membership checks.
|
|
56
|
+
const s = getKeys(e, undefined);
|
|
57
|
+
for (let c = 0, p = s.length; c < p; c++) {
|
|
58
|
+
const p = s[c];
|
|
59
|
+
const l = Object.getOwnPropertyDescriptor(e, p);
|
|
60
|
+
if (l.get) continue;
|
|
61
|
+
u = l.value;
|
|
62
|
+
if (t && isWrappable(u)) wrap(u, o);
|
|
63
|
+
if ((f = snapshotImpl(u, t, r, n)) !== u || i) {
|
|
64
|
+
if (!i) {
|
|
65
|
+
i = Object.create(Object.getPrototypeOf(e));
|
|
66
|
+
Object.assign(i, e);
|
|
67
|
+
}
|
|
68
|
+
i[p] = f;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
const s = getKeys(e, c);
|
|
73
|
+
for (let p = 0, l = s.length; p < l; p++) {
|
|
74
|
+
let l = s[p];
|
|
75
|
+
const a = getPropertyDescriptor(e, c, l);
|
|
76
|
+
if (a.get) continue;
|
|
77
|
+
u = l in c ? c[l] : e[l];
|
|
78
|
+
if (t && isWrappable(u)) wrap(u, o);
|
|
79
|
+
if ((f = snapshotImpl(u, t, r, n)) !== e[l] || i) {
|
|
80
|
+
if (!i) {
|
|
81
|
+
i = Object.create(Object.getPrototypeOf(e));
|
|
82
|
+
Object.assign(i, e);
|
|
83
|
+
}
|
|
84
|
+
i[l] = f;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return i || e;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function snapshot(e, t, r) {
|
|
92
|
+
return snapshotImpl(e, false, t, r);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Returns a plain (non-proxy) deep copy **and** subscribes the current
|
|
97
|
+
* tracking scope to every nested change in the source store. Any write
|
|
98
|
+
* anywhere in the subtree invalidates the consumer.
|
|
99
|
+
*
|
|
100
|
+
* Use this when you need plain data inside a reactive scope and want to
|
|
101
|
+
* react to deep mutations (e.g. passing a snapshot to `reconcile()` or to a
|
|
102
|
+
* memo that should rerun on any nested change). For most read paths, prefer
|
|
103
|
+
* direct property access — Solid stores already track per-property reads
|
|
104
|
+
* with no `deep()` wrapper needed.
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```ts
|
|
108
|
+
* const [state] = createStore({ a: { b: { c: 1 } } });
|
|
109
|
+
*
|
|
110
|
+
* createEffect(
|
|
111
|
+
* () => deep(state), // reruns on any nested change
|
|
112
|
+
* plain => sendToWorker(plain) // worker gets a non-proxy copy
|
|
113
|
+
* );
|
|
114
|
+
* ```
|
|
115
|
+
*/ function deep(e) {
|
|
116
|
+
return snapshotImpl(e, true);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function trueFn() {
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const propTraps = {
|
|
124
|
+
get(e, t, r) {
|
|
125
|
+
if (t === $PROXY) return r;
|
|
126
|
+
return e.get(t);
|
|
127
|
+
},
|
|
128
|
+
has(e, t) {
|
|
129
|
+
if (t === $PROXY) return true;
|
|
130
|
+
return e.has(t);
|
|
131
|
+
},
|
|
132
|
+
set: trueFn,
|
|
133
|
+
deleteProperty: trueFn,
|
|
134
|
+
getOwnPropertyDescriptor(e, t) {
|
|
135
|
+
return {
|
|
136
|
+
configurable: true,
|
|
137
|
+
enumerable: true,
|
|
138
|
+
get() {
|
|
139
|
+
return e.get(t);
|
|
140
|
+
},
|
|
141
|
+
set: trueFn,
|
|
142
|
+
deleteProperty: trueFn
|
|
143
|
+
};
|
|
144
|
+
},
|
|
145
|
+
ownKeys(e) {
|
|
146
|
+
return e.keys();
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
function resolveSource(e) {
|
|
151
|
+
return !(e = typeof e === "function" ? e() : e) ? {} : e;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const $SOURCES = Symbol(0);
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Merges multiple props-like objects into a single proxy that *preserves
|
|
158
|
+
* reactivity*. Reads are forwarded to the right-most source that defines the
|
|
159
|
+
* property, so later sources override earlier ones (like `Object.assign`).
|
|
160
|
+
*
|
|
161
|
+
* Function arguments are treated as memo-backed sources — useful for passing
|
|
162
|
+
* derived defaults whose computation should track reactively.
|
|
163
|
+
*
|
|
164
|
+
* Use this in component bodies to merge defaults / overrides without losing
|
|
165
|
+
* Solid's per-property tracking.
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* ```tsx
|
|
169
|
+
* function Button(_props: { label: string; type?: string; disabled?: boolean }) {
|
|
170
|
+
* const props = merge({ type: "button", disabled: false }, _props);
|
|
171
|
+
*
|
|
172
|
+
* return <button type={props.type} disabled={props.disabled}>{props.label}</button>;
|
|
173
|
+
* }
|
|
174
|
+
* ```
|
|
175
|
+
*/ function merge(...e) {
|
|
176
|
+
if (e.length === 1 && typeof e[0] !== "function") return e[0];
|
|
177
|
+
let t = false;
|
|
178
|
+
const r = [];
|
|
179
|
+
for (let n = 0; n < e.length; n++) {
|
|
180
|
+
const o = e[n];
|
|
181
|
+
t = t || !!o && $PROXY in o;
|
|
182
|
+
const s = !!o && o[$SOURCES];
|
|
183
|
+
if (s) {
|
|
184
|
+
for (let e = 0; e < s.length; e++) r.push(s[e]);
|
|
185
|
+
} else r.push(typeof o === "function" ? (t = true, createMemo(o)) : o);
|
|
186
|
+
}
|
|
187
|
+
if (SUPPORTS_PROXY && t) {
|
|
188
|
+
return new Proxy({
|
|
189
|
+
get(e) {
|
|
190
|
+
if (e === $SOURCES) return r;
|
|
191
|
+
for (let t = r.length - 1; t >= 0; t--) {
|
|
192
|
+
const n = resolveSource(r[t]);
|
|
193
|
+
if (e in n) return n[e];
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
has(e) {
|
|
197
|
+
for (let t = r.length - 1; t >= 0; t--) {
|
|
198
|
+
if (e in resolveSource(r[t])) return true;
|
|
199
|
+
}
|
|
200
|
+
return false;
|
|
201
|
+
},
|
|
202
|
+
keys() {
|
|
203
|
+
const e = new Set;
|
|
204
|
+
for (let t = 0; t < r.length; t++) {
|
|
205
|
+
const n = ownEnumerableKeys(resolveSource(r[t]));
|
|
206
|
+
for (let t = 0; t < n.length; t++) e.add(n[t]);
|
|
207
|
+
}
|
|
208
|
+
return [ ...e ];
|
|
209
|
+
}
|
|
210
|
+
}, propTraps);
|
|
211
|
+
}
|
|
212
|
+
const n = Object.create(null);
|
|
213
|
+
let o = false;
|
|
214
|
+
let s = r.length - 1;
|
|
215
|
+
for (let e = s; e >= 0; e--) {
|
|
216
|
+
const t = r[e];
|
|
217
|
+
if (!t) {
|
|
218
|
+
e === s && s--;
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
const c = Object.getOwnPropertyNames(t);
|
|
222
|
+
for (let r = c.length - 1; r >= 0; r--) {
|
|
223
|
+
const i = c[r];
|
|
224
|
+
if (i === "__proto__" || i === "constructor") continue;
|
|
225
|
+
if (!n[i]) {
|
|
226
|
+
o = o || e !== s;
|
|
227
|
+
const r = Object.getOwnPropertyDescriptor(t, i);
|
|
228
|
+
n[i] = r.get ? {
|
|
229
|
+
enumerable: true,
|
|
230
|
+
configurable: true,
|
|
231
|
+
get: r.get.bind(t)
|
|
232
|
+
} : r;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
if (!o) return r[s];
|
|
237
|
+
const c = {};
|
|
238
|
+
const i = Object.keys(n);
|
|
239
|
+
for (let e = i.length - 1; e >= 0; e--) {
|
|
240
|
+
const t = i[e], r = n[t];
|
|
241
|
+
if (r.get) Object.defineProperty(c, t, r); else c[t] = r.value;
|
|
242
|
+
}
|
|
243
|
+
c[$SOURCES] = r;
|
|
244
|
+
return c;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Returns a reactive proxy of `props` with the listed keys hidden. Tracking
|
|
249
|
+
* on the remaining keys is preserved.
|
|
250
|
+
*
|
|
251
|
+
* Use it to forward "rest" props to a child element while pulling out the
|
|
252
|
+
* keys your component handles itself — the equivalent of `splitProps(p, ["a","b"])[1]`.
|
|
253
|
+
*
|
|
254
|
+
* @example
|
|
255
|
+
* ```tsx
|
|
256
|
+
* function Input(props: { label: string; value: string; onInput: (v: string) => void } & JSX.HTMLAttributes<HTMLInputElement>) {
|
|
257
|
+
* const rest = omit(props, "label", "value", "onInput");
|
|
258
|
+
*
|
|
259
|
+
* return (
|
|
260
|
+
* <label>
|
|
261
|
+
* {props.label}
|
|
262
|
+
* <input
|
|
263
|
+
* {...rest}
|
|
264
|
+
* value={props.value}
|
|
265
|
+
* onInput={e => props.onInput(e.currentTarget.value)}
|
|
266
|
+
* />
|
|
267
|
+
* </label>
|
|
268
|
+
* );
|
|
269
|
+
* }
|
|
270
|
+
* ```
|
|
271
|
+
*/ function omit(e, ...t) {
|
|
272
|
+
if (SUPPORTS_PROXY && $PROXY in e) {
|
|
273
|
+
return new Proxy({
|
|
274
|
+
get(r) {
|
|
275
|
+
return t.includes(r) ? undefined : e[r];
|
|
276
|
+
},
|
|
277
|
+
has(r) {
|
|
278
|
+
return !t.includes(r) && r in e;
|
|
279
|
+
},
|
|
280
|
+
keys() {
|
|
281
|
+
return ownEnumerableKeys(e).filter(e => !t.includes(e));
|
|
282
|
+
}
|
|
283
|
+
}, propTraps);
|
|
284
|
+
}
|
|
285
|
+
const r = {};
|
|
286
|
+
const n = Object.getOwnPropertyNames(e);
|
|
287
|
+
const o = t.length > 4 && n.length > t.length ? new Set(t) : undefined;
|
|
288
|
+
for (const s of n) {
|
|
289
|
+
if (o ? !o.has(s) : !t.includes(s)) {
|
|
290
|
+
const t = Object.getOwnPropertyDescriptor(e, s);
|
|
291
|
+
!t.get && !t.set && t.enumerable && t.writable && t.configurable ? r[s] = t.value : Object.defineProperty(r, s, t);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
return r;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
export { deep, merge, omit, snapshot };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { Accessor } from "./signals.js";
|
|
2
|
+
import { type Store } from "./store/store.js";
|
|
3
|
+
/**
|
|
4
|
+
* Declares that in-flight work will change the targeted data: the named
|
|
5
|
+
* slot(s) — and everything DERIVED from them — read as pending
|
|
6
|
+
* (`isPending` → `true`) from the declaration until the surrounding
|
|
7
|
+
* transaction settles or reverts. Marks ride the same status rails as real
|
|
8
|
+
* in-flight async, so pendingness flows through memos and effects like any
|
|
9
|
+
* other pending source, while the marked values themselves stay readable
|
|
10
|
+
* (a mark is a promise of change, not an absence of value). This is the
|
|
11
|
+
* declaration verb of the pending model — additive only. A mark can turn
|
|
12
|
+
* pending ON for data the graph can't see changing yet; nothing can turn
|
|
13
|
+
* pending OFF while a real change is in flight — a quiet `refresh()`
|
|
14
|
+
* re-ask under a mark still reads pending (declaring the reload is what
|
|
15
|
+
* makes it a real question).
|
|
16
|
+
*
|
|
17
|
+
* Targets:
|
|
18
|
+
* - `affects(store)` — a store proxy (any record, root or nested): every
|
|
19
|
+
* record reachable from it at declaration time reads pending, including
|
|
20
|
+
* through captured child proxies (e.g. `<For>` rows). Siblings are
|
|
21
|
+
* untouched; records added after the declaration are not covered.
|
|
22
|
+
* - `affects(record, key)` — exactly the named slot of the record. One key
|
|
23
|
+
* per call (keys do NOT form a path — target the owning record directly).
|
|
24
|
+
* - `affects(accessor)` — a source accessor (signal or memo): the source
|
|
25
|
+
* reads pending.
|
|
26
|
+
*
|
|
27
|
+
* Typically called at the top of an `action` alongside optimistic writes —
|
|
28
|
+
* both are up-front declarations about the same mutation. Outside any
|
|
29
|
+
* transaction the mark is released at the end of the current flush.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* const send = action(function* (text: string) {
|
|
34
|
+
* setState(s => { s.messages.push({ text, status: "sending" }); });
|
|
35
|
+
* affects(state.messages.at(-1)!, "status"); // this slot pends until settle
|
|
36
|
+
* yield api.send(text);
|
|
37
|
+
* });
|
|
38
|
+
*
|
|
39
|
+
* const reload = action(function* () {
|
|
40
|
+
* affects(thing); // the whole store pends…
|
|
41
|
+
* refresh(thing); // …over this otherwise-quiet re-ask
|
|
42
|
+
* yield api.done();
|
|
43
|
+
* });
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare function affects(target: Accessor<unknown> | Store<object>): void;
|
|
47
|
+
export declare function affects<T extends object>(target: Store<T>, key: keyof T): void;
|
|
@@ -20,18 +20,18 @@ export declare class RevealController {
|
|
|
20
20
|
_evaluating: boolean;
|
|
21
21
|
constructor(order: OrderAccessor, collapsed: BoolAccessor);
|
|
22
22
|
_forEachOwnedSlot(fn: (slot: RevealSlot) => boolean | void): boolean;
|
|
23
|
-
|
|
23
|
+
_isReady(): boolean;
|
|
24
24
|
/**
|
|
25
25
|
* "Minimally ready" = this group has something visible to show under its own policy.
|
|
26
26
|
* Used by an enclosing `together` group to decide when it can release.
|
|
27
|
-
* - `together`:
|
|
27
|
+
* - `together`: every direct slot is minimally ready.
|
|
28
28
|
* - `sequential`: the first owned slot is minimally ready (frontier can advance).
|
|
29
29
|
* - `natural`: any owned slot is minimally ready.
|
|
30
30
|
*/
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
_isMinimallyReady(): boolean;
|
|
32
|
+
_register(slot: RevealSlot): void;
|
|
33
|
+
_unregister(slot: RevealSlot): void;
|
|
34
|
+
_evaluate(disabledOverride?: boolean, collapsedOverride?: boolean): void;
|
|
35
35
|
}
|
|
36
36
|
export declare class CollectionQueue extends Queue {
|
|
37
37
|
_collectionType: number;
|
|
@@ -48,7 +48,7 @@ export declare class CollectionQueue extends Queue {
|
|
|
48
48
|
constructor(type: number);
|
|
49
49
|
run(type: number): void;
|
|
50
50
|
notify(node: Effect<any>, type: number, flags: number, error?: any): boolean;
|
|
51
|
-
|
|
51
|
+
_checkSources(): void;
|
|
52
52
|
}
|
|
53
53
|
/**
|
|
54
54
|
* Lower-level primitive that backs the `<Loading>` flow control. Catches
|
|
@@ -128,7 +128,7 @@ export declare function createErrorBoundary<T, U>(fn: () => T, fallback: (error:
|
|
|
128
128
|
* own minimal signal).
|
|
129
129
|
* - `together` — every direct slot is minimally ready.
|
|
130
130
|
* - `natural` — any direct slot has visible content (leaves on resolve; nested
|
|
131
|
-
* composites
|
|
131
|
+
* composites via their own minimal signal).
|
|
132
132
|
*
|
|
133
133
|
* @example
|
|
134
134
|
* ```ts
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { type OptimisticLane } from "./lanes.js";
|
|
2
|
-
import type { Computed } from "./types.js";
|
|
3
|
-
export declare function
|
|
2
|
+
import type { Computed, Link } from "./types.js";
|
|
3
|
+
export declare function addPendingSource(el: Computed<any>, source: Computed<any>): boolean;
|
|
4
|
+
export declare function setPendingError(el: Computed<any>, source?: Computed<any>, error?: any): void;
|
|
5
|
+
export declare function forEachDependent(el: Computed<any>, fn: (node: Computed<any>, link: Link) => void): void;
|
|
6
|
+
export declare function settlePendingSource(el: Computed<any>, source?: Computed<any>, snap?: boolean): void;
|
|
4
7
|
export declare function isThenable<T>(value: T | PromiseLike<T>): value is PromiseLike<T>;
|
|
5
8
|
export declare function handleAsync<T>(el: Computed<T>, result: T | PromiseLike<T> | AsyncIterable<T>, setter?: (value: T) => void): T;
|
|
6
9
|
export declare function clearStatus(el: Computed<any>, clearUninitialized?: boolean): void;
|
|
@@ -10,6 +10,14 @@ export declare const REACTIVE_OPTIMISTIC_DIRTY: number;
|
|
|
10
10
|
export declare const REACTIVE_SNAPSHOT_STALE: number;
|
|
11
11
|
export declare const REACTIVE_LAZY: number;
|
|
12
12
|
export declare const REACTIVE_MANUAL_WRITE: number;
|
|
13
|
+
/**
|
|
14
|
+
* The pending recompute is a re-ask of the same question: `refresh()` dirtied
|
|
15
|
+
* the node while no tracked input changed value. Cleared whenever a real
|
|
16
|
+
* value-change notification arrives (`insertSubs`), and consumed by
|
|
17
|
+
* `recompute` into the node's `_reask` classification — a quiet (re-ask)
|
|
18
|
+
* pending window does not read as pending (question-scoped pending model).
|
|
19
|
+
*/
|
|
20
|
+
export declare const REACTIVE_REASK: number;
|
|
13
21
|
export declare const CONFIG_OWNED_WRITE: number;
|
|
14
22
|
export declare const CONFIG_NO_SNAPSHOT: number;
|
|
15
23
|
export declare const CONFIG_TRANSPARENT: number;
|
|
@@ -5,6 +5,12 @@ export declare const PRIMITIVE_IN_FORBIDDEN_SCOPE_MESSAGE = "[PRIMITIVE_IN_FORBI
|
|
|
5
5
|
export declare const REACTIVE_WRITE_IN_OWNED_SCOPE_SIGNAL_MESSAGE: string;
|
|
6
6
|
export declare const REACTIVE_WRITE_IN_OWNED_SCOPE_REFRESH_MESSAGE: string;
|
|
7
7
|
export declare let tracking: boolean;
|
|
8
|
+
/** @internal verdict-module glue */
|
|
9
|
+
export declare function setPendingCheckActive(v: boolean): void;
|
|
10
|
+
/** @internal verdict-module glue */
|
|
11
|
+
export declare function setLatestReadActive(v: boolean): void;
|
|
12
|
+
/** @internal verdict-module glue */
|
|
13
|
+
export declare function setContextInternal(v: Owner | null): void;
|
|
8
14
|
export declare let stale: boolean;
|
|
9
15
|
export declare let pendingCheckActive: boolean;
|
|
10
16
|
export declare let latestReadActive: boolean;
|
|
@@ -60,6 +66,12 @@ export declare function setStrictRead(v: string | false): string | false;
|
|
|
60
66
|
* ```
|
|
61
67
|
*/
|
|
62
68
|
export declare function untrack<T>(fn: () => T, strictReadLabel?: string | false): T;
|
|
69
|
+
/**
|
|
70
|
+
* Bring a computed to a readable state: lazy/disposed nodes are (re)computed;
|
|
71
|
+
* an isPending() probe (`refresh`) additionally pulls the node fully up to
|
|
72
|
+
* date so its status flags reflect the current graph.
|
|
73
|
+
*/
|
|
74
|
+
export declare function prepareComputed(comp: Computed<unknown>, refresh: boolean): void;
|
|
63
75
|
export declare function read<T>(el: Signal<T> | Computed<T>): T;
|
|
64
76
|
export declare function setSignal<T>(el: Signal<T> | Computed<T>, v: T | ((prev: T) => T)): T;
|
|
65
77
|
/**
|
|
@@ -97,76 +109,7 @@ export declare function setMemo<T>(el: Computed<T>, v: T | ((prev: T) => T)): T;
|
|
|
97
109
|
* ```
|
|
98
110
|
*/
|
|
99
111
|
export declare function runWithOwner<T>(owner: Owner | null, fn: () => T): T;
|
|
100
|
-
/**
|
|
101
|
-
* Keep the lazily-created isPending()/latest() companion nodes in sync with a
|
|
102
|
-
* new value. Every path that produces a value for `el` — direct set, async
|
|
103
|
-
* resolution, transition-held sync recompute — must route through here so a
|
|
104
|
-
* new write path can't silently skip the companions (#2831).
|
|
105
|
-
*/
|
|
106
|
-
export declare function syncCompanions<T>(el: Signal<T> | Computed<T>, value: T): void;
|
|
107
|
-
/**
|
|
108
|
-
* Update _pendingSignal when pending state changes. When the override clears
|
|
109
|
-
* (pending -> not pending), merge the sub-lane into the source's lane so
|
|
110
|
-
* isPending effects are blocked until the full scope resolves.
|
|
111
|
-
*/
|
|
112
|
-
export declare function updatePendingSignal(el: Signal<any> | Computed<any>): void;
|
|
113
|
-
/**
|
|
114
|
-
* A firewall's status change re-derives the verdicts of its probed leaves:
|
|
115
|
-
* leaf companions consult the firewall (broad inheritance), so async
|
|
116
|
-
* starting/settling on the firewall must poke them or they keep a stale
|
|
117
|
-
* verdict forever (V4 stuck-companion class, #2838).
|
|
118
|
-
*/
|
|
119
|
-
export declare function updateChildCompanions(el: Computed<any>): void;
|
|
120
|
-
/**
|
|
121
|
-
* Settlement checkpoint (#2838): re-derive a node's companions directly from
|
|
122
|
-
* its committed state. Called when the transition machinery for the node is
|
|
123
|
-
* done with it — a pending commit or an optimistic revert. Verdicts are
|
|
124
|
-
* written committed (not through setSignal) because a transition-scoped
|
|
125
|
-
* override window opened here would itself need a settlement, re-scheduling
|
|
126
|
-
* forever while async is still in flight. This is what keeps companions
|
|
127
|
-
* coherent past transition completion: a verdict is a property of the data
|
|
128
|
-
* (A19), so it must survive the transition that happened to produce it.
|
|
129
|
-
*/
|
|
130
|
-
export declare function snapCompanionsToState(owner: Signal<any> | Computed<any>): void;
|
|
131
112
|
export declare function staleValues<T>(fn: () => T, set?: boolean): T;
|
|
132
|
-
/**
|
|
133
|
-
* Reads reactive expressions while bypassing any pending async overlay — i.e.
|
|
134
|
-
* always returns the most-recently-committed value, even when newer reads
|
|
135
|
-
* inside `fn` are still in flight.
|
|
136
|
-
*
|
|
137
|
-
* Useful inside a `<Loading>` boundary's children when you want to keep
|
|
138
|
-
* showing the previous resolved data instead of the fallback while the next
|
|
139
|
-
* value loads.
|
|
140
|
-
*
|
|
141
|
-
* @example
|
|
142
|
-
* ```tsx
|
|
143
|
-
* <Loading fallback={<Skeleton />}>
|
|
144
|
-
* {/* During a transition, render the previous user instead of skeleton: *\/}
|
|
145
|
-
* <UserCard user={latest(() => user())} />
|
|
146
|
-
* </Loading>
|
|
147
|
-
* ```
|
|
148
|
-
*/
|
|
149
|
-
export declare function latest<T>(fn: () => T): T;
|
|
150
|
-
/**
|
|
151
|
-
* Returns `true` if any reactive read inside `fn` is showing a stale value
|
|
152
|
-
* while newer async work is pending. Does not subscribe — pair with a tracked
|
|
153
|
-
* memo if you want to react to pending status changes.
|
|
154
|
-
*
|
|
155
|
-
* Useful for showing inline transition indicators alongside the previous
|
|
156
|
-
* value (rather than swapping to a `<Loading>` fallback).
|
|
157
|
-
* Because `fn` is read normally, `isPending` participates in Loading/SSR
|
|
158
|
-
* readiness the same way the read itself would.
|
|
159
|
-
*
|
|
160
|
-
* @example
|
|
161
|
-
* ```tsx
|
|
162
|
-
* const pending = createMemo(() => isPending(() => user()));
|
|
163
|
-
*
|
|
164
|
-
* <button disabled={pending()}>{pending() ? "Saving…" : "Save"}</button>
|
|
165
|
-
*
|
|
166
|
-
* <button disabled={isPending(() => user())}>Save</button>
|
|
167
|
-
* ```
|
|
168
|
-
*/
|
|
169
|
-
export declare function isPending(fn: () => any): boolean;
|
|
170
113
|
/**
|
|
171
114
|
* Invalidates one reactive source, forcing it to re-execute even if its inputs
|
|
172
115
|
* haven't changed.
|
package/dist/types/core/dev.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export interface DevHooks {
|
|
|
6
6
|
onStoreNodeUpdate?: (state: any, property: PropertyKey, value: any, prev: any) => void;
|
|
7
7
|
}
|
|
8
8
|
export type DiagnosticSeverity = "warn" | "error";
|
|
9
|
-
export type DiagnosticCode = "STRICT_READ_UNTRACKED" | "PENDING_ASYNC_UNTRACKED_READ" | "PENDING_ASYNC_FORBIDDEN_SCOPE" | "REACTIVE_WRITE_IN_OWNED_SCOPE" | "ACTION_CALLED_IN_OWNED_SCOPE" | "RUN_WITH_DISPOSED_OWNER" | "NO_OWNER_CLEANUP" | "CLEANUP_IN_FORBIDDEN_SCOPE" | "SETTLED_CLEANUP_UNOWNED" | "PRIMITIVE_IN_FORBIDDEN_SCOPE" | "NO_OWNER_EFFECT" | "NO_OWNER_BOUNDARY" | "ASYNC_OUTSIDE_LOADING_BOUNDARY" | "INVALID_REFRESH_TARGET" | "MISSING_EFFECT_FN" | "SYNC_NODE_RECEIVED_ASYNC" | "REACTIVITY_HALTED" | "INVARIANT_VIOLATION";
|
|
9
|
+
export type DiagnosticCode = "STRICT_READ_UNTRACKED" | "PENDING_ASYNC_UNTRACKED_READ" | "PENDING_ASYNC_FORBIDDEN_SCOPE" | "REACTIVE_WRITE_IN_OWNED_SCOPE" | "ACTION_CALLED_IN_OWNED_SCOPE" | "RUN_WITH_DISPOSED_OWNER" | "NO_OWNER_CLEANUP" | "CLEANUP_IN_FORBIDDEN_SCOPE" | "SETTLED_CLEANUP_UNOWNED" | "PRIMITIVE_IN_FORBIDDEN_SCOPE" | "NO_OWNER_EFFECT" | "NO_OWNER_BOUNDARY" | "ASYNC_OUTSIDE_LOADING_BOUNDARY" | "INVALID_REFRESH_TARGET" | "INVALID_AFFECTS_TARGET" | "MISSING_EFFECT_FN" | "SYNC_NODE_RECEIVED_ASYNC" | "REACTIVITY_HALTED" | "INVARIANT_VIOLATION";
|
|
10
10
|
export type DiagnosticKind = "strict-read" | "async" | "write" | "lifecycle" | "owner" | "error";
|
|
11
11
|
export interface DiagnosticEvent {
|
|
12
12
|
sequence: number;
|
|
@@ -11,35 +11,5 @@ export declare let externalSourceConfig: {
|
|
|
11
11
|
factory: ExternalSourceFactory;
|
|
12
12
|
untrack: <T>(fn: () => T) => T;
|
|
13
13
|
} | null;
|
|
14
|
-
/**
|
|
15
|
-
* Registers a factory that bridges external reactive systems (e.g. MobX, Vue refs)
|
|
16
|
-
* into Solid's tracking graph. Every computation will be wrapped so that the
|
|
17
|
-
* external library can track its own dependencies alongside Solid's.
|
|
18
|
-
*
|
|
19
|
-
* Multiple calls pipe together: each new factory wraps the previous one.
|
|
20
|
-
*
|
|
21
|
-
* @param config.factory receives `(fn, trigger)` — wrap fn execution in external tracking,
|
|
22
|
-
* call trigger when external deps change. Return `{ track, dispose }`.
|
|
23
|
-
* @param config.untrack optional wrapper for `untrack` — disables external tracking too.
|
|
24
|
-
*
|
|
25
|
-
* @example
|
|
26
|
-
* ```ts
|
|
27
|
-
* // Bridge an external "subscribe / notify" library into Solid's graph.
|
|
28
|
-
* // `factory` wraps every Solid compute so the external library can attach
|
|
29
|
-
* // its own dependency tracker; `trigger` re-runs the compute on external
|
|
30
|
-
* // change. `untrack` mirrors Solid's `untrack()` into the external library
|
|
31
|
-
* // so that reads inside `untrack(...)` don't get tracked twice.
|
|
32
|
-
* enableExternalSource({
|
|
33
|
-
* factory: (compute, trigger) => {
|
|
34
|
-
* const sub = externalLib.subscribe(trigger);
|
|
35
|
-
* return {
|
|
36
|
-
* track: prev => externalLib.run(() => compute(prev)),
|
|
37
|
-
* dispose: () => sub.unsubscribe()
|
|
38
|
-
* };
|
|
39
|
-
* },
|
|
40
|
-
* untrack: fn => externalLib.untracked(fn)
|
|
41
|
-
* });
|
|
42
|
-
* ```
|
|
43
|
-
*/
|
|
44
14
|
export declare function enableExternalSource(config: ExternalSourceConfig): void;
|
|
45
15
|
export declare function _resetExternalSourceConfig(): void;
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import type { Computed } from "./types.js";
|
|
2
|
+
/** The queue a node belongs to, picked from its own zombie flag. */
|
|
3
|
+
export declare function queueFor(n: Computed<any>): Heap;
|
|
4
|
+
/**
|
|
5
|
+
* Schedule one subscriber to re-run on the next flush: tracked effects bypass
|
|
6
|
+
* the heap and go directly to their effect queue; everything else is inserted
|
|
7
|
+
* into its own (zombie-flag-routed) heap with the `_min` cursor pulled down.
|
|
8
|
+
*/
|
|
9
|
+
export declare function enqueueSub(node: Computed<any>): void;
|
|
2
10
|
export interface Heap {
|
|
3
11
|
_heap: (Computed<unknown> | undefined)[];
|
|
4
12
|
_marked: boolean;
|