@zeix/cause-effect 0.12.1 → 0.12.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.12.1
3
+ Version 0.12.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
 
package/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @name Cause & Effect
3
- * @version 0.12.1
3
+ * @version 0.12.2
4
4
  * @author Esther Brunner
5
5
  */
6
6
  export { type Signal, type MaybeSignal, type InferMaybeSignalType, type ComputedCallbacks, type EffectCallbacks, UNSET, isSignal, toSignal } from './lib/signal';
package/index.js CHANGED
@@ -1 +1 @@
1
- var V=(x)=>typeof x==="function";var R=(x,B)=>Object.prototype.toString.call(x)===`[object ${B}]`,m=(x)=>(B)=>B instanceof x,j=m(Error),g=m(Promise),y=(x)=>j(x)?x:new Error(String(x));var F,D=new Set,w=0,N=new Map,M,p=()=>{M=void 0;for(let x of N.values()){for(let B of x.values())B();x.clear()}},d=()=>{if(M)cancelAnimationFrame(M);M=requestAnimationFrame(p)};queueMicrotask(p);var T=(x)=>{if(F&&!x.includes(F))x.push(F)},C=(x)=>{for(let B of x)w?D.add(B):B()},U=()=>{while(D.size){let x=Array.from(D);D.clear();for(let B of x)B()}},n=(x)=>{w++,x(),U(),w--},O=(x,B)=>{let z=F;F=B,x(),F=z},v=(x,B)=>new Promise((z,$)=>{let L=()=>{try{z(x())}catch(H){$(H)}};if(B){let[H,J]=B;if(!N.has(H))N.set(H,new Map);N.get(H).set(J,L)}d()});function Y(x,...B){let z=()=>O(()=>{let $=_(B,x);if(j($))console.error("Unhandled error in effect:",$)},z);z()}var o="Computed",i=(x,B)=>{if(!B)return!1;return x.name===B.name&&x.message===B.message},I=(x,...B)=>{let z=[],$=Q,L,H=!0,J=!1,X=!1,K=(G)=>{if(!Object.is(G,$))$=G,H=!1,L=void 0,J=!1},W=()=>{J=Q===$,$=Q,L=void 0},Z=(G)=>{let P=y(G);J=i(P,L),$=Q,L=P},A=()=>{if(H=!0,!J)C(z)},h=()=>O(()=>{if(X)throw new Error("Circular dependency detected");J=!0,X=!0;let G=_(B,x);if(g(G))W(),G.then((P)=>{K(P),C(z)}).catch(Z);else if(G==null||Q===G)W();else if(j(G))Z(G);else K(G);X=!1},A),q={[Symbol.toStringTag]:o,get:()=>{if(T(z),U(),H)h();if(L)throw L;return $},map:(G)=>I(G,q),match:(G)=>{return Y(G,q),q}};return q},S=(x)=>R(x,o);var b="State",E=(x)=>{let B=[],z=x,$={[Symbol.toStringTag]:b,get:()=>{return T(B),z},set:(L)=>{if(Object.is(z,L))return;if(z=L,C(B),Q===z)B.length=0},update:(L)=>{$.set(L(z))},map:(L)=>I(L,$),match:(L)=>{return Y(L,$),$}};return $},k=(x)=>R(x,b);var Q=Symbol(),c=(x)=>V(x)&&!x.length||typeof x==="object"&&x!==null&&("ok"in x)&&V(x.ok),f=(x)=>k(x)||S(x),t=(x)=>f(x)?x:c(x)?I(x):E(x),_=(x,B)=>{let{ok:z,nil:$,err:L}=V(B)?{ok:B}:B,H=[],J=[],X=!1;for(let W=0;W<x.length;W++){let Z=x[W];try{let A=f(Z)?Z.get():V(Z)?Z():Z;if(A===Q)X=!0;H[W]=A}catch(A){J.push(y(A))}}let K=void 0;try{if(X&&$)K=$();else if(J.length)K=L?L(...J):J[0];else if(!X)K=z(...H)}catch(W){if(K=y(W),L)K=L(K)}return K};export{O as watch,t as toSignal,E as state,k as isState,f as isSignal,S as isComputed,v as enqueue,Y as effect,I as computed,n as batch,Q as UNSET};
1
+ var V=(x)=>typeof x==="function";var R=(x,B)=>Object.prototype.toString.call(x)===`[object ${B}]`,m=(x)=>(B)=>B instanceof x,j=m(Error),g=m(Promise),y=(x)=>j(x)?x:new Error(String(x));var F,D=new Set,w=0,N=new Map,M,p=()=>{M=void 0;for(let x of N.values()){for(let B of x.values())B();x.clear()}},d=()=>{if(M)cancelAnimationFrame(M);M=requestAnimationFrame(p)};queueMicrotask(p);var T=(x)=>{if(F&&!x.includes(F))x.push(F)},C=(x)=>{for(let B of x)w?D.add(B):B()},U=()=>{while(D.size){let x=Array.from(D);D.clear();for(let B of x)B()}},n=(x)=>{w++,x(),U(),w--},O=(x,B)=>{let z=F;F=B,x(),F=z},v=(x,B)=>new Promise((z,$)=>{let L=()=>{try{z(x())}catch(H){$(H)}};if(B){let[H,J]=B;if(!N.has(H))N.set(H,new Map);N.get(H).set(J,L)}d()});function Y(x,...B){let z=!1,$=()=>O(()=>{if(z)throw new Error("Circular dependency in effect detected");z=!0;let L=_(B,x);if(j(L))console.error("Unhandled error in effect:",L);z=!1},$);$()}var o="Computed",i=(x,B)=>{if(!B)return!1;return x.name===B.name&&x.message===B.message},I=(x,...B)=>{let z=[],$=Q,L,H=!0,J=!1,X=!1,K=(G)=>{if(!Object.is(G,$))$=G,H=!1,L=void 0,J=!1},W=()=>{J=Q===$,$=Q,L=void 0},Z=(G)=>{let P=y(G);J=i(P,L),$=Q,L=P},A=()=>{if(H=!0,!J)C(z)},h=()=>O(()=>{if(X)throw new Error("Circular dependency in computed detected");J=!0,X=!0;let G=_(B,x);if(g(G))W(),G.then((P)=>{K(P),C(z)}).catch(Z);else if(G==null||Q===G)W();else if(j(G))Z(G);else K(G);X=!1},A),q={[Symbol.toStringTag]:o,get:()=>{if(T(z),U(),H)h();if(L)throw L;return $},map:(G)=>I(G,q),match:(G)=>{return Y(G,q),q}};return q},S=(x)=>R(x,o);var b="State",E=(x)=>{let B=[],z=x,$={[Symbol.toStringTag]:b,get:()=>{return T(B),z},set:(L)=>{if(Object.is(z,L))return;if(z=L,C(B),Q===z)B.length=0},update:(L)=>{$.set(L(z))},map:(L)=>I(L,$),match:(L)=>{return Y(L,$),$}};return $},k=(x)=>R(x,b);var Q=Symbol(),c=(x)=>V(x)&&!x.length||typeof x==="object"&&x!==null&&("ok"in x)&&V(x.ok),f=(x)=>k(x)||S(x),t=(x)=>f(x)?x:c(x)?I(x):E(x),_=(x,B)=>{let{ok:z,nil:$,err:L}=V(B)?{ok:B}:B,H=[],J=[],X=!1;for(let W=0;W<x.length;W++){let Z=x[W];try{let A=f(Z)?Z.get():V(Z)?Z():Z;if(A===Q)X=!0;H[W]=A}catch(A){J.push(y(A))}}let K=void 0;try{if(X&&$)K=$();else if(J.length)K=L?L(...J):J[0];else if(!X)K=z(...H)}catch(W){if(K=y(W),L)K=L(K)}return K};export{O as watch,t as toSignal,E as state,k as isState,f as isSignal,S as isComputed,v as enqueue,Y as effect,I as computed,n as batch,Q as UNSET};
package/index.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @name Cause & Effect
3
- * @version 0.12.1
3
+ * @version 0.12.2
4
4
  * @author Esther Brunner
