@dougongjs/reactive 0.8.1 → 0.8.2
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 +6 -2
- package/dist/disposal-runtime.d.ts +0 -4
- package/dist/disposal-runtime.d.ts.map +1 -1
- package/dist/index.js +239 -252
- package/dist/observe.d.ts +0 -4
- package/dist/observe.d.ts.map +1 -1
- package/dist/protocol.d.ts +0 -1
- package/dist/protocol.d.ts.map +1 -1
- package/dist/signals.d.ts +0 -17
- package/dist/signals.d.ts.map +1 -1
- package/dist/sync-result.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,9 +19,11 @@ const count = signal(0)
|
|
|
19
19
|
const double = computed(() => count.get() * 2)
|
|
20
20
|
|
|
21
21
|
batch(() => count.set(21))
|
|
22
|
-
double.get()
|
|
22
|
+
double.get()
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
+
`double.get()` 返回 `42`。
|
|
26
|
+
|
|
25
27
|
`computed` 是惰性的,依赖动态追踪。`batch` 按订阅身份合并回调内的重复通知。三者都拒绝异步回调——同步追踪和批次边界不能跨越 `await`,与其产生静默的错误结果,不如立刻抛错。
|
|
26
28
|
|
|
27
29
|
### observe:把值的变化编译成资源的重建
|
|
@@ -56,9 +58,11 @@ const count = signal(0)
|
|
|
56
58
|
const double = computed(() => count.get() * 2)
|
|
57
59
|
|
|
58
60
|
batch(() => count.set(21))
|
|
59
|
-
double.get()
|
|
61
|
+
double.get()
|
|
60
62
|
```
|
|
61
63
|
|
|
64
|
+
`double.get()` returns `42`.
|
|
65
|
+
|
|
62
66
|
`computed` is lazy with dynamic dependency tracking. `batch` coalesces repeated notifications per subscription identity. All three reject asynchronous callbacks — synchronous tracking and batch boundaries cannot survive an `await`, and throwing immediately beats producing a silently wrong result.
|
|
63
67
|
|
|
64
68
|
### observe: compiling value change into resource rebuild
|
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
/** Fails at module load before an unavailable Promise primitive reaches a lifecycle transition. */
|
|
2
1
|
export declare function assertPromiseRuntime(withResolvers: unknown): asserts withResolvers is typeof Promise.withResolvers;
|
|
3
|
-
/** Resolves the conventional protocol key without mutating the ambient Symbol constructor. */
|
|
4
2
|
export declare function resolveDisposalSymbol(native: symbol | undefined, name: "Symbol.dispose" | "Symbol.asyncDispose"): symbol;
|
|
5
|
-
/** Canonical runtime key for Dougong's synchronous disposal protocol. */
|
|
6
3
|
export declare const disposeSymbol: typeof Symbol.dispose;
|
|
7
|
-
/** Canonical runtime key for Dougong's asynchronous disposal protocol. */
|
|
8
4
|
export declare const asyncDisposeSymbol: typeof Symbol.asyncDispose;
|
|
9
5
|
//# sourceMappingURL=disposal-runtime.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"disposal-runtime.d.ts","sourceRoot":"","sources":["../src/disposal-runtime.ts"],"names":[],"mappings":"AACA,
|
|
1
|
+
{"version":3,"file":"disposal-runtime.d.ts","sourceRoot":"","sources":["../src/disposal-runtime.ts"],"names":[],"mappings":"AACA,wBAAgB,oBAAoB,CAClC,aAAa,EAAE,OAAO,GACrB,OAAO,CAAC,aAAa,IAAI,OAAO,OAAO,CAAC,aAAa,CAIvD;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,IAAI,EAAE,gBAAgB,GAAG,qBAAqB,UAG/C;AAID,eAAO,MAAM,aAAa,EAAE,OAAO,MAAM,CAAC,OAGhB,CAAC;AAC3B,eAAO,MAAM,kBAAkB,EAAE,OAAO,MAAM,CAAC,YAGhB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,40 +1,37 @@
|
|
|
1
|
-
function
|
|
2
|
-
if (typeof
|
|
1
|
+
function D(s) {
|
|
2
|
+
if (typeof s != "function")
|
|
3
3
|
throw new Error("Unsupported JavaScript runtime: Promise.withResolvers is required");
|
|
4
4
|
}
|
|
5
|
-
function
|
|
6
|
-
return
|
|
5
|
+
function b(s, e) {
|
|
6
|
+
return s ?? Symbol.for(e);
|
|
7
7
|
}
|
|
8
|
-
|
|
9
|
-
const
|
|
8
|
+
D(Promise.withResolvers);
|
|
9
|
+
const w = b(
|
|
10
10
|
Symbol.dispose,
|
|
11
11
|
"Symbol.dispose"
|
|
12
|
-
),
|
|
12
|
+
), y = b(
|
|
13
13
|
Symbol.asyncDispose,
|
|
14
14
|
"Symbol.asyncDispose"
|
|
15
15
|
);
|
|
16
|
-
function
|
|
17
|
-
const
|
|
18
|
-
if (
|
|
19
|
-
throw
|
|
16
|
+
function a(s, e) {
|
|
17
|
+
const t = m(s);
|
|
18
|
+
if (t)
|
|
19
|
+
throw t.catch(() => {
|
|
20
20
|
}), new TypeError(e);
|
|
21
21
|
}
|
|
22
|
-
function
|
|
23
|
-
if (
|
|
24
|
-
const e =
|
|
22
|
+
function m(s) {
|
|
23
|
+
if (s === null || typeof s != "object" && typeof s != "function") return;
|
|
24
|
+
const e = s.then;
|
|
25
25
|
if (typeof e == "function")
|
|
26
26
|
return Promise.resolve().then(
|
|
27
|
-
() => new Promise((
|
|
27
|
+
() => new Promise((t, i) => Reflect.apply(e, s, [t, i]))
|
|
28
28
|
);
|
|
29
29
|
}
|
|
30
|
-
let
|
|
31
|
-
const
|
|
32
|
-
let
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
return new z(t);
|
|
36
|
-
}
|
|
37
|
-
class z {
|
|
30
|
+
let u = 0, p = !1;
|
|
31
|
+
const f = /* @__PURE__ */ new Set(), o = /* @__PURE__ */ new Set();
|
|
32
|
+
let c;
|
|
33
|
+
const l = /* @__PURE__ */ new WeakMap();
|
|
34
|
+
class g {
|
|
38
35
|
#e;
|
|
39
36
|
constructor(e) {
|
|
40
37
|
this.#e = e, Object.freeze(this);
|
|
@@ -43,224 +40,232 @@ class z {
|
|
|
43
40
|
const e = this.#e;
|
|
44
41
|
this.#e = void 0, e?.();
|
|
45
42
|
}
|
|
46
|
-
[
|
|
43
|
+
[w]() {
|
|
47
44
|
this.dispose();
|
|
48
45
|
}
|
|
49
46
|
}
|
|
50
|
-
function
|
|
51
|
-
if (
|
|
52
|
-
const
|
|
53
|
-
|
|
47
|
+
function O() {
|
|
48
|
+
if (p) return;
|
|
49
|
+
const s = [];
|
|
50
|
+
p = !0;
|
|
54
51
|
try {
|
|
55
|
-
for (;
|
|
56
|
-
const e =
|
|
57
|
-
e.delete(
|
|
58
|
-
const i =
|
|
52
|
+
for (; o.size || f.size; ) {
|
|
53
|
+
const e = o.size ? o : f, t = e.values().next().value;
|
|
54
|
+
e.delete(t);
|
|
55
|
+
const i = t.listener;
|
|
59
56
|
if (i)
|
|
60
57
|
try {
|
|
61
|
-
|
|
62
|
-
} catch (
|
|
63
|
-
|
|
58
|
+
a(i(), "Signal subscribers must be synchronous");
|
|
59
|
+
} catch (r) {
|
|
60
|
+
s.push(r);
|
|
64
61
|
}
|
|
65
62
|
}
|
|
66
63
|
} finally {
|
|
67
|
-
|
|
64
|
+
f.clear(), o.clear(), p = !1;
|
|
68
65
|
}
|
|
69
|
-
|
|
66
|
+
R(s);
|
|
70
67
|
}
|
|
71
|
-
function
|
|
72
|
-
for (const e of
|
|
73
|
-
(e.kind === "dependency" ?
|
|
74
|
-
|
|
68
|
+
function S(s) {
|
|
69
|
+
for (const e of s)
|
|
70
|
+
(e.kind === "dependency" ? o : f).add(e);
|
|
71
|
+
u || O();
|
|
75
72
|
}
|
|
76
|
-
function
|
|
77
|
-
|
|
78
|
-
const i = { kind:
|
|
79
|
-
return
|
|
80
|
-
i.listener = void 0,
|
|
73
|
+
function d(s, e, t) {
|
|
74
|
+
k(e);
|
|
75
|
+
const i = { kind: t, listener: e };
|
|
76
|
+
return s.add(i), new g(() => {
|
|
77
|
+
i.listener = void 0, s.delete(i);
|
|
81
78
|
});
|
|
82
79
|
}
|
|
83
|
-
function
|
|
84
|
-
if (
|
|
85
|
-
if (
|
|
86
|
-
throw new AggregateError(
|
|
80
|
+
function R(s) {
|
|
81
|
+
if (s.length === 1) throw s[0];
|
|
82
|
+
if (s.length > 1)
|
|
83
|
+
throw new AggregateError(s, "Reactive subscribers failed");
|
|
87
84
|
}
|
|
88
|
-
function
|
|
89
|
-
|
|
85
|
+
function E(s) {
|
|
86
|
+
c?.(s);
|
|
90
87
|
}
|
|
91
|
-
function
|
|
92
|
-
if (typeof
|
|
93
|
-
|
|
88
|
+
function I(s) {
|
|
89
|
+
if (typeof s != "function") throw new TypeError("batch() expects a function");
|
|
90
|
+
u++;
|
|
94
91
|
let e;
|
|
95
92
|
try {
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
} catch (
|
|
99
|
-
e = { ok: !1, error:
|
|
93
|
+
const t = s();
|
|
94
|
+
a(t, "Reactive batches must be synchronous"), e = { ok: !0, value: t };
|
|
95
|
+
} catch (t) {
|
|
96
|
+
e = { ok: !1, error: t };
|
|
100
97
|
} finally {
|
|
101
|
-
|
|
98
|
+
u--;
|
|
102
99
|
}
|
|
103
|
-
if (!
|
|
100
|
+
if (!u)
|
|
104
101
|
try {
|
|
105
|
-
|
|
106
|
-
} catch (
|
|
107
|
-
e = e.ok ? { ok: !1, error:
|
|
102
|
+
O();
|
|
103
|
+
} catch (t) {
|
|
104
|
+
e = e.ok ? { ok: !1, error: t } : { ok: !1, error: new AggregateError([e.error, t], "Reactive batch failed") };
|
|
108
105
|
}
|
|
109
106
|
if (!e.ok) throw e.error;
|
|
110
107
|
return e.value;
|
|
111
108
|
}
|
|
112
|
-
function
|
|
113
|
-
|
|
114
|
-
const i = /* @__PURE__ */ new Set(), n = {
|
|
115
|
-
get() {
|
|
116
|
-
return T(n), e;
|
|
117
|
-
},
|
|
118
|
-
set(r) {
|
|
119
|
-
if (a)
|
|
120
|
-
throw new TypeError("Computed signal calculations cannot write signals");
|
|
121
|
-
Object.is(e, r) || (e = r, s++, k(i));
|
|
122
|
-
},
|
|
123
|
-
subscribe(r) {
|
|
124
|
-
return v(i, r, "observer");
|
|
125
|
-
}
|
|
126
|
-
};
|
|
127
|
-
return d.set(n, {
|
|
128
|
-
get version() {
|
|
129
|
-
return s;
|
|
130
|
-
},
|
|
131
|
-
refresh() {
|
|
132
|
-
},
|
|
133
|
-
subscribeInvalidation: (r) => v(i, r, "dependency")
|
|
134
|
-
}), Object.freeze(n);
|
|
109
|
+
function L(s) {
|
|
110
|
+
return new z(s).view;
|
|
135
111
|
}
|
|
136
|
-
function
|
|
137
|
-
if (typeof
|
|
138
|
-
return new
|
|
112
|
+
function q(s) {
|
|
113
|
+
if (typeof s != "function") throw new TypeError("computed() expects a function");
|
|
114
|
+
return new P(s).view;
|
|
139
115
|
}
|
|
140
|
-
class
|
|
116
|
+
class z {
|
|
117
|
+
#e = /* @__PURE__ */ new Set();
|
|
118
|
+
#t;
|
|
119
|
+
#s = 0;
|
|
120
|
+
view;
|
|
121
|
+
constructor(e) {
|
|
122
|
+
this.#t = e, this.view = Object.freeze({
|
|
123
|
+
get: () => (E(this.view), this.#t),
|
|
124
|
+
set: (t) => this.#r(t),
|
|
125
|
+
subscribe: (t) => d(this.#e, t, "observer")
|
|
126
|
+
}), l.set(this.view, this);
|
|
127
|
+
}
|
|
128
|
+
get version() {
|
|
129
|
+
return this.#s;
|
|
130
|
+
}
|
|
131
|
+
refresh() {
|
|
132
|
+
}
|
|
133
|
+
subscribeInvalidation(e) {
|
|
134
|
+
return d(this.#e, e, "dependency");
|
|
135
|
+
}
|
|
136
|
+
#r(e) {
|
|
137
|
+
if (c)
|
|
138
|
+
throw new TypeError("Computed signal calculations cannot write signals");
|
|
139
|
+
Object.is(this.#t, e) || (this.#t = e, this.#s++, S(this.#e));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
class P {
|
|
141
143
|
#e;
|
|
142
|
-
#
|
|
143
|
-
#
|
|
144
|
-
#
|
|
145
|
-
#
|
|
146
|
-
#
|
|
144
|
+
#t = /* @__PURE__ */ new Set();
|
|
145
|
+
#s = /* @__PURE__ */ new Map();
|
|
146
|
+
#r;
|
|
147
|
+
#n = !1;
|
|
148
|
+
#i = !0;
|
|
147
149
|
#c = 0;
|
|
148
150
|
view;
|
|
149
151
|
constructor(e) {
|
|
150
152
|
this.#e = e, this.view = Object.freeze({
|
|
151
153
|
get: () => this.#o(),
|
|
152
|
-
subscribe: (
|
|
153
|
-
}),
|
|
154
|
+
subscribe: (t) => this.#h(t)
|
|
155
|
+
}), l.set(this.view, this);
|
|
154
156
|
}
|
|
155
157
|
get version() {
|
|
156
158
|
return this.#c;
|
|
157
159
|
}
|
|
158
160
|
refresh() {
|
|
159
|
-
if (this.#
|
|
160
|
-
this.#
|
|
161
|
+
if (this.#n) throw new TypeError("Circular computed signal");
|
|
162
|
+
this.#n = !0;
|
|
161
163
|
try {
|
|
162
|
-
this.#
|
|
164
|
+
this.#v();
|
|
163
165
|
} finally {
|
|
164
|
-
this.#
|
|
166
|
+
this.#n = !1;
|
|
165
167
|
}
|
|
166
168
|
}
|
|
167
169
|
#o() {
|
|
168
|
-
return this.refresh(),
|
|
170
|
+
return this.refresh(), E(this.view), this.#a();
|
|
169
171
|
}
|
|
170
172
|
#a() {
|
|
171
|
-
const e = this.#
|
|
173
|
+
const e = this.#r;
|
|
172
174
|
if (e.phase === "error") throw e.error;
|
|
173
175
|
return e.value;
|
|
174
176
|
}
|
|
175
177
|
subscribeInvalidation(e) {
|
|
176
178
|
return this.#h(e, "dependency");
|
|
177
179
|
}
|
|
178
|
-
#h(e,
|
|
179
|
-
|
|
180
|
-
const i = { kind:
|
|
181
|
-
if (this.#
|
|
180
|
+
#h(e, t = "observer") {
|
|
181
|
+
k(e);
|
|
182
|
+
const i = { kind: t, listener: e }, r = this.#t.size === 0;
|
|
183
|
+
if (this.#t.add(i), r)
|
|
182
184
|
try {
|
|
183
|
-
this.refresh(),
|
|
184
|
-
} catch (
|
|
185
|
-
throw this.#
|
|
185
|
+
this.refresh(), t === "observer" && this.#a(), this.#f();
|
|
186
|
+
} catch (n) {
|
|
187
|
+
throw this.#t.delete(i), this.#t.size || this.#u(), n;
|
|
186
188
|
}
|
|
187
|
-
return
|
|
188
|
-
i.listener = void 0, this.#
|
|
189
|
+
return new g(() => {
|
|
190
|
+
i.listener = void 0, this.#t.delete(i), this.#t.size || this.#u();
|
|
189
191
|
});
|
|
190
192
|
}
|
|
191
|
-
#
|
|
192
|
-
this.#
|
|
193
|
+
#d = () => {
|
|
194
|
+
this.#i || (this.#i = !0, S(this.#t));
|
|
193
195
|
};
|
|
194
196
|
#u() {
|
|
195
|
-
for (const e of this.#
|
|
197
|
+
for (const e of this.#s.values())
|
|
196
198
|
e.subscription?.dispose(), e.subscription = void 0;
|
|
197
199
|
}
|
|
198
200
|
#f() {
|
|
199
|
-
for (const e of this.#
|
|
200
|
-
e.subscription ??= e.node.subscribeInvalidation(this.#
|
|
201
|
-
}
|
|
202
|
-
#
|
|
203
|
-
const e = this.#
|
|
204
|
-
if (e && !this.#
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
201
|
+
for (const e of this.#s.values())
|
|
202
|
+
e.subscription ??= e.node.subscribeInvalidation(this.#d);
|
|
203
|
+
}
|
|
204
|
+
#v() {
|
|
205
|
+
const e = this.#r;
|
|
206
|
+
if (e && !this.#i && !this.#p()) return;
|
|
207
|
+
this.#i = !0;
|
|
208
|
+
const t = /* @__PURE__ */ new Set(), i = this.#b(t);
|
|
209
|
+
this.#l(t), (!e || (i.phase === "value" ? e.phase !== "value" || !Object.is(e.value, i.value) : e.phase !== "error" || !Object.is(e.error, i.error))) && this.#c++, this.#r = i, this.#i = !1, this.#t.size && this.#f();
|
|
210
|
+
}
|
|
211
|
+
#p() {
|
|
212
|
+
for (const e of this.#s.values())
|
|
213
|
+
if (e.node.refresh(), e.version !== e.node.version) return !0;
|
|
214
|
+
return this.#i;
|
|
215
|
+
}
|
|
216
|
+
#b(e) {
|
|
217
|
+
const t = c;
|
|
218
|
+
c = (i) => e.add(i);
|
|
215
219
|
try {
|
|
216
|
-
const
|
|
217
|
-
|
|
218
|
-
} catch (
|
|
219
|
-
|
|
220
|
+
const i = this.#e();
|
|
221
|
+
return a(i, "Computed signal calculations must be synchronous"), { phase: "value", value: i };
|
|
222
|
+
} catch (i) {
|
|
223
|
+
return { phase: "error", error: i };
|
|
220
224
|
} finally {
|
|
221
|
-
|
|
225
|
+
c = t;
|
|
222
226
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
for (const
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
const
|
|
229
|
-
|
|
230
|
-
|
|
227
|
+
}
|
|
228
|
+
#l(e) {
|
|
229
|
+
for (const [t, i] of this.#s)
|
|
230
|
+
e.has(t) || (i.subscription?.dispose(), this.#s.delete(t));
|
|
231
|
+
for (const t of e) {
|
|
232
|
+
const i = l.get(t);
|
|
233
|
+
if (!i) continue;
|
|
234
|
+
const r = this.#s.get(t) ?? {
|
|
235
|
+
node: i,
|
|
236
|
+
version: i.version,
|
|
231
237
|
subscription: void 0
|
|
232
238
|
};
|
|
233
|
-
|
|
239
|
+
r.version = i.version, this.#s.set(t, r);
|
|
234
240
|
}
|
|
235
|
-
(!e || (n.phase === "value" ? e.phase !== "value" || !Object.is(e.value, n.value) : e.phase !== "error" || !Object.is(e.error, n.error))) && this.#c++, this.#n = n, this.#t = !1, this.#s.size && this.#f();
|
|
236
241
|
}
|
|
237
242
|
}
|
|
238
|
-
function
|
|
239
|
-
if (typeof
|
|
243
|
+
function k(s) {
|
|
244
|
+
if (typeof s != "function")
|
|
240
245
|
throw new TypeError("Signal subscriber must be a function");
|
|
241
246
|
}
|
|
242
|
-
class
|
|
247
|
+
class j {
|
|
243
248
|
#e;
|
|
249
|
+
#t;
|
|
244
250
|
#s;
|
|
251
|
+
#r = { present: !1 };
|
|
252
|
+
#n = !1;
|
|
245
253
|
#i;
|
|
246
|
-
#n = { present: !1 };
|
|
247
|
-
#r = !1;
|
|
248
|
-
#t;
|
|
249
254
|
#c;
|
|
250
255
|
#o;
|
|
251
256
|
#a;
|
|
252
|
-
constructor(e,
|
|
253
|
-
this.#e = { phase: "active", binding: { owner: e, source:
|
|
257
|
+
constructor(e, t, i) {
|
|
258
|
+
this.#e = { phase: "active", binding: { owner: e, source: t, observer: i } };
|
|
254
259
|
}
|
|
255
260
|
start() {
|
|
256
|
-
const { owner: e, source:
|
|
257
|
-
if (
|
|
258
|
-
throw
|
|
259
|
-
this.#
|
|
260
|
-
const
|
|
261
|
-
this.#
|
|
262
|
-
() => this.#
|
|
263
|
-
() => this.#
|
|
261
|
+
const { owner: e, source: t } = this.#y(), i = t.subscribe(() => this.#d());
|
|
262
|
+
if (x(i, "Readable.subscribe()"), this.#e.phase !== "active")
|
|
263
|
+
throw v(i), new Error("Observation is not active");
|
|
264
|
+
this.#t = i, this.#p();
|
|
265
|
+
const r = e.spawn((C) => this.#u(C)), n = A(r);
|
|
266
|
+
this.#i = r, n.then(
|
|
267
|
+
() => this.#m(r),
|
|
268
|
+
() => this.#m(r)
|
|
264
269
|
);
|
|
265
270
|
}
|
|
266
271
|
attachOwnerCleanup(e) {
|
|
@@ -269,151 +274,133 @@ class x {
|
|
|
269
274
|
dispose() {
|
|
270
275
|
if (this.#a) return this.#a;
|
|
271
276
|
const e = Promise.withResolvers();
|
|
272
|
-
return this.#a = e.promise, this.#c = void 0, this.#
|
|
277
|
+
return this.#a = e.promise, this.#c = void 0, this.#g("disposed"), this.#o?.(), this.#h().then(e.resolve, e.reject), e.promise;
|
|
273
278
|
}
|
|
274
279
|
async #h() {
|
|
275
280
|
const e = [];
|
|
276
|
-
if (await this.#
|
|
281
|
+
if (await this.#l(e), await h(this.#O(), e), await h(this.#w(), e), e.length === 1) throw e[0];
|
|
277
282
|
if (e.length > 1) throw new AggregateError(e, "Observation cleanup failed");
|
|
278
283
|
}
|
|
279
|
-
#
|
|
280
|
-
this.#e.phase === "active" && (this.#
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
* The serialization point. Sleeps until invalidated, then replaces the current
|
|
284
|
-
* lifetime, repeating while the value keeps changing. The inner loop collapses
|
|
285
|
-
* a burst of changes into one replacement per settled value rather than one per
|
|
286
|
-
* notification.
|
|
287
|
-
*
|
|
288
|
-
* A failure here stops the observation and reports it. There is no caller to
|
|
289
|
-
* return to — this runs in a spawned task — so continuing would mean silently
|
|
290
|
-
* observing a value with a lifetime that failed to establish.
|
|
291
|
-
*/
|
|
284
|
+
#d() {
|
|
285
|
+
this.#e.phase === "active" && (this.#n = !0, this.#o?.());
|
|
286
|
+
}
|
|
287
|
+
// Stop on drain failure because continuing would observe a value whose resource ownership never established.
|
|
292
288
|
async #u(e) {
|
|
293
289
|
try {
|
|
294
290
|
for (; this.#e.phase === "active" && !e.aborted; )
|
|
295
|
-
for (await this.#f(e); this.#e.phase === "active" && !e.aborted && this.#
|
|
296
|
-
this.#
|
|
297
|
-
} catch (
|
|
298
|
-
if (this.#e.phase !== "active") throw
|
|
299
|
-
await this.#E(
|
|
291
|
+
for (await this.#f(e); this.#e.phase === "active" && !e.aborted && this.#n; )
|
|
292
|
+
this.#n = !1, await this.#v(e);
|
|
293
|
+
} catch (t) {
|
|
294
|
+
if (this.#e.phase !== "active") throw t;
|
|
295
|
+
await this.#E(t);
|
|
300
296
|
}
|
|
301
297
|
}
|
|
302
298
|
#f(e) {
|
|
303
|
-
return this.#
|
|
299
|
+
return this.#n || this.#e.phase !== "active" || e.aborted ? Promise.resolve() : new Promise((t) => {
|
|
304
300
|
const i = () => {
|
|
305
|
-
e.removeEventListener("abort", i), this.#o === i && (this.#o = void 0),
|
|
301
|
+
e.removeEventListener("abort", i), this.#o === i && (this.#o = void 0), t();
|
|
306
302
|
};
|
|
307
|
-
this.#o = i, e.addEventListener("abort", i, { once: !0 }), (this.#
|
|
303
|
+
this.#o = i, e.addEventListener("abort", i, { once: !0 }), (this.#n || this.#e.phase !== "active" || e.aborted) && i();
|
|
308
304
|
});
|
|
309
305
|
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
* Strictly in that order: overlapping them would run two owners of whatever the
|
|
313
|
-
* observer set up, and a failed observer would leave the previous lifetime half
|
|
314
|
-
* disposed.
|
|
315
|
-
*
|
|
316
|
-
* `#observed` is cleared while no lifetime is current, so an interrupted
|
|
317
|
-
* replacement cannot leave a value marked as observed when nothing is
|
|
318
|
-
* observing it.
|
|
319
|
-
*/
|
|
320
|
-
async #l(e) {
|
|
306
|
+
// Clear the observed marker during replacement so interruption cannot leave a value without its owner.
|
|
307
|
+
async #v(e) {
|
|
321
308
|
if (this.#e.phase !== "active" || e.aborted) return;
|
|
322
|
-
const
|
|
323
|
-
if (this.#
|
|
324
|
-
const i = this.#
|
|
325
|
-
i && await i.dispose(), this.#
|
|
309
|
+
const t = this.#e.binding.source.get();
|
|
310
|
+
if (this.#r.present && Object.is(t, this.#r.value)) return;
|
|
311
|
+
const i = this.#w();
|
|
312
|
+
i && await i.dispose(), this.#r = { present: !1 }, !(this.#e.phase !== "active" || e.aborted) && this.#p();
|
|
326
313
|
}
|
|
327
|
-
#
|
|
328
|
-
const { owner: e, source:
|
|
329
|
-
|
|
330
|
-
const
|
|
331
|
-
this.#
|
|
332
|
-
}
|
|
333
|
-
#
|
|
334
|
-
const i = this.#
|
|
335
|
-
|
|
336
|
-
}
|
|
337
|
-
async #
|
|
338
|
-
const
|
|
339
|
-
if (this.#
|
|
314
|
+
#p() {
|
|
315
|
+
const { owner: e, source: t } = this.#y(), i = e.lifetime("observation");
|
|
316
|
+
T(i, "ObservationOwner.lifetime()"), this.#s = i;
|
|
317
|
+
const r = t.get();
|
|
318
|
+
this.#b(r, i), this.#e.phase === "active" && (this.#r = { present: !0, value: r });
|
|
319
|
+
}
|
|
320
|
+
#b(e, t) {
|
|
321
|
+
const i = this.#y().observer(e, t);
|
|
322
|
+
a(i, "Observers must be synchronous; use owner.spawn() for async work");
|
|
323
|
+
}
|
|
324
|
+
async #l(e) {
|
|
325
|
+
const t = this.#t;
|
|
326
|
+
if (this.#t = void 0, !!t)
|
|
340
327
|
try {
|
|
341
|
-
|
|
328
|
+
v(t);
|
|
342
329
|
} catch (i) {
|
|
343
330
|
e.push(i);
|
|
344
331
|
}
|
|
345
332
|
}
|
|
346
|
-
#
|
|
347
|
-
const e = this.#
|
|
348
|
-
return this.#
|
|
333
|
+
#w() {
|
|
334
|
+
const e = this.#s;
|
|
335
|
+
return this.#s = void 0, e;
|
|
349
336
|
}
|
|
350
337
|
#O() {
|
|
351
|
-
const e = this.#
|
|
352
|
-
return this.#
|
|
338
|
+
const e = this.#i;
|
|
339
|
+
return this.#i = void 0, e;
|
|
353
340
|
}
|
|
354
341
|
#S() {
|
|
355
342
|
const e = this.#c;
|
|
356
343
|
return this.#c = void 0, e;
|
|
357
344
|
}
|
|
358
|
-
#
|
|
359
|
-
this.#
|
|
345
|
+
#m(e) {
|
|
346
|
+
this.#i === e && (this.#i = void 0);
|
|
360
347
|
}
|
|
361
348
|
async #E(e) {
|
|
362
|
-
const
|
|
363
|
-
throw this.#
|
|
349
|
+
const t = [e];
|
|
350
|
+
throw this.#g("stopped"), this.#o?.(), await this.#l(t), await h(this.#w(), t), this.#i = void 0, await h(this.#S(), t), t.length === 1 ? t[0] : new AggregateError(t, "Observation stopped after a replacement failed");
|
|
364
351
|
}
|
|
365
|
-
#
|
|
352
|
+
#y() {
|
|
366
353
|
const e = this.#e;
|
|
367
354
|
if (e.phase !== "active") throw new Error("Observation is not active");
|
|
368
355
|
return e.binding;
|
|
369
356
|
}
|
|
370
|
-
#
|
|
371
|
-
this.#e = { phase: e }, this.#
|
|
357
|
+
#g(e) {
|
|
358
|
+
this.#e = { phase: e }, this.#r = { present: !1 }, this.#n = !1;
|
|
372
359
|
}
|
|
373
360
|
}
|
|
374
|
-
function
|
|
361
|
+
function B(s, e, t) {
|
|
375
362
|
if (!e || typeof e.get != "function" || typeof e.subscribe != "function")
|
|
376
363
|
throw new TypeError("observe() expects a readable source");
|
|
377
|
-
if (typeof
|
|
378
|
-
if (!
|
|
364
|
+
if (typeof t != "function") throw new TypeError("Observer must be a function");
|
|
365
|
+
if (!s || typeof s.cleanup != "function" || typeof s.lifetime != "function" || typeof s.spawn != "function")
|
|
379
366
|
throw new TypeError("observe() expects an observation owner");
|
|
380
|
-
const i = new
|
|
381
|
-
|
|
367
|
+
const i = new j(s, e, t), r = s.cleanup(() => i.dispose());
|
|
368
|
+
T(r, "ObservationOwner.cleanup()"), i.attachOwnerCleanup(r);
|
|
382
369
|
try {
|
|
383
|
-
return i.start(),
|
|
384
|
-
} catch (
|
|
370
|
+
return i.start(), r;
|
|
371
|
+
} catch (n) {
|
|
385
372
|
throw i.dispose().catch(() => {
|
|
386
|
-
}),
|
|
373
|
+
}), n;
|
|
387
374
|
}
|
|
388
375
|
}
|
|
389
|
-
function
|
|
390
|
-
if (!
|
|
376
|
+
function x(s, e) {
|
|
377
|
+
if (!s || typeof s.dispose != "function" || typeof s[w] != "function")
|
|
391
378
|
throw new TypeError(`${e} must return a Disposable`);
|
|
392
379
|
}
|
|
393
|
-
function
|
|
394
|
-
if (!
|
|
380
|
+
function T(s, e) {
|
|
381
|
+
if (!s || typeof s.dispose != "function" || typeof s[y] != "function")
|
|
395
382
|
throw new TypeError(`${e} must return an AsyncDisposable`);
|
|
396
383
|
}
|
|
397
|
-
function
|
|
398
|
-
const e =
|
|
384
|
+
function A(s) {
|
|
385
|
+
const e = s && typeof s.dispose == "function" && typeof s[y] == "function" ? m(s.result) : void 0;
|
|
399
386
|
if (!e)
|
|
400
387
|
throw new TypeError("ObservationOwner.spawn() must return an ObservationTask");
|
|
401
388
|
return e;
|
|
402
389
|
}
|
|
403
|
-
function
|
|
404
|
-
|
|
390
|
+
function v(s) {
|
|
391
|
+
a(s.dispose(), "Readable subscriptions must dispose synchronously");
|
|
405
392
|
}
|
|
406
|
-
async function
|
|
407
|
-
if (
|
|
393
|
+
async function h(s, e) {
|
|
394
|
+
if (s)
|
|
408
395
|
try {
|
|
409
|
-
await
|
|
410
|
-
} catch (
|
|
411
|
-
e.push(
|
|
396
|
+
await s.dispose();
|
|
397
|
+
} catch (t) {
|
|
398
|
+
e.push(t);
|
|
412
399
|
}
|
|
413
400
|
}
|
|
414
401
|
export {
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
402
|
+
I as batch,
|
|
403
|
+
q as computed,
|
|
404
|
+
B as observe,
|
|
405
|
+
L as signal
|
|
419
406
|
};
|
package/dist/observe.d.ts
CHANGED
|
@@ -8,9 +8,5 @@ export interface ObservationOwner<Child extends AsyncDisposable = AsyncDisposabl
|
|
|
8
8
|
readonly spawn: <T>(task: (signal: AbortSignal) => T | PromiseLike<T>) => ObservationTask<T>;
|
|
9
9
|
}
|
|
10
10
|
export type Observer<T, Child extends AsyncDisposable> = (value: T, lifetime: Child) => void;
|
|
11
|
-
/**
|
|
12
|
-
* Lifetime-aware synchronization built only from the public source and
|
|
13
|
-
* Lifetime protocols. It is a reactive-layer combinator, not a Core hook.
|
|
14
|
-
*/
|
|
15
11
|
export declare function observe<T, Child extends AsyncDisposable>(owner: ObservationOwner<Child>, source: Readable<T>, observer: Observer<T, Child>): AsyncDisposable;
|
|
16
12
|
//# sourceMappingURL=observe.d.ts.map
|
package/dist/observe.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"observe.d.ts","sourceRoot":"","sources":["../src/observe.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,eAAe,EAEpB,KAAK,QAAQ,EACd,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"observe.d.ts","sourceRoot":"","sources":["../src/observe.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,eAAe,EAEpB,KAAK,QAAQ,EACd,MAAM,YAAY,CAAC;AAKpB,MAAM,WAAW,eAAe,CAAC,CAAC,GAAG,IAAI,CAAE,SAAQ,eAAe;IAChE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB,CAAC,KAAK,SAAS,eAAe,GAAG,eAAe;IAC/E,QAAQ,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,OAAO,KAAK,eAAe,CAAC;IAC9D,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC;IAC5C,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,KAAK,eAAe,CAAC,CAAC,CAAC,CAAC;CAC9F;AAED,MAAM,MAAM,QAAQ,CAAC,CAAC,EAAE,KAAK,SAAS,eAAe,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,KAAK,IAAI,CAAC;AAgN7F,wBAAgB,OAAO,CAAC,CAAC,EAAE,KAAK,SAAS,eAAe,EACtD,KAAK,EAAE,gBAAgB,CAAC,KAAK,CAAC,EAC9B,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,EACnB,QAAQ,EAAE,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC,GAC3B,eAAe,CAyBjB"}
|
package/dist/protocol.d.ts
CHANGED
|
@@ -7,7 +7,6 @@ export interface AsyncDisposable {
|
|
|
7
7
|
dispose(): Promise<void>;
|
|
8
8
|
[Symbol.asyncDispose](): Promise<void>;
|
|
9
9
|
}
|
|
10
|
-
/** Structural observable protocol shared by signals, ContributionViews and diagnostics. */
|
|
11
10
|
export interface Readable<T> {
|
|
12
11
|
get(): T;
|
|
13
12
|
subscribe(listener: () => void): Disposable;
|
package/dist/protocol.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,kBAAkB,EAClB,aAAa,GACd,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,UAAU;IACzB,OAAO,IAAI,IAAI,CAAC;IAChB,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,QAAQ,CAAC,CAAC;IACzB,GAAG,IAAI,CAAC,CAAC;IACT,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,UAAU,CAAC;CAC7C"}
|
package/dist/signals.d.ts
CHANGED
|
@@ -1,29 +1,12 @@
|
|
|
1
1
|
import { Readable } from './protocol';
|
|
2
2
|
declare const dougongSignal: unique symbol;
|
|
3
|
-
/** A reactive node created by Dougong and safe to compose with computed(). */
|
|
4
3
|
export interface ReadonlySignal<T> extends Readable<T> {
|
|
5
4
|
readonly [dougongSignal]: true;
|
|
6
5
|
}
|
|
7
6
|
export interface Signal<T> extends ReadonlySignal<T> {
|
|
8
7
|
readonly set: (value: T) => void;
|
|
9
8
|
}
|
|
10
|
-
/**
|
|
11
|
-
* Defers notification until the outermost batch returns, so a group of writes is
|
|
12
|
-
* observed once. Nested calls join the outer batch.
|
|
13
|
-
*
|
|
14
|
-
* Notifications are queued by subscription, not by callback, so the same
|
|
15
|
-
* function subscribed to two signals is still called twice — deduplicating by
|
|
16
|
-
* callback would silently merge two independent subscriptions.
|
|
17
|
-
*
|
|
18
|
-
* If both the body and the flush fail, both errors are reported. A subscriber
|
|
19
|
-
* failing during flush must not hide why the batch itself failed.
|
|
20
|
-
*/
|
|
21
9
|
export declare function batch<T>(callback: () => T): T;
|
|
22
|
-
/**
|
|
23
|
-
* A value with subscribers. Writes are compared with `Object.is`, so setting the
|
|
24
|
-
* same value notifies nobody — which is what makes `computed` chains stable
|
|
25
|
-
* under idempotent updates.
|
|
26
|
-
*/
|
|
27
10
|
export declare function signal<T>(initialValue: T): Signal<T>;
|
|
28
11
|
export declare function computed<T>(calculate: () => T): ReadonlySignal<T>;
|
|
29
12
|
export {};
|
package/dist/signals.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signals.d.ts","sourceRoot":"","sources":["../src/signals.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"signals.d.ts","sourceRoot":"","sources":["../src/signals.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkC,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAG3E,OAAO,CAAC,MAAM,aAAa,EAAE,OAAO,MAAM,CAAC;AAE3C,MAAM,WAAW,cAAc,CAAC,CAAC,CAAE,SAAQ,QAAQ,CAAC,CAAC,CAAC;IACpD,QAAQ,CAAC,CAAC,aAAa,CAAC,EAAE,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,MAAM,CAAC,CAAC,CAAE,SAAQ,cAAc,CAAC,CAAC,CAAC;IAClD,QAAQ,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;CAClC;AA0GD,wBAAgB,KAAK,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC,CA4B7C;AAED,wBAAgB,MAAM,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAEpD;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAGjE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-result.d.ts","sourceRoot":"","sources":["../src/sync-result.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sync-result.d.ts","sourceRoot":"","sources":["../src/sync-result.ts"],"names":[],"mappings":"AACA,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAOvE;AAGD,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,SAAS,CAO5E"}
|