@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 +1 -1
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/index.ts +1 -1
- package/lib/computed.ts +1 -1
- package/lib/effect.ts +4 -0
- package/package.json +1 -1
- package/test/computed.test.ts +23 -14
- package/test/effect.test.ts +24 -0
package/README.md
CHANGED
package/index.d.ts
CHANGED
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
|
|
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
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
package/test/computed.test.ts
CHANGED
|
@@ -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
|
-
|
|
224
|
-
let
|
|
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 =
|
|
227
|
-
if (
|
|
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(
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
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(
|
|
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:
|
|
246
|
-
expect(
|
|
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);
|
package/test/effect.test.ts
CHANGED
|
@@ -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
|
});
|