@zeix/cause-effect 0.14.1 → 0.14.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 +1 -1
- package/biome.json +35 -0
- package/index.d.ts +6 -6
- package/index.dev.js +294 -0
- package/index.js +1 -1
- package/index.ts +21 -20
- package/package.json +5 -6
- package/src/computed.d.ts +2 -2
- package/src/computed.ts +15 -15
- package/src/effect.d.ts +7 -7
- package/src/effect.ts +13 -11
- package/src/scheduler.d.ts +2 -2
- package/src/scheduler.ts +3 -3
- package/src/signal.d.ts +1 -1
- package/src/signal.ts +4 -3
- package/src/util.ts +1 -1
- package/test/batch.test.ts +11 -11
- package/test/benchmark.test.ts +78 -42
- package/test/computed.test.ts +30 -30
- package/test/effect.test.ts +19 -19
- package/test/state.test.ts +33 -33
- package/test/util/framework-types.ts +2 -2
- package/test/util/perf-tests.ts +2 -2
- package/test/util/reactive-framework.ts +1 -1
package/README.md
CHANGED
package/biome.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://biomejs.dev/schemas/2.1.4/schema.json",
|
|
3
|
+
"vcs": {
|
|
4
|
+
"enabled": false,
|
|
5
|
+
"clientKind": "git",
|
|
6
|
+
"useIgnoreFile": false
|
|
7
|
+
},
|
|
8
|
+
"files": {
|
|
9
|
+
"ignoreUnknown": false,
|
|
10
|
+
"includes": ["**", "!index.js", "!index.dev.js", "!**/*.d.ts"]
|
|
11
|
+
},
|
|
12
|
+
"formatter": {
|
|
13
|
+
"enabled": true,
|
|
14
|
+
"indentStyle": "tab"
|
|
15
|
+
},
|
|
16
|
+
"linter": {
|
|
17
|
+
"enabled": true,
|
|
18
|
+
"rules": {
|
|
19
|
+
"recommended": true
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"javascript": {
|
|
23
|
+
"formatter": {
|
|
24
|
+
"quoteStyle": "double"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"assist": {
|
|
28
|
+
"enabled": true,
|
|
29
|
+
"actions": {
|
|
30
|
+
"source": {
|
|
31
|
+
"organizeImports": "on"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
package/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @name Cause & Effect
|
|
3
|
-
* @version 0.14.
|
|
3
|
+
* @version 0.14.2
|
|
4
4
|
* @author Esther Brunner
|
|
5
5
|
*/
|
|
6
|
-
export {
|
|
7
|
-
export { type Signal, type MaybeSignal, type SignalValues, UNSET, isSignal, isComputedCallback, toSignal, } from './src/signal';
|
|
8
|
-
export { type State, TYPE_STATE, state, isState } from './src/state';
|
|
9
|
-
export { type Computed, type ComputedCallback, TYPE_COMPUTED, computed, isComputed, } from './src/computed';
|
|
6
|
+
export { type Computed, type ComputedCallback, computed, isComputed, TYPE_COMPUTED, } from './src/computed';
|
|
10
7
|
export { type EffectMatcher, effect } from './src/effect';
|
|
11
|
-
export {
|
|
8
|
+
export { batch, type Cleanup, enqueue, flush, notify, observe, subscribe, type Updater, type Watcher, watch, } from './src/scheduler';
|
|
9
|
+
export { isComputedCallback, isSignal, type MaybeSignal, type Signal, type SignalValues, toSignal, UNSET, } from './src/signal';
|
|
10
|
+
export { isState, type State, state, TYPE_STATE } from './src/state';
|
|
11
|
+
export { CircularDependencyError, isFunction } from './src/util';
|
package/index.dev.js
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
// src/scheduler.ts
|
|
2
|
+
var active;
|
|
3
|
+
var pending = new Set;
|
|
4
|
+
var batchDepth = 0;
|
|
5
|
+
var updateMap = new Map;
|
|
6
|
+
var requestId;
|
|
7
|
+
var updateDOM = () => {
|
|
8
|
+
requestId = undefined;
|
|
9
|
+
const updates = Array.from(updateMap.values());
|
|
10
|
+
updateMap.clear();
|
|
11
|
+
for (const update of updates) {
|
|
12
|
+
update();
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
var requestTick = () => {
|
|
16
|
+
if (requestId)
|
|
17
|
+
cancelAnimationFrame(requestId);
|
|
18
|
+
requestId = requestAnimationFrame(updateDOM);
|
|
19
|
+
};
|
|
20
|
+
queueMicrotask(updateDOM);
|
|
21
|
+
var watch = (notice) => {
|
|
22
|
+
const cleanups = new Set;
|
|
23
|
+
const w = notice;
|
|
24
|
+
w.off = (on) => {
|
|
25
|
+
cleanups.add(on);
|
|
26
|
+
};
|
|
27
|
+
w.cleanup = () => {
|
|
28
|
+
for (const cleanup of cleanups) {
|
|
29
|
+
cleanup();
|
|
30
|
+
}
|
|
31
|
+
cleanups.clear();
|
|
32
|
+
};
|
|
33
|
+
return w;
|
|
34
|
+
};
|
|
35
|
+
var subscribe = (watchers) => {
|
|
36
|
+
if (active && !watchers.has(active)) {
|
|
37
|
+
const watcher = active;
|
|
38
|
+
watchers.add(watcher);
|
|
39
|
+
active.off(() => {
|
|
40
|
+
watchers.delete(watcher);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
var notify = (watchers) => {
|
|
45
|
+
for (const watcher of watchers) {
|
|
46
|
+
if (batchDepth)
|
|
47
|
+
pending.add(watcher);
|
|
48
|
+
else
|
|
49
|
+
watcher();
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
var flush = () => {
|
|
53
|
+
while (pending.size) {
|
|
54
|
+
const watchers = Array.from(pending);
|
|
55
|
+
pending.clear();
|
|
56
|
+
for (const watcher of watchers) {
|
|
57
|
+
watcher();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
var batch = (fn) => {
|
|
62
|
+
batchDepth++;
|
|
63
|
+
try {
|
|
64
|
+
fn();
|
|
65
|
+
} finally {
|
|
66
|
+
flush();
|
|
67
|
+
batchDepth--;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
var observe = (run, watcher) => {
|
|
71
|
+
const prev = active;
|
|
72
|
+
active = watcher;
|
|
73
|
+
try {
|
|
74
|
+
run();
|
|
75
|
+
} finally {
|
|
76
|
+
active = prev;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
var enqueue = (fn, dedupe) => new Promise((resolve, reject) => {
|
|
80
|
+
updateMap.set(dedupe || Symbol(), () => {
|
|
81
|
+
try {
|
|
82
|
+
resolve(fn());
|
|
83
|
+
} catch (error) {
|
|
84
|
+
reject(error);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
requestTick();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// src/util.ts
|
|
91
|
+
var isFunction = (value) => typeof value === "function";
|
|
92
|
+
var isObjectOfType = (value, type) => Object.prototype.toString.call(value) === `[object ${type}]`;
|
|
93
|
+
var toError = (reason) => reason instanceof Error ? reason : Error(String(reason));
|
|
94
|
+
|
|
95
|
+
class CircularDependencyError extends Error {
|
|
96
|
+
constructor(where) {
|
|
97
|
+
super(`Circular dependency in ${where} detected`);
|
|
98
|
+
this.name = "CircularDependencyError";
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// src/state.ts
|
|
103
|
+
var TYPE_STATE = "State";
|
|
104
|
+
var state = (initialValue) => {
|
|
105
|
+
const watchers = new Set;
|
|
106
|
+
let value = initialValue;
|
|
107
|
+
const s = {
|
|
108
|
+
[Symbol.toStringTag]: TYPE_STATE,
|
|
109
|
+
get: () => {
|
|
110
|
+
subscribe(watchers);
|
|
111
|
+
return value;
|
|
112
|
+
},
|
|
113
|
+
set: (v) => {
|
|
114
|
+
if (Object.is(value, v))
|
|
115
|
+
return;
|
|
116
|
+
value = v;
|
|
117
|
+
notify(watchers);
|
|
118
|
+
if (UNSET === value)
|
|
119
|
+
watchers.clear();
|
|
120
|
+
},
|
|
121
|
+
update: (fn) => {
|
|
122
|
+
s.set(fn(value));
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
return s;
|
|
126
|
+
};
|
|
127
|
+
var isState = (value) => isObjectOfType(value, TYPE_STATE);
|
|
128
|
+
|
|
129
|
+
// src/signal.ts
|
|
130
|
+
var UNSET = Symbol();
|
|
131
|
+
var isSignal = (value) => isState(value) || isComputed(value);
|
|
132
|
+
var toSignal = (value) => isSignal(value) ? value : isComputedCallback(value) ? computed(value) : state(value);
|
|
133
|
+
|
|
134
|
+
// src/computed.ts
|
|
135
|
+
var TYPE_COMPUTED = "Computed";
|
|
136
|
+
var computed = (fn) => {
|
|
137
|
+
const watchers = new Set;
|
|
138
|
+
let value = UNSET;
|
|
139
|
+
let error;
|
|
140
|
+
let controller;
|
|
141
|
+
let dirty = true;
|
|
142
|
+
let changed = false;
|
|
143
|
+
let computing = false;
|
|
144
|
+
const ok = (v) => {
|
|
145
|
+
if (!Object.is(v, value)) {
|
|
146
|
+
value = v;
|
|
147
|
+
changed = true;
|
|
148
|
+
}
|
|
149
|
+
error = undefined;
|
|
150
|
+
dirty = false;
|
|
151
|
+
};
|
|
152
|
+
const nil = () => {
|
|
153
|
+
changed = UNSET !== value;
|
|
154
|
+
value = UNSET;
|
|
155
|
+
error = undefined;
|
|
156
|
+
};
|
|
157
|
+
const err = (e) => {
|
|
158
|
+
const newError = toError(e);
|
|
159
|
+
changed = !error || newError.name !== error.name || newError.message !== error.message;
|
|
160
|
+
value = UNSET;
|
|
161
|
+
error = newError;
|
|
162
|
+
};
|
|
163
|
+
const settle = (settleFn) => (arg) => {
|
|
164
|
+
computing = false;
|
|
165
|
+
controller = undefined;
|
|
166
|
+
settleFn(arg);
|
|
167
|
+
if (changed)
|
|
168
|
+
notify(watchers);
|
|
169
|
+
};
|
|
170
|
+
const mark = watch(() => {
|
|
171
|
+
dirty = true;
|
|
172
|
+
controller?.abort("Aborted because source signal changed");
|
|
173
|
+
if (watchers.size)
|
|
174
|
+
notify(watchers);
|
|
175
|
+
else
|
|
176
|
+
mark.cleanup();
|
|
177
|
+
});
|
|
178
|
+
const compute = () => observe(() => {
|
|
179
|
+
if (computing)
|
|
180
|
+
throw new CircularDependencyError("computed");
|
|
181
|
+
changed = false;
|
|
182
|
+
if (isFunction(fn) && fn.constructor.name === "AsyncFunction") {
|
|
183
|
+
if (controller)
|
|
184
|
+
return value;
|
|
185
|
+
controller = new AbortController;
|
|
186
|
+
controller.signal.addEventListener("abort", () => {
|
|
187
|
+
computing = false;
|
|
188
|
+
controller = undefined;
|
|
189
|
+
compute();
|
|
190
|
+
}, {
|
|
191
|
+
once: true
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
let result;
|
|
195
|
+
computing = true;
|
|
196
|
+
try {
|
|
197
|
+
result = controller ? fn(controller.signal) : fn();
|
|
198
|
+
} catch (e) {
|
|
199
|
+
if (e instanceof DOMException && e.name === "AbortError")
|
|
200
|
+
nil();
|
|
201
|
+
else
|
|
202
|
+
err(e);
|
|
203
|
+
computing = false;
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
if (result instanceof Promise)
|
|
207
|
+
result.then(settle(ok), settle(err));
|
|
208
|
+
else if (result == null || UNSET === result)
|
|
209
|
+
nil();
|
|
210
|
+
else
|
|
211
|
+
ok(result);
|
|
212
|
+
computing = false;
|
|
213
|
+
}, mark);
|
|
214
|
+
const c = {
|
|
215
|
+
[Symbol.toStringTag]: TYPE_COMPUTED,
|
|
216
|
+
get: () => {
|
|
217
|
+
subscribe(watchers);
|
|
218
|
+
flush();
|
|
219
|
+
if (dirty)
|
|
220
|
+
compute();
|
|
221
|
+
if (error)
|
|
222
|
+
throw error;
|
|
223
|
+
return value;
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
return c;
|
|
227
|
+
};
|
|
228
|
+
var isComputed = (value) => isObjectOfType(value, TYPE_COMPUTED);
|
|
229
|
+
var isComputedCallback = (value) => isFunction(value) && value.length < 2;
|
|
230
|
+
// src/effect.ts
|
|
231
|
+
function effect(matcher) {
|
|
232
|
+
const {
|
|
233
|
+
signals,
|
|
234
|
+
ok,
|
|
235
|
+
err = (error) => {
|
|
236
|
+
console.error(error);
|
|
237
|
+
},
|
|
238
|
+
nil = () => {
|
|
239
|
+
}
|
|
240
|
+
} = isFunction(matcher) ? { signals: [], ok: matcher } : matcher;
|
|
241
|
+
let running = false;
|
|
242
|
+
const run = watch(() => observe(() => {
|
|
243
|
+
if (running)
|
|
244
|
+
throw new CircularDependencyError("effect");
|
|
245
|
+
running = true;
|
|
246
|
+
const errors = [];
|
|
247
|
+
let pending2 = false;
|
|
248
|
+
const values = signals.map((signal) => {
|
|
249
|
+
try {
|
|
250
|
+
const value = signal.get();
|
|
251
|
+
if (value === UNSET)
|
|
252
|
+
pending2 = true;
|
|
253
|
+
return value;
|
|
254
|
+
} catch (e) {
|
|
255
|
+
errors.push(toError(e));
|
|
256
|
+
return UNSET;
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
let cleanup;
|
|
260
|
+
try {
|
|
261
|
+
cleanup = pending2 ? nil() : errors.length ? err(...errors) : ok(...values);
|
|
262
|
+
} catch (e) {
|
|
263
|
+
cleanup = err(toError(e));
|
|
264
|
+
} finally {
|
|
265
|
+
if (isFunction(cleanup))
|
|
266
|
+
run.off(cleanup);
|
|
267
|
+
}
|
|
268
|
+
running = false;
|
|
269
|
+
}, run));
|
|
270
|
+
run();
|
|
271
|
+
return () => run.cleanup();
|
|
272
|
+
}
|
|
273
|
+
export {
|
|
274
|
+
watch,
|
|
275
|
+
toSignal,
|
|
276
|
+
subscribe,
|
|
277
|
+
state,
|
|
278
|
+
observe,
|
|
279
|
+
notify,
|
|
280
|
+
isState,
|
|
281
|
+
isSignal,
|
|
282
|
+
isFunction,
|
|
283
|
+
isComputedCallback,
|
|
284
|
+
isComputed,
|
|
285
|
+
flush,
|
|
286
|
+
enqueue,
|
|
287
|
+
effect,
|
|
288
|
+
computed,
|
|
289
|
+
batch,
|
|
290
|
+
UNSET,
|
|
291
|
+
TYPE_STATE,
|
|
292
|
+
TYPE_COMPUTED,
|
|
293
|
+
CircularDependencyError
|
|
294
|
+
};
|
package/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var V,M=new Set,U=0,k=new Map,D,f=()=>{D=void 0;let $=Array.from(k.values());k.clear();for(let B of $)B()},d=()=>{if(D)cancelAnimationFrame(D);D=requestAnimationFrame(f)};queueMicrotask(f);var Y=($)=>{let B=new Set,W=$;return W.off=(z)=>{B.add(z)},W.cleanup=()=>{for(let z of B)z();B.clear()},W},I=($)=>{if(V&&!$.has(V)){let B=V;$.add(B),V.off(()=>{$.delete(B)})}},F=($)=>{for(let B of $)if(U)M.add(B);else B()},N=()=>{while(M.size){let $=Array.from(M);M.clear();for(let B of $)B()}},h=($)=>{U++;try{$()}finally{N(),U--}},O=($,B)=>{let W=V;V=B;try{$()}finally{V=W}},v=($,B)=>new Promise((W,z)=>{k.set(B||Symbol(),()=>{try{W($())}catch(G){z(G)}}),d()});var j=($)=>typeof $==="function",P=($,B)=>Object.prototype.toString.call($)===`[object ${B}]`,C=($)=>$ instanceof Error?$:Error(String($));class R extends Error{constructor($){super(`Circular dependency in ${$} detected`);this.name="CircularDependencyError"}}var _="State",S=($)=>{let B=new Set,W=$,z={[Symbol.toStringTag]:_,get:()=>{return I(B),W},set:(G)=>{if(Object.is(W,G))return;if(W=G,F(B),K===W)B.clear()},update:(G)=>{z.set(G(W))}};return z},T=($)=>P($,_);var K=Symbol(),p=($)=>T($)||b($),o=($)=>p($)?$:g($)?E($):S($);var m="Computed",E=($)=>{let B=new Set,W=K,z,G,X=!0,L=!1,J=!1,x=(H)=>{if(!Object.is(H,W))W=H,L=!0;z=void 0,X=!1},q=()=>{L=K!==W,W=K,z=void 0},Z=(H)=>{let Q=C(H);L=!z||Q.name!==z.name||Q.message!==z.message,W=K,z=Q},A=(H)=>(Q)=>{if(J=!1,G=void 0,H(Q),L)F(B)},y=Y(()=>{if(X=!0,G?.abort("Aborted because source signal changed"),B.size)F(B);else y.cleanup()}),w=()=>O(()=>{if(J)throw new R("computed");if(L=!1,j($)&&$.constructor.name==="AsyncFunction"){if(G)return W;G=new AbortController,G.signal.addEventListener("abort",()=>{J=!1,G=void 0,w()},{once:!0})}let H;J=!0;try{H=G?$(G.signal):$()}catch(Q){if(Q instanceof DOMException&&Q.name==="AbortError")q();else Z(Q);J=!1;return}if(H instanceof Promise)H.then(A(x),A(Z));else if(H==null||K===H)q();else x(H);J=!1},y);return{[Symbol.toStringTag]:m,get:()=>{if(I(B),N(),X)w();if(z)throw z;return W}}},b=($)=>P($,m),g=($)=>j($)&&$.length<2;function s($){let{signals:B,ok:W,err:z=(J)=>{console.error(J)},nil:G=()=>{}}=j($)?{signals:[],ok:$}:$,X=!1,L=Y(()=>O(()=>{if(X)throw new R("effect");X=!0;let J=[],x=!1,q=B.map((A)=>{try{let y=A.get();if(y===K)x=!0;return y}catch(y){return J.push(C(y)),K}}),Z;try{Z=x?G():J.length?z(...J):W(...q)}catch(A){Z=z(C(A))}finally{if(j(Z))L.off(Z)}X=!1},L));return L(),()=>L.cleanup()}export{Y as watch,o as toSignal,I as subscribe,S as state,O as observe,F as notify,T as isState,p as isSignal,j as isFunction,g as isComputedCallback,b as isComputed,N as flush,v as enqueue,s as effect,E as computed,h as batch,K as UNSET,_ as TYPE_STATE,m as TYPE_COMPUTED,R as CircularDependencyError};
|
package/index.ts
CHANGED
|
@@ -1,36 +1,37 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @name Cause & Effect
|
|
3
|
-
* @version 0.14.
|
|
3
|
+
* @version 0.14.2
|
|
4
4
|
* @author Esther Brunner
|
|
5
5
|
*/
|
|
6
|
-
|
|
7
|
-
export {
|
|
8
|
-
type Signal,
|
|
9
|
-
type MaybeSignal,
|
|
10
|
-
type SignalValues,
|
|
11
|
-
UNSET,
|
|
12
|
-
isSignal,
|
|
13
|
-
isComputedCallback,
|
|
14
|
-
toSignal,
|
|
15
|
-
} from './src/signal'
|
|
16
|
-
export { type State, TYPE_STATE, state, isState } from './src/state'
|
|
6
|
+
|
|
17
7
|
export {
|
|
18
8
|
type Computed,
|
|
19
9
|
type ComputedCallback,
|
|
20
|
-
TYPE_COMPUTED,
|
|
21
10
|
computed,
|
|
22
11
|
isComputed,
|
|
12
|
+
TYPE_COMPUTED,
|
|
23
13
|
} from './src/computed'
|
|
24
14
|
export { type EffectMatcher, effect } from './src/effect'
|
|
25
15
|
export {
|
|
26
|
-
|
|
16
|
+
batch,
|
|
27
17
|
type Cleanup,
|
|
28
|
-
|
|
29
|
-
watch,
|
|
30
|
-
subscribe,
|
|
31
|
-
notify,
|
|
18
|
+
enqueue,
|
|
32
19
|
flush,
|
|
33
|
-
|
|
20
|
+
notify,
|
|
34
21
|
observe,
|
|
35
|
-
|
|
22
|
+
subscribe,
|
|
23
|
+
type Updater,
|
|
24
|
+
type Watcher,
|
|
25
|
+
watch,
|
|
36
26
|
} from './src/scheduler'
|
|
27
|
+
export {
|
|
28
|
+
isComputedCallback,
|
|
29
|
+
isSignal,
|
|
30
|
+
type MaybeSignal,
|
|
31
|
+
type Signal,
|
|
32
|
+
type SignalValues,
|
|
33
|
+
toSignal,
|
|
34
|
+
UNSET,
|
|
35
|
+
} from './src/signal'
|
|
36
|
+
export { isState, type State, state, TYPE_STATE } from './src/state'
|
|
37
|
+
export { CircularDependencyError, isFunction } from './src/util'
|
package/package.json
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zeix/cause-effect",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.2",
|
|
4
4
|
"author": "Esther Brunner",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "index.ts",
|
|
7
7
|
"devDependencies": {
|
|
8
|
+
"@biomejs/biome": "2.1.4",
|
|
8
9
|
"@types/bun": "latest",
|
|
9
|
-
"
|
|
10
|
-
"random": "^5.4.0",
|
|
11
|
-
"typescript-eslint": "^8.32.1"
|
|
10
|
+
"random": "^5.4.1"
|
|
12
11
|
},
|
|
13
12
|
"peerDependencies": {
|
|
14
13
|
"typescript": "^5.6.3"
|
|
@@ -25,9 +24,9 @@
|
|
|
25
24
|
"access": "public"
|
|
26
25
|
},
|
|
27
26
|
"scripts": {
|
|
28
|
-
"build": "bun build index.ts --outdir ./ --minify &&
|
|
27
|
+
"build": "bunx tsc && bun build index.ts --outdir ./ --minify && bun build index.ts --outfile index.dev.js",
|
|
29
28
|
"test": "bun test",
|
|
30
|
-
"lint": "bunx
|
|
29
|
+
"lint": "bunx biome lint --write"
|
|
31
30
|
},
|
|
32
31
|
"type": "module",
|
|
33
32
|
"types": "index.d.ts"
|
package/src/computed.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ type Computed<T extends {}> = {
|
|
|
3
3
|
get(): T;
|
|
4
4
|
};
|
|
5
5
|
type ComputedCallback<T extends {} & {
|
|
6
|
-
then?:
|
|
6
|
+
then?: undefined;
|
|
7
7
|
}> = ((abort: AbortSignal) => Promise<T>) | (() => T);
|
|
8
8
|
declare const TYPE_COMPUTED = "Computed";
|
|
9
9
|
/**
|
|
@@ -30,4 +30,4 @@ declare const isComputed: <T extends {}>(value: unknown) => value is Computed<T>
|
|
|
30
30
|
* @returns {boolean} - true if value is a callback or callbacks object, false otherwise
|
|
31
31
|
*/
|
|
32
32
|
declare const isComputedCallback: <T extends {}>(value: unknown) => value is ComputedCallback<T>;
|
|
33
|
-
export {
|
|
33
|
+
export { TYPE_COMPUTED, computed, isComputed, isComputedCallback, type Computed, type ComputedCallback, };
|
package/src/computed.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
+
import {
|
|
2
|
+
flush,
|
|
3
|
+
notify,
|
|
4
|
+
observe,
|
|
5
|
+
subscribe,
|
|
6
|
+
type Watcher,
|
|
7
|
+
watch,
|
|
8
|
+
} from './scheduler'
|
|
9
|
+
import { UNSET } from './signal'
|
|
1
10
|
import {
|
|
2
11
|
CircularDependencyError,
|
|
3
12
|
isFunction,
|
|
4
13
|
isObjectOfType,
|
|
5
14
|
toError,
|
|
6
15
|
} from './util'
|
|
7
|
-
import {
|
|
8
|
-
type Watcher,
|
|
9
|
-
watch,
|
|
10
|
-
subscribe,
|
|
11
|
-
notify,
|
|
12
|
-
flush,
|
|
13
|
-
observe,
|
|
14
|
-
} from './scheduler'
|
|
15
|
-
import { UNSET } from './signal'
|
|
16
16
|
|
|
17
17
|
/* === Types === */
|
|
18
18
|
|
|
@@ -20,7 +20,7 @@ type Computed<T extends {}> = {
|
|
|
20
20
|
[Symbol.toStringTag]: 'Computed'
|
|
21
21
|
get(): T
|
|
22
22
|
}
|
|
23
|
-
type ComputedCallback<T extends {} & { then?:
|
|
23
|
+
type ComputedCallback<T extends {} & { then?: undefined }> =
|
|
24
24
|
| ((abort: AbortSignal) => Promise<T>)
|
|
25
25
|
| (() => T)
|
|
26
26
|
|
|
@@ -49,7 +49,7 @@ const computed = <T extends {}>(fn: ComputedCallback<T>): Computed<T> => {
|
|
|
49
49
|
let computing = false
|
|
50
50
|
|
|
51
51
|
// Functions to update internal state
|
|
52
|
-
const ok = (v: T) => {
|
|
52
|
+
const ok = (v: T): undefined => {
|
|
53
53
|
if (!Object.is(v, value)) {
|
|
54
54
|
value = v
|
|
55
55
|
changed = true
|
|
@@ -57,12 +57,12 @@ const computed = <T extends {}>(fn: ComputedCallback<T>): Computed<T> => {
|
|
|
57
57
|
error = undefined
|
|
58
58
|
dirty = false
|
|
59
59
|
}
|
|
60
|
-
const nil = () => {
|
|
60
|
+
const nil = (): undefined => {
|
|
61
61
|
changed = UNSET !== value
|
|
62
62
|
value = UNSET
|
|
63
63
|
error = undefined
|
|
64
64
|
}
|
|
65
|
-
const err = (e: unknown) => {
|
|
65
|
+
const err = (e: unknown): undefined => {
|
|
66
66
|
const newError = toError(e)
|
|
67
67
|
changed =
|
|
68
68
|
!error ||
|
|
@@ -169,10 +169,10 @@ const isComputedCallback = /*#__PURE__*/ <T extends {}>(
|
|
|
169
169
|
/* === Exports === */
|
|
170
170
|
|
|
171
171
|
export {
|
|
172
|
-
type Computed,
|
|
173
|
-
type ComputedCallback,
|
|
174
172
|
TYPE_COMPUTED,
|
|
175
173
|
computed,
|
|
176
174
|
isComputed,
|
|
177
175
|
isComputedCallback,
|
|
176
|
+
type Computed,
|
|
177
|
+
type ComputedCallback,
|
|
178
178
|
}
|
package/src/effect.d.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { type Signal, type SignalValues } from './signal';
|
|
2
1
|
import { type Cleanup } from './scheduler';
|
|
3
|
-
type
|
|
2
|
+
import { type Signal, type SignalValues } from './signal';
|
|
3
|
+
type EffectMatcher<S extends Signal<unknown & {}>[]> = {
|
|
4
4
|
signals: S;
|
|
5
|
-
ok: (...values: SignalValues<S>) =>
|
|
6
|
-
err?: (...errors: Error[]) =>
|
|
7
|
-
nil?: () =>
|
|
5
|
+
ok: (...values: SignalValues<S>) => Cleanup | undefined;
|
|
6
|
+
err?: (...errors: Error[]) => Cleanup | undefined;
|
|
7
|
+
nil?: () => Cleanup | undefined;
|
|
8
8
|
};
|
|
9
9
|
/**
|
|
10
10
|
* Define what happens when a reactive state changes
|
|
11
11
|
*
|
|
12
12
|
* @since 0.1.0
|
|
13
|
-
* @param {EffectMatcher<S> | (() =>
|
|
13
|
+
* @param {EffectMatcher<S> | (() => Cleanup | undefined)} matcher - effect matcher or callback
|
|
14
14
|
* @returns {Cleanup} - cleanup function for the effect
|
|
15
15
|
*/
|
|
16
|
-
declare function effect<S extends Signal<{}>[]>(matcher: EffectMatcher<S> | (() =>
|
|
16
|
+
declare function effect<S extends Signal<unknown & {}>[]>(matcher: EffectMatcher<S> | (() => Cleanup | undefined)): Cleanup;
|
|
17
17
|
export { type EffectMatcher, effect };
|
package/src/effect.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
+
import { type Cleanup, observe, watch } from './scheduler'
|
|
1
2
|
import { type Signal, type SignalValues, UNSET } from './signal'
|
|
2
3
|
import { CircularDependencyError, isFunction, toError } from './util'
|
|
3
|
-
import { type Cleanup, watch, observe } from './scheduler'
|
|
4
4
|
|
|
5
5
|
/* === Types === */
|
|
6
6
|
|
|
7
|
-
type EffectMatcher<S extends Signal<{}>[]> = {
|
|
7
|
+
type EffectMatcher<S extends Signal<unknown & {}>[]> = {
|
|
8
8
|
signals: S
|
|
9
|
-
ok: (...values: SignalValues<S>) =>
|
|
10
|
-
err?: (...errors: Error[]) =>
|
|
11
|
-
nil?: () =>
|
|
9
|
+
ok: (...values: SignalValues<S>) => Cleanup | undefined
|
|
10
|
+
err?: (...errors: Error[]) => Cleanup | undefined
|
|
11
|
+
nil?: () => Cleanup | undefined
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
/* === Functions === */
|
|
@@ -17,17 +17,19 @@ type EffectMatcher<S extends Signal<{}>[]> = {
|
|
|
17
17
|
* Define what happens when a reactive state changes
|
|
18
18
|
*
|
|
19
19
|
* @since 0.1.0
|
|
20
|
-
* @param {EffectMatcher<S> | (() =>
|
|
20
|
+
* @param {EffectMatcher<S> | (() => Cleanup | undefined)} matcher - effect matcher or callback
|
|
21
21
|
* @returns {Cleanup} - cleanup function for the effect
|
|
22
22
|
*/
|
|
23
|
-
function effect<S extends Signal<{}>[]>(
|
|
24
|
-
matcher: EffectMatcher<S> | (() =>
|
|
23
|
+
function effect<S extends Signal<unknown & {}>[]>(
|
|
24
|
+
matcher: EffectMatcher<S> | (() => Cleanup | undefined),
|
|
25
25
|
): Cleanup {
|
|
26
26
|
const {
|
|
27
27
|
signals,
|
|
28
28
|
ok,
|
|
29
|
-
err =
|
|
30
|
-
|
|
29
|
+
err = (error: Error): undefined => {
|
|
30
|
+
console.error(error)
|
|
31
|
+
},
|
|
32
|
+
nil = (): undefined => {},
|
|
31
33
|
} = isFunction(matcher)
|
|
32
34
|
? { signals: [] as unknown as S, ok: matcher }
|
|
33
35
|
: matcher
|
|
@@ -53,7 +55,7 @@ function effect<S extends Signal<{}>[]>(
|
|
|
53
55
|
}) as SignalValues<S>
|
|
54
56
|
|
|
55
57
|
// Effectful part
|
|
56
|
-
let cleanup:
|
|
58
|
+
let cleanup: Cleanup | undefined
|
|
57
59
|
try {
|
|
58
60
|
cleanup = pending
|
|
59
61
|
? nil()
|
package/src/scheduler.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ type Watcher = {
|
|
|
4
4
|
off(cleanup: Cleanup): void;
|
|
5
5
|
cleanup(): void;
|
|
6
6
|
};
|
|
7
|
-
type Updater = <T>() => T | boolean |
|
|
7
|
+
type Updater = <T>() => T | boolean | undefined;
|
|
8
8
|
/**
|
|
9
9
|
* Create a watcher that can be used to observe changes to a signal
|
|
10
10
|
*
|
|
@@ -51,5 +51,5 @@ declare const observe: (run: () => void, watcher?: Watcher) => void;
|
|
|
51
51
|
* @param {Updater} fn - function to be executed on the next animation frame; can return updated value <T>, success <boolean> or void
|
|
52
52
|
* @param {symbol} dedupe - Symbol for deduplication; if not provided, a unique Symbol is created ensuring the update is always executed
|
|
53
53
|
*/
|
|
54
|
-
declare const enqueue: <T>(fn: Updater, dedupe?: symbol) => Promise<boolean |
|
|
54
|
+
declare const enqueue: <T>(fn: Updater, dedupe?: symbol) => Promise<boolean | T | undefined>;
|
|
55
55
|
export { type Cleanup, type Watcher, type Updater, subscribe, notify, flush, batch, watch, observe, enqueue, };
|
package/src/scheduler.ts
CHANGED
|
@@ -8,7 +8,7 @@ type Watcher = {
|
|
|
8
8
|
cleanup(): void
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
type Updater = <T>() => T | boolean |
|
|
11
|
+
type Updater = <T>() => T | boolean | undefined
|
|
12
12
|
|
|
13
13
|
/* === Internal === */
|
|
14
14
|
|
|
@@ -145,8 +145,8 @@ const observe = (run: () => void, watcher?: Watcher): void => {
|
|
|
145
145
|
* @param {symbol} dedupe - Symbol for deduplication; if not provided, a unique Symbol is created ensuring the update is always executed
|
|
146
146
|
*/
|
|
147
147
|
const enqueue = <T>(fn: Updater, dedupe?: symbol) =>
|
|
148
|
-
new Promise<T | boolean |
|
|
149
|
-
updateMap.set(dedupe || Symbol(), () => {
|
|
148
|
+
new Promise<T | boolean | undefined>((resolve, reject) => {
|
|
149
|
+
updateMap.set(dedupe || Symbol(), (): undefined => {
|
|
150
150
|
try {
|
|
151
151
|
resolve(fn())
|
|
152
152
|
} catch (error) {
|
package/src/signal.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ type Signal<T extends {}> = {
|
|
|
3
3
|
get(): T;
|
|
4
4
|
};
|
|
5
5
|
type MaybeSignal<T extends {}> = T | Signal<T> | ComputedCallback<T>;
|
|
6
|
-
type SignalValues<S extends Signal<{}>[]> = {
|
|
6
|
+
type SignalValues<S extends Signal<unknown & {}>[]> = {
|
|
7
7
|
[K in keyof S]: S[K] extends Signal<infer T> ? T : never;
|
|
8
8
|
};
|
|
9
9
|
declare const UNSET: any;
|