@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # Cause & Effect
2
2
 
3
- Version 0.14.1
3
+ Version 0.14.2
4
4
 
5
5
  **Cause & Effect** is a lightweight, reactive state management library for JavaScript applications. It uses fine-grained reactivity with signals to create predictable and efficient data flow in your app.
6
6
 
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.1
3
+ * @version 0.14.2
4
4
  * @author Esther Brunner
5
5
  */
6
- export { isFunction, CircularDependencyError } from './src/util';
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 { type Watcher, type Cleanup, type Updater, watch, subscribe, notify, flush, batch, observe, enqueue, } from './src/scheduler';
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 j=($)=>typeof $==="function",M=($,B)=>Object.prototype.toString.call($)===`[object ${B}]`,Y=($)=>$ instanceof Error?$:Error(String($));class F extends Error{constructor($){super(`Circular dependency in ${$} detected`);return this}}var y,N=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 I=($)=>{let B=new Set,W=$;return W.off=(z)=>{B.add(z)},W.cleanup=()=>{for(let z of B)z();B.clear()},W},O=($)=>{if(y&&!$.has(y)){let B=y;$.add(B),y.off(()=>{$.delete(B)})}},R=($)=>{for(let B of $)if(U)N.add(B);else B()},P=()=>{while(N.size){let $=Array.from(N);N.clear();for(let B of $)B()}},h=($)=>{U++;try{$()}finally{P(),U--}},q=($,B)=>{let W=y;y=B;try{$()}finally{y=W}},v=($,B)=>new Promise((W,z)=>{k.set(B||Symbol(),()=>{try{W($())}catch(G){z(G)}}),d()});var _="State",S=($)=>{let B=new Set,W=$,z={[Symbol.toStringTag]:_,get:()=>{return O(B),W},set:(G)=>{if(Object.is(W,G))return;if(W=G,R(B),J===W)B.clear()},update:(G)=>{z.set(G(W))}};return z},T=($)=>M($,_);var b="Computed",E=($)=>{let B=new Set,W=J,z,G,X=!0,K=!1,L=!1,x=(H)=>{if(!Object.is(H,W))W=H,K=!0;z=void 0,X=!1},C=()=>{K=J!==W,W=J,z=void 0},Z=(H)=>{let Q=Y(H);K=!z||Q.name!==z.name||Q.message!==z.message,W=J,z=Q},A=(H)=>(Q)=>{if(L=!1,G=void 0,H(Q),K)R(B)},V=I(()=>{if(X=!0,G?.abort("Aborted because source signal changed"),B.size)R(B);else V.cleanup()}),w=()=>q(()=>{if(L)throw new F("computed");if(K=!1,j($)&&$.constructor.name==="AsyncFunction"){if(G)return W;G=new AbortController,G.signal.addEventListener("abort",()=>{L=!1,G=void 0,w()},{once:!0})}let H;L=!0;try{H=G?$(G.signal):$()}catch(Q){if(Q instanceof DOMException&&Q.name==="AbortError")C();else Z(Q);L=!1;return}if(H instanceof Promise)H.then(A(x),A(Z));else if(H==null||J===H)C();else x(H);L=!1},V);return{[Symbol.toStringTag]:b,get:()=>{if(O(B),P(),X)w();if(z)throw z;return W}}},g=($)=>M($,b),m=($)=>j($)&&$.length<2;var J=Symbol(),p=($)=>T($)||g($),o=($)=>p($)?$:m($)?E($):S($);function s($){let{signals:B,ok:W,err:z=console.error,nil:G=()=>{}}=j($)?{signals:[],ok:$}:$,X=!1,K=I(()=>q(()=>{if(X)throw new F("effect");X=!0;let L=[],x=!1,C=B.map((A)=>{try{let V=A.get();if(V===J)x=!0;return V}catch(V){return L.push(Y(V)),J}}),Z=void 0;try{Z=x?G():L.length?z(...L):W(...C)}catch(A){Z=z(Y(A))}finally{if(j(Z))K.off(Z)}X=!1},K));return K(),()=>K.cleanup()}export{I as watch,o as toSignal,O as subscribe,S as state,q as observe,R as notify,T as isState,p as isSignal,j as isFunction,m as isComputedCallback,g as isComputed,P as flush,v as enqueue,s as effect,E as computed,h as batch,J as UNSET,_ as TYPE_STATE,b as TYPE_COMPUTED,F as CircularDependencyError};
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.1
3
+ * @version 0.14.2
4
4
  * @author Esther Brunner
5
5
  */
6
- export { isFunction, CircularDependencyError } from './src/util'
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
- type Watcher,
16
+ batch,
27
17
  type Cleanup,
28
- type Updater,
29
- watch,
30
- subscribe,
31
- notify,
18
+ enqueue,
32
19
  flush,
33
- batch,
20
+ notify,
34
21
  observe,
35
- enqueue,
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.1",
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
- "eslint": "^9.27.0",
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 && bunx tsc",
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 eslint src/"
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?: void;
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 { type Computed, type ComputedCallback, TYPE_COMPUTED, computed, isComputed, isComputedCallback, };
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?: void }> =
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 EffectMatcher<S extends Signal<{}>[]> = {
2
+ import { type Signal, type SignalValues } from './signal';
3
+ type EffectMatcher<S extends Signal<unknown & {}>[]> = {
4
4
  signals: S;
5
- ok: (...values: SignalValues<S>) => void | Cleanup;
6
- err?: (...errors: Error[]) => void | Cleanup;
7
- nil?: () => void | Cleanup;
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> | (() => void | Cleanup)} matcher - effect matcher or callback
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> | (() => void | Cleanup)): Cleanup;
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>) => void | Cleanup
10
- err?: (...errors: Error[]) => void | Cleanup
11
- nil?: () => void | Cleanup
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> | (() => void | Cleanup)} matcher - effect matcher or callback
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> | (() => void | Cleanup),
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 = console.error,
30
- nil = () => {},
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: void | Cleanup = undefined
58
+ let cleanup: Cleanup | undefined
57
59
  try {
58
60
  cleanup = pending
59
61
  ? nil()
@@ -4,7 +4,7 @@ type Watcher = {
4
4
  off(cleanup: Cleanup): void;
5
5
  cleanup(): void;
6
6
  };
7
- type Updater = <T>() => T | boolean | void;
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 | void | T>;
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 | void
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 | void>((resolve, reject) => {
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;