@zeix/cause-effect 0.13.0 → 0.13.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.13.0
3
+ Version 0.13.2
4
4
 
5
5
  **Cause & Effect** is a lightweight, reactive state management library for JavaScript applications. It uses the concept of signals to create a predictable and efficient data flow in your app.
6
6
 
@@ -301,4 +301,4 @@ Feel free to contribute, report issues, or suggest improvements.
301
301
 
302
302
  Licence: [MIT](LICENCE.md)
303
303
 
304
- (c) 2025 [Zeix AG](https://zeix.com)
304
+ (c) 2025 [Zeix AG](https://zeix.com)
@@ -0,0 +1,35 @@
1
+ import globals from 'globals'
2
+ import pluginJs from '@eslint/js'
3
+ import tseslint from 'typescript-eslint'
4
+
5
+ /** @type {import('eslint').Linter.Config[]} */
6
+ export default [
7
+ {
8
+ ignores: ['index.js', '**/*.min.js'],
9
+ },
10
+ {
11
+ files: ['**/*.{js,mjs,cjs,ts}'],
12
+ },
13
+ { languageOptions: { globals: globals.browser } },
14
+ pluginJs.configs.recommended,
15
+ ...tseslint.configs.recommended,
16
+ {
17
+ rules: {
18
+ // we know what we're doing ;-)
19
+ '@typescript-eslint/no-empty-object-type': 'off',
20
+ '@typescript-eslint/no-explicit-any': 'off',
21
+ '@typescript-eslint/no-unused-vars': [
22
+ 'error',
23
+ {
24
+ args: 'all',
25
+ argsIgnorePattern: '^_',
26
+ caughtErrors: 'all',
27
+ caughtErrorsIgnorePattern: '^_',
28
+ destructuredArrayIgnorePattern: '^_',
29
+ varsIgnorePattern: '^_',
30
+ ignoreRestSiblings: true,
31
+ },
32
+ ],
33
+ },
34
+ },
35
+ ]
package/index.d.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  /**
2
2
  * @name Cause & Effect
3
- * @version 0.13.0
3
+ * @version 0.13.2
4
4
  * @author Esther Brunner
5
5
  */
6
- export { CircularDependencyError } from './lib/util';
7
- export { type Signal, type MaybeSignal, UNSET, isSignal, isComputedCallback, toSignal } from './lib/signal';
8
- export { type State, state, isState } from './lib/state';
9
- export { type Computed, type ComputedMatcher, computed, isComputed } from './lib/computed';
10
- export { type EffectMatcher, type TapMatcher, effect } from './lib/effect';
11
- export { type EnqueueDedupe, batch, watch, enqueue } from './lib/scheduler';
6
+ export { CircularDependencyError } from './src/util';
7
+ export { type Signal, type MaybeSignal, type ComputedCallback, UNSET, isSignal, isComputedCallback, toSignal, } from './src/signal';
8
+ export { type State, state, isState } from './src/state';
9
+ export { type Computed, type ComputedMatcher, computed, isComputed, } from './src/computed';
10
+ export { type EffectMatcher, type TapMatcher, effect } from './src/effect';
11
+ export { type EnqueueDedupe, batch, watch, enqueue } from './src/scheduler';
package/index.js CHANGED
@@ -1 +1 @@
1
- var X=(x)=>typeof x==="function",d=(x)=>X(x)&&x.constructor.name==="AsyncFunction",P=(x,y)=>Object.prototype.toString.call(x)===`[object ${y}]`,c=(x)=>x instanceof Error,I=(x)=>x instanceof DOMException&&x.name==="AbortError",m=(x)=>x instanceof Promise,j=(x)=>c(x)?x:Error(String(x));class V extends Error{constructor(x){super(`Circular dependency in ${x} detected`);return this}}var A,R=new Set,U=0,_=new Map,D,v=()=>{D=void 0;let x=Array.from(_.values());_.clear();for(let y of x)y()},t=()=>{if(D)cancelAnimationFrame(D);D=requestAnimationFrame(v)};queueMicrotask(v);var N=(x)=>{if(A&&!x.has(A)){let y=A;x.add(y),A.cleanups.add(()=>{x.delete(y)})}},F=(x)=>{for(let y of x)if(U)R.add(y);else y()},k=()=>{while(R.size){let x=Array.from(R);R.clear();for(let y of x)y()}},a=(x)=>{U++;try{x()}finally{k(),U--}},M=(x,y)=>{let z=A;A=y;try{x()}finally{A=z}},r=(x,y)=>new Promise((z,J)=>{let B=()=>{try{z(x())}catch(K){J(K)}};if(y)_.set(y,B);t()});function Y(x){let{signals:y,ok:z,err:J=console.error,nil:B=()=>{}}=X(x)?{signals:[],ok:x}:x,K=!1,L=()=>M(()=>{if(K)throw new V("effect");K=!0;let G=void 0;try{G=S({signals:y,ok:z,err:J,nil:B})}catch(Q){J(j(Q))}if(X(G))L.cleanups.add(G);K=!1},L);return L.cleanups=new Set,L(),()=>{L.cleanups.forEach((G)=>G()),L.cleanups.clear()}}var o="Computed",e=(x,y)=>{if(!y)return!1;return x.name===y.name&&x.message===y.message},O=(x)=>{let y=new Set,z=X(x)?void 0:{nil:()=>Z,err:(...$)=>{if($.length>1)throw new AggregateError($);else throw $[0]},...x},J=z?z.ok:x,B=Z,K,L=!0,G=!1,Q=!1,H,W=($)=>{if(!Object.is($,B))B=$,L=!1,K=void 0,G=!0},g=()=>{G=Z!==B,B=Z,K=void 0},f=($)=>{let C=j($);G=!e(C,K),B=Z,K=C},n=($)=>{if(Q=!1,H=void 0,W($),G)F(y)},u=($)=>{if(Q=!1,H=void 0,f($),G)F(y)},l=()=>{Q=!1,H=void 0,p()},q=()=>{if(L=!0,H?.abort("Aborted because source signal changed"),y.size){if(G)F(y)}else q.cleanups.forEach(($)=>$()),q.cleanups.clear()};q.cleanups=new Set;let p=()=>M(()=>{if(Q)throw new V("computed");if(G=!1,d(J)){if(H)return B;if(H=new AbortController,z)z.abort=z.abort instanceof AbortSignal?AbortSignal.any([z.abort,H.signal]):H.signal;H.signal.addEventListener("abort",l,{once:!0})}let $;Q=!0;try{$=z&&z.signals.length?S(z):J(H?.signal)}catch(C){I(C)?g():f(C),Q=!1;return}if(m($))$.then(n,u);else if($==null||Z===$)g();else W($);Q=!1},q),T={[Symbol.toStringTag]:o,get:()=>{if(N(y),k(),L)p();if(K)throw K;return B},map:($)=>O({signals:[T],ok:$}),tap:($)=>Y({signals:[T],...X($)?{ok:$}:$})};return T},b=(x)=>P(x,o);var i="State",E=(x)=>{let y=new Set,z=x,J={[Symbol.toStringTag]:i,get:()=>{return N(y),z},set:(B)=>{if(Object.is(z,B))return;if(z=B,F(y),Z===z)y.clear()},update:(B)=>{J.set(B(z))},map:(B)=>O({signals:[J],ok:B}),tap:(B)=>Y({signals:[J],...X(B)?{ok:B}:B})};return J},w=(x)=>P(x,i);var Z=Symbol(),h=(x)=>w(x)||b(x),s=(x)=>X(x)&&x.length<2,xx=(x)=>h(x)?x:s(x)?O(x):E(x),S=(x)=>{let{signals:y,abort:z,ok:J,err:B,nil:K}=x,L=[],G=!1,Q=y.map((H)=>{try{let W=H.get();if(W===Z)G=!0;return W}catch(W){if(I(W))throw W;L.push(j(W))}});try{return G?K(z):L.length?B(...L):J(...Q)}catch(H){if(I(H))throw H;let W=j(H);return B(W)}};export{M as watch,xx as toSignal,E as state,w as isState,h as isSignal,s as isComputedCallback,b as isComputed,r as enqueue,Y as effect,O as computed,a as batch,Z as UNSET,V as CircularDependencyError};
1
+ var X=(x)=>typeof x==="function",d=(x)=>X(x)&&x.constructor.name==="AsyncFunction",P=(x,y)=>Object.prototype.toString.call(x)===`[object ${y}]`,c=(x)=>x instanceof Error,I=(x)=>x instanceof DOMException&&x.name==="AbortError",m=(x)=>x instanceof Promise,C=(x)=>c(x)?x:Error(String(x));class A extends Error{constructor(x){super(`Circular dependency in ${x} detected`);return this}}var j,R=new Set,U=0,_=new Map,D,v=()=>{D=void 0;let x=Array.from(_.values());_.clear();for(let y of x)y()},t=()=>{if(D)cancelAnimationFrame(D);D=requestAnimationFrame(v)};queueMicrotask(v);var N=(x)=>{if(j&&!x.has(j)){let y=j;x.add(y),j.cleanups.add(()=>{x.delete(y)})}},V=(x)=>{for(let y of x)if(U)R.add(y);else y()},k=()=>{while(R.size){let x=Array.from(R);R.clear();for(let y of x)y()}},a=(x)=>{U++;try{x()}finally{k(),U--}},M=(x,y)=>{let z=j;j=y;try{x()}finally{j=z}},r=(x,y)=>new Promise((z,J)=>{_.set(y,()=>{try{z(x())}catch(B){J(B)}}),t()});function Y(x){let{signals:y,ok:z,err:J=console.error,nil:B=()=>{}}=X(x)?{signals:[],ok:x}:x,L=!1,K=()=>M(()=>{if(L)throw new A("effect");L=!0;let H=void 0;try{H=S({signals:y,ok:z,err:J,nil:B})}catch(Q){J(C(Q))}if(X(H))K.cleanups.add(H);L=!1},K);return K.cleanups=new Set,K(),()=>{K.cleanups.forEach((H)=>H()),K.cleanups.clear()}}var o="Computed",e=(x,y)=>{if(!y)return!1;return x.name===y.name&&x.message===y.message},F=(x)=>{let y=new Set,z=X(x)?void 0:{nil:()=>Z,err:(...$)=>{if($.length>1)throw new AggregateError($);else throw $[0]},...x},J=z?z.ok:x,B=Z,L,K=!0,H=!1,Q=!1,G,W=($)=>{if(!Object.is($,B))B=$,K=!1,L=void 0,H=!0},g=()=>{H=Z!==B,B=Z,L=void 0},p=($)=>{let O=C($);H=!e(O,L),B=Z,L=O},n=($)=>{if(Q=!1,G=void 0,W($),H)V(y)},u=($)=>{if(Q=!1,G=void 0,p($),H)V(y)},l=()=>{Q=!1,G=void 0,f()},q=()=>{if(K=!0,G?.abort("Aborted because source signal changed"),y.size)V(y);else q.cleanups.forEach(($)=>$()),q.cleanups.clear()};q.cleanups=new Set;let f=()=>M(()=>{if(Q)throw new A("computed");if(H=!1,d(J)){if(G)return B;if(G=new AbortController,z)z.abort=z.abort instanceof AbortSignal?AbortSignal.any([z.abort,G.signal]):G.signal;G.signal.addEventListener("abort",l,{once:!0})}let $;Q=!0;try{$=z&&z.signals.length?S(z):J(G?.signal)}catch(O){if(I(O))g();else p(O);Q=!1;return}if(m($))$.then(n,u);else if($==null||Z===$)g();else W($);Q=!1},q),T={[Symbol.toStringTag]:o,get:()=>{if(N(y),k(),K)f();if(L)throw L;return B},map:($)=>F({signals:[T],ok:$}),tap:($)=>Y({signals:[T],...X($)?{ok:$}:$})};return T},b=(x)=>P(x,o);var i="State",E=(x)=>{let y=new Set,z=x,J={[Symbol.toStringTag]:i,get:()=>{return N(y),z},set:(B)=>{if(Object.is(z,B))return;if(z=B,V(y),Z===z)y.clear()},update:(B)=>{J.set(B(z))},map:(B)=>F({signals:[J],ok:B}),tap:(B)=>Y({signals:[J],...X(B)?{ok:B}:B})};return J},w=(x)=>P(x,i);var Z=Symbol(),h=(x)=>w(x)||b(x),s=(x)=>X(x)&&x.length<2,xx=(x)=>h(x)?x:s(x)?F(x):E(x),S=(x)=>{let{signals:y,abort:z,ok:J,err:B,nil:L}=x,K=[],H=!1,Q=y.map((G)=>{try{let W=G.get();if(W===Z)H=!0;return W}catch(W){if(I(W))throw W;K.push(C(W))}});try{return H?L(z):K.length?B(...K):J(...Q)}catch(G){if(I(G))throw G;let W=C(G);return B(W)}};export{M as watch,xx as toSignal,E as state,w as isState,h as isSignal,s as isComputedCallback,b as isComputed,r as enqueue,Y as effect,F as computed,a as batch,Z as UNSET,A as CircularDependencyError};
package/index.ts CHANGED
@@ -1,15 +1,25 @@
1
1
  /**
2
2
  * @name Cause & Effect
3
- * @version 0.13.0
3
+ * @version 0.13.2
4
4
  * @author Esther Brunner
5
5
  */
6
- export { CircularDependencyError } from './lib/util'
6
+ export { CircularDependencyError } from './src/util'
7
7
  export {
8
- type Signal, type MaybeSignal,
9
- UNSET, isSignal, isComputedCallback, toSignal
10
- } from './lib/signal'
8
+ type Signal,
9
+ type MaybeSignal,
10
+ type ComputedCallback,
11
+ UNSET,
12
+ isSignal,
13
+ isComputedCallback,
14
+ toSignal,
15
+ } from './src/signal'
11
16
 
12
- export { type State, state, isState } from './lib/state'
13
- export { type Computed, type ComputedMatcher, computed, isComputed } from './lib/computed'
14
- export { type EffectMatcher, type TapMatcher, effect } from './lib/effect'
15
- export { type EnqueueDedupe, batch, watch, enqueue } from './lib/scheduler'
17
+ export { type State, state, isState } from './src/state'
18
+ export {
19
+ type Computed,
20
+ type ComputedMatcher,
21
+ computed,
22
+ isComputed,
23
+ } from './src/computed'
24
+ export { type EffectMatcher, type TapMatcher, effect } from './src/effect'
25
+ export { type EnqueueDedupe, batch, watch, enqueue } from './src/scheduler'
package/package.json CHANGED
@@ -1,31 +1,34 @@
1
1
  {
2
- "name": "@zeix/cause-effect",
3
- "version": "0.13.0",
4
- "author": "Esther Brunner",
5
- "main": "index.js",
6
- "module": "index.ts",
7
- "devDependencies": {
8
- "@types/bun": "latest",
9
- "random": "^5.3.0"
10
- },
11
- "peerDependencies": {
12
- "typescript": "^5.6.3"
13
- },
14
- "description": "Cause & Effect - reactive state management with signals.",
15
- "license": "MIT",
16
- "keywords": [
17
- "Cause & Effect",
18
- "Reactivity",
19
- "Signals",
20
- "Effects"
21
- ],
22
- "publishConfig": {
23
- "access": "public"
24
- },
25
- "scripts": {
26
- "build": "bun build index.ts --outdir ./ --minify && bunx tsc",
27
- "test": "bun test"
28
- },
29
- "type": "module",
30
- "types": "index.d.ts"
2
+ "name": "@zeix/cause-effect",
3
+ "version": "0.13.2",
4
+ "author": "Esther Brunner",
5
+ "main": "index.js",
6
+ "module": "index.ts",
7
+ "devDependencies": {
8
+ "@types/bun": "latest",
9
+ "eslint": "^9.27.0",
10
+ "random": "^5.4.0",
11
+ "typescript-eslint": "^8.32.1"
12
+ },
13
+ "peerDependencies": {
14
+ "typescript": "^5.6.3"
15
+ },
16
+ "description": "Cause & Effect - reactive state management with signals.",
17
+ "license": "MIT",
18
+ "keywords": [
19
+ "Cause & Effect",
20
+ "Reactivity",
21
+ "Signals",
22
+ "Effects"
23
+ ],
24
+ "publishConfig": {
25
+ "access": "public"
26
+ },
27
+ "scripts": {
28
+ "build": "bun build index.ts --outdir ./ --minify && bunx tsc",
29
+ "test": "bun test",
30
+ "lint": "bunx eslint src/"
31
+ },
32
+ "type": "module",
33
+ "types": "index.d.ts"
31
34
  }
@@ -1,4 +1,4 @@
1
- import { type Signal } from './signal';
1
+ import { type Signal, type ComputedCallback } from './signal';
2
2
  import { type TapMatcher } from './effect';
3
3
  export type ComputedMatcher<S extends Signal<{}>[], R extends {}> = {
4
4
  signals: S;
@@ -19,10 +19,10 @@ export type Computed<T extends {}> = {
19
19
  * Create a derived signal from existing signals
20
20
  *
21
21
  * @since 0.9.0
22
- * @param {ComputedMatcher<S, T> | ((abort?: AbortSignal) => T | Promise<T>)} matcher - computed matcher or callback
22
+ * @param {ComputedMatcher<S, T> | ComputedCallback<T>} matcher - computed matcher or callback
23
23
  * @returns {Computed<T>} - Computed signal
24
24
  */
25
- export declare const computed: <T extends {}, S extends Signal<{}>[] = []>(matcher: ComputedMatcher<S, T> | ((abort?: AbortSignal) => T | Promise<T>)) => Computed<T>;
25
+ export declare const computed: <T extends {}, S extends Signal<{}>[] = []>(matcher: ComputedMatcher<S, T> | ComputedCallback<T>) => Computed<T>;
26
26
  /**
27
27
  * Check if a value is a computed state
28
28
  *
@@ -1,24 +1,34 @@
1
- import { type Signal, match, UNSET } from './signal'
2
- import { CircularDependencyError, isAbortError, isAsyncFunction, isFunction, isObjectOfType, isPromise, toError } from './util'
1
+ import { type Signal, type ComputedCallback, match, UNSET } from './signal'
2
+ import {
3
+ CircularDependencyError,
4
+ isAbortError,
5
+ isAsyncFunction,
6
+ isFunction,
7
+ isObjectOfType,
8
+ isPromise,
9
+ toError,
10
+ } from './util'
3
11
  import { type Watcher, flush, notify, subscribe, watch } from './scheduler'
4
12
  import { type TapMatcher, type EffectMatcher, effect } from './effect'
5
13
 
6
14
  /* === Types === */
7
15
 
8
16
  export type ComputedMatcher<S extends Signal<{}>[], R extends {}> = {
9
- signals: S,
17
+ signals: S
10
18
  abort?: AbortSignal
11
- ok: (...values: {
19
+ ok: (
20
+ ...values: {
12
21
  [K in keyof S]: S[K] extends Signal<infer T> ? T : never
13
- }) => R | Promise<R>
22
+ }
23
+ ) => R | Promise<R>
14
24
  err?: (...errors: Error[]) => R | Promise<R>
15
25
  nil?: () => R | Promise<R>
16
26
  }
17
27
 
18
28
  export type Computed<T extends {}> = {
19
- [Symbol.toStringTag]: 'Computed'
20
- get(): T
21
- map<U extends {}>(fn: (v: T) => U | Promise<U>): Computed<U>
29
+ [Symbol.toStringTag]: 'Computed'
30
+ get(): T
31
+ map<U extends {}>(fn: (v: T) => U | Promise<U>): Computed<U>
22
32
  tap(matcher: TapMatcher<T> | ((v: T) => void | (() => void))): () => void
23
33
  }
24
34
 
@@ -30,34 +40,36 @@ const TYPE_COMPUTED = 'Computed'
30
40
 
31
41
  const isEquivalentError = /*#__PURE__*/ (
32
42
  error1: Error,
33
- error2: Error | undefined
43
+ error2: Error | undefined,
34
44
  ): boolean => {
35
- if (!error2) return false
36
- return error1.name === error2.name && error1.message === error2.message
45
+ if (!error2) return false
46
+ return error1.name === error2.name && error1.message === error2.message
37
47
  }
38
48
 
39
49
  /* === Computed Factory === */
40
50
 
41
51
  /**
42
52
  * Create a derived signal from existing signals
43
- *
53
+ *
44
54
  * @since 0.9.0
45
- * @param {ComputedMatcher<S, T> | ((abort?: AbortSignal) => T | Promise<T>)} matcher - computed matcher or callback
55
+ * @param {ComputedMatcher<S, T> | ComputedCallback<T>} matcher - computed matcher or callback
46
56
  * @returns {Computed<T>} - Computed signal
47
57
  */
48
58
  export const computed = <T extends {}, S extends Signal<{}>[] = []>(
49
- matcher: ComputedMatcher<S, T> | ((abort?: AbortSignal) => T | Promise<T>)
59
+ matcher: ComputedMatcher<S, T> | ComputedCallback<T>,
50
60
  ): Computed<T> => {
51
61
  const watchers: Set<Watcher> = new Set()
52
- const m = isFunction(matcher) ? undefined : {
53
- nil: () => UNSET,
54
- err: (...errors: Error[]) => {
55
- if (errors.length > 1) throw new AggregateError(errors)
56
- else throw errors[0]
57
- },
58
- ...matcher,
59
- } as Required<ComputedMatcher<S, T>>
60
- const fn = (m ? m.ok : matcher) as (abort?: AbortSignal) => T | Promise<T>
62
+ const m = isFunction(matcher)
63
+ ? undefined
64
+ : ({
65
+ nil: () => UNSET,
66
+ err: (...errors: Error[]) => {
67
+ if (errors.length > 1) throw new AggregateError(errors)
68
+ else throw errors[0]
69
+ },
70
+ ...matcher,
71
+ } as Required<ComputedMatcher<S, T>>)
72
+ const fn = (m ? m.ok : matcher) as ComputedCallback<T>
61
73
 
62
74
  // Internal state
63
75
  let value: T = UNSET
@@ -77,7 +89,7 @@ export const computed = <T extends {}, S extends Signal<{}>[] = []>(
77
89
  }
78
90
  }
79
91
  const nil = () => {
80
- changed = (UNSET !== value)
92
+ changed = UNSET !== value
81
93
  value = UNSET
82
94
  error = undefined
83
95
  }
@@ -100,17 +112,17 @@ export const computed = <T extends {}, S extends Signal<{}>[] = []>(
100
112
  if (changed) notify(watchers)
101
113
  }
102
114
  const abort = () => {
103
- computing = false
104
- controller = undefined
115
+ computing = false
116
+ controller = undefined
105
117
  compute() // retry
106
- }
118
+ }
107
119
 
108
120
  // Called when notified from sources (push)
109
121
  const mark = (() => {
110
122
  dirty = true
111
123
  controller?.abort('Aborted because source signal changed')
112
124
  if (watchers.size) {
113
- if (changed) notify(watchers)
125
+ notify(watchers)
114
126
  } else {
115
127
  mark.cleanups.forEach((fn: () => void) => fn())
116
128
  mark.cleanups.clear()
@@ -119,40 +131,47 @@ export const computed = <T extends {}, S extends Signal<{}>[] = []>(
119
131
  mark.cleanups = new Set()
120
132
 
121
133
  // Called when requested by dependencies (pull)
122
- const compute = () => watch(() => {
123
- if (computing) throw new CircularDependencyError('computed')
124
- changed = false
125
- if (isAsyncFunction(fn)) {
126
- if (controller) return value // return current value until promise resolves
127
- controller = new AbortController()
128
- if (m) m.abort = m.abort instanceof AbortSignal
129
- ? AbortSignal.any([m.abort, controller.signal])
130
- : controller.signal
131
- controller.signal.addEventListener('abort', abort, { once: true })
132
- }
133
- let result: T | Promise<T>
134
- computing = true
135
- try {
136
- result = m && m.signals.length
137
- ? match<S, T>(m)
138
- : fn(controller?.signal)
139
- } catch (e) {
140
- isAbortError(e) ? nil() : err(e)
134
+ const compute = () =>
135
+ watch(() => {
136
+ if (computing) throw new CircularDependencyError('computed')
137
+ changed = false
138
+ if (isAsyncFunction(fn)) {
139
+ if (controller) return value // return current value until promise resolves
140
+ controller = new AbortController()
141
+ if (m)
142
+ m.abort =
143
+ m.abort instanceof AbortSignal
144
+ ? AbortSignal.any([m.abort, controller.signal])
145
+ : controller.signal
146
+ controller.signal.addEventListener('abort', abort, {
147
+ once: true,
148
+ })
149
+ }
150
+ let result: T | Promise<T>
151
+ computing = true
152
+ try {
153
+ result =
154
+ m && m.signals.length
155
+ ? match<S, T>(m)
156
+ : fn(controller?.signal)
157
+ } catch (e) {
158
+ if (isAbortError(e)) nil()
159
+ else err(e)
160
+ computing = false
161
+ return
162
+ }
163
+ if (isPromise(result)) result.then(resolve, reject)
164
+ else if (null == result || UNSET === result) nil()
165
+ else ok(result)
141
166
  computing = false
142
- return
143
- }
144
- if (isPromise(result)) result.then(resolve, reject)
145
- else if (null == result || UNSET === result) nil()
146
- else ok(result)
147
- computing = false
148
- }, mark)
167
+ }, mark)
149
168
 
150
169
  const c: Computed<T> = {
151
170
  [Symbol.toStringTag]: TYPE_COMPUTED,
152
171
 
153
172
  /**
154
173
  * Get the current value of the computed
155
- *
174
+ *
156
175
  * @since 0.9.0
157
176
  * @returns {T} - current value of the computed
158
177
  */
@@ -166,7 +185,7 @@ export const computed = <T extends {}, S extends Signal<{}>[] = []>(
166
185
 
167
186
  /**
168
187
  * Create a computed signal from the current computed signal
169
- *
188
+ *
170
189
  * @since 0.9.0
171
190
  * @param {((v: T) => U | Promise<U>)} fn - computed callback
172
191
  * @returns {Computed<U>} - computed signal
@@ -174,21 +193,23 @@ export const computed = <T extends {}, S extends Signal<{}>[] = []>(
174
193
  map: <U extends {}>(fn: (v: T) => U | Promise<U>): Computed<U> =>
175
194
  computed({
176
195
  signals: [c],
177
- ok: fn
196
+ ok: fn,
178
197
  }),
179
198
 
180
- /**
199
+ /**
181
200
  * Case matching for the computed signal with effect callbacks
182
- *
201
+ *
183
202
  * @since 0.13.0
184
203
  * @param {TapMatcher<T> | ((v: T) => void | (() => void))} matcher - tap matcher or effect callback
185
204
  * @returns {() => void} - cleanup function for the effect
186
205
  */
187
- tap: (matcher: TapMatcher<T> | ((v: T) => void | (() => void))): () => void =>
206
+ tap: (
207
+ matcher: TapMatcher<T> | ((v: T) => void | (() => void)),
208
+ ): (() => void) =>
188
209
  effect({
189
210
  signals: [c],
190
- ...(isFunction(matcher) ? { ok: matcher } : matcher)
191
- } as EffectMatcher<[Computed<T>]>)
211
+ ...(isFunction(matcher) ? { ok: matcher } : matcher),
212
+ } as EffectMatcher<[Computed<T>]>),
192
213
  }
193
214
  return c
194
215
  }
@@ -197,10 +218,11 @@ export const computed = <T extends {}, S extends Signal<{}>[] = []>(
197
218
 
198
219
  /**
199
220
  * Check if a value is a computed state
200
- *
221
+ *
201
222
  * @since 0.9.0
202
223
  * @param {unknown} value - value to check
203
224
  * @returns {boolean} - true if value is a computed state, false otherwise
204
225
  */
205
- export const isComputed = /*#__PURE__*/ <T extends {}>(value: unknown): value is Computed<T> =>
206
- isObjectOfType(value, TYPE_COMPUTED)
226
+ export const isComputed = /*#__PURE__*/ <T extends {}>(
227
+ value: unknown,
228
+ ): value is Computed<T> => isObjectOfType(value, TYPE_COMPUTED)
@@ -12,9 +12,11 @@ export type TapMatcher<T extends {}> = {
12
12
 
13
13
  export type EffectMatcher<S extends Signal<{}>[]> = {
14
14
  signals: S
15
- ok: (...values: {
16
- [K in keyof S]: S[K] extends Signal<infer T> ? T : never
17
- }) => void | (() => void)
15
+ ok: (
16
+ ...values: {
17
+ [K in keyof S]: S[K] extends Signal<infer T> ? T : never
18
+ }
19
+ ) => void | (() => void)
18
20
  err?: (...errors: Error[]) => void | (() => void)
19
21
  nil?: () => void | (() => void)
20
22
  }
@@ -23,39 +25,45 @@ export type EffectMatcher<S extends Signal<{}>[]> = {
23
25
 
24
26
  /**
25
27
  * Define what happens when a reactive state changes
26
- *
28
+ *
27
29
  * @since 0.1.0
28
30
  * @param {EffectMatcher<S> | (() => void | (() => void))} matcher - effect matcher or callback
29
31
  * @returns {() => void} - cleanup function for the effect
30
32
  */
31
33
  export function effect<S extends Signal<{}>[]>(
32
- matcher: EffectMatcher<S> | (() => void | (() => void))
34
+ matcher: EffectMatcher<S> | (() => void | (() => void)),
33
35
  ): () => void {
34
36
  const {
35
37
  signals,
36
38
  ok,
37
39
  err = console.error,
38
- nil = () => {}
40
+ nil = () => {},
39
41
  } = isFunction(matcher)
40
42
  ? { signals: [] as unknown as S, ok: matcher }
41
43
  : matcher
42
44
  let running = false
43
- const run = (() => watch(() => {
44
- if (running) throw new CircularDependencyError('effect')
45
- running = true
46
- let cleanup: void | (() => void) = undefined
47
- try {
48
- cleanup = match<S, void | (() => void)>({ signals, ok, err, nil }) as void | (() => void)
49
- } catch (e) {
50
- err(toError(e))
51
- }
52
- if (isFunction(cleanup)) run.cleanups.add(cleanup)
53
- running = false
54
- }, run)) as Watcher
45
+ const run = (() =>
46
+ watch(() => {
47
+ if (running) throw new CircularDependencyError('effect')
48
+ running = true
49
+ let cleanup: void | (() => void) = undefined
50
+ try {
51
+ cleanup = match<S, void | (() => void)>({
52
+ signals,
53
+ ok,
54
+ err,
55
+ nil,
56
+ }) as void | (() => void)
57
+ } catch (e) {
58
+ err(toError(e))
59
+ }
60
+ if (isFunction(cleanup)) run.cleanups.add(cleanup)
61
+ running = false
62
+ }, run)) as Watcher
55
63
  run.cleanups = new Set()
56
64
  run()
57
65
  return () => {
58
66
  run.cleanups.forEach((fn: () => void) => fn())
59
67
  run.cleanups.clear()
60
68
  }
61
- }
69
+ }
@@ -39,4 +39,4 @@ export declare const watch: (run: () => void, mark?: Watcher) => void;
39
39
  * @param {Updater} fn - function to be executed on the next animation frame; can return updated value <T>, success <boolean> or void
40
40
  * @param {EnqueueDedupe} dedupe - [element, operation] pair for deduplication
41
41
  */
42
- export declare const enqueue: <T>(fn: Updater, dedupe?: EnqueueDedupe) => Promise<boolean | void | T>;
42
+ export declare const enqueue: <T>(fn: Updater, dedupe: EnqueueDedupe) => Promise<boolean | void | T>;