5
5
  */
6
6
  export {
package/lib/computed.ts CHANGED
@@ -79,7 +79,7 @@ export const computed = <T extends {}, U extends MaybeSignal<{}>[]>(
79
79
 
80
80
  // Called when requested by dependencies (pull)
81
81
  const compute = () => watch(() => {
82
- if (computing) throw new Error('Circular dependency detected')
82
+ if (computing) throw new Error('Circular dependency in computed detected')
83
83
  unchanged = true
84
84
  computing = true
85
85
  const result = resolve(maybeSignals, cb)
package/lib/effect.ts CHANGED
@@ -16,10 +16,14 @@ export function effect<U extends MaybeSignal<{}>[]>(
16
16
  cb: EffectCallbacks<U>,
17
17
  ...maybeSignals: U
18
18
  ): void {
19
+ let running = false
19
20
  const run = () => watch(() => {
21
+ if (running) throw new Error('Circular dependency in effect detected')
22
+ running = true
20
23
  const result = resolve(maybeSignals, cb)
21
24
  if (isError(result))
22
25
  console.error('Unhandled error in effect:', result)
26
+ running = false
23
27
  }, run)
24
28
  run()
25
29
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeix/cause-effect",
3
- "version": "0.12.1",
3
+ "version": "0.12.2",
4
4
  "author": "Esther Brunner",
5
5
  "main": "index.js",
6
6
  "module": "index.ts",
@@ -216,36 +216,45 @@ describe('Computed', function () {
216
216
  const c = computed(() => b.get() + a.get());
217
217
  expect(() => {
218
218
  b.get(); // This should trigger the circular dependency
219
- }).toThrow('Circular dependency detected');
219
+ }).toThrow('Circular dependency in computed detected');
220
220
  expect(a.get()).toBe(1);
221
221
  });
222
222
 
223
- /* test('should propagate error if an error occurred', function() {
224
- let count = 0;
223
+ test('should propagate error if an error occurred', function() {
224
+ let okCount = 0;
225
+ let errCount = 0;
225
226
  const x = state(0);
226
- const a = computed(() => {
227
- if (x.get() === 1) throw new Error('Calculation error');
227
+ const a = x.map(v => {
228
+ if (v === 1) throw new Error('Calculation error');
228
229
  return 1;
229
230
  });
230
- const b = a.map(v => v ? 'success' : 'pending');
231
- const c = computed(() => {
232
- count++;
233
- return `c: ${b.get()}`;
231
+ const b = a.map({
232
+ ok: v => v ? 'success' : 'failure',
233
+ err: _e => {
234
+ errCount++;
235
+ // console.error(e);
236
+ return `recovered`;
237
+ }
238
+ });
239
+ const c = b.map(v => {
240
+ okCount++;
241
+ return `c: ${v}`;
234
242
  });
235
243
  expect(a.get()).toBe(1);
236
244
  expect(c.get()).toBe('c: success');
237
- expect(count).toBe(1);
238
- x.set(1)
245
+ expect(okCount).toBe(1);
239
246
  try {
247
+ x.set(1)
240
248
  expect(a.get()).toBe(1);
241
249
  expect(true).toBe(false); // This line should not be reached
242
250
  } catch (error) {
243
251
  expect(error.message).toBe('Calculation error');
244
252
  } finally {
245
- expect(c.get()).toBe('c: success');
246
- expect(count).toBe(2);
253
+ expect(c.get()).toBe('c: recovered');
254
+ expect(okCount).toBe(2);
255
+ expect(errCount).toBe(1);
247
256
  }
248
- }); */
257
+ });
249
258
 
250
259
  test('should return a computed signal with .map()', function() {
251
260
  const cause = state(42);
@@ -154,4 +154,28 @@ describe('Effect', function () {
154
154
  console.error = originalConsoleError;
155
155
  }
156
156
  });
157
+
158
+ test('should detect and throw error for circular dependencies in effects', () => {
159
+ let okCount = 0
160
+ let errCount = 0
161
+ const count = state(0)
162
+
163
+ effect({
164
+ ok: () => {
165
+ okCount++
166
+ // This effect updates the signal it depends on, creating a circular dependency
167
+ count.update(v => ++v)
168
+ },
169
+ err: e => {
170
+ errCount++
171
+ expect(e).toBeInstanceOf(Error)
172
+ expect(e.message).toBe('Circular dependency in effect detected')
173
+ }
174
+ }, count)
175
+
176
+ // Verify that the count was changed only once due to the circular dependency error
177
+ expect(count.get()).toBe(1)
178
+ expect(okCount).toBe(1)
179
+ expect(errCount).toBe(1)
180
+ })
157
181
  });