@zeix/cause-effect 0.18.3 → 0.18.5
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/ARCHITECTURE.md +8 -8
- package/CHANGELOG.md +22 -0
- package/CLAUDE.md +36 -397
- package/OWNERSHIP_BUG.md +95 -0
- package/README.md +1 -1
- package/index.dev.js +18 -10
- package/index.js +1 -1
- package/index.ts +2 -1
- package/package.json +1 -1
- package/src/graph.ts +26 -4
- package/src/nodes/memo.ts +1 -3
- package/src/nodes/task.ts +1 -3
- package/test/effect.test.ts +204 -0
- package/test/unown.test.ts +179 -0
- package/types/index.d.ts +2 -2
- package/types/src/graph.d.ts +12 -1
- package/.ai-context.md +0 -281
- package/examples/events-sensor.ts +0 -187
- package/examples/selector-sensor.ts +0 -173
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Cause & Effect
|
|
2
2
|
|
|
3
|
-
Version 0.18.
|
|
3
|
+
Version 0.18.5
|
|
4
4
|
|
|
5
5
|
**Cause & Effect** is a reactive state management primitives library for TypeScript. It provides the foundational building blocks for managing complex, dynamic, composite, and asynchronous state — correctly and performantly — in a unified signal graph.
|
|
6
6
|
|
package/index.dev.js
CHANGED
|
@@ -199,10 +199,12 @@ function propagate(node, newFlag = FLAG_DIRTY) {
|
|
|
199
199
|
for (let e = node.sinks;e; e = e.nextSink)
|
|
200
200
|
propagate(e.sink, FLAG_CHECK);
|
|
201
201
|
} else {
|
|
202
|
-
if (flags & FLAG_DIRTY)
|
|
202
|
+
if ((flags & (FLAG_DIRTY | FLAG_CHECK)) >= newFlag)
|
|
203
203
|
return;
|
|
204
|
-
|
|
205
|
-
|
|
204
|
+
const wasQueued = flags & (FLAG_DIRTY | FLAG_CHECK);
|
|
205
|
+
node.flags = newFlag;
|
|
206
|
+
if (!wasQueued)
|
|
207
|
+
queuedEffects.push(node);
|
|
206
208
|
}
|
|
207
209
|
}
|
|
208
210
|
function setState(node, next) {
|
|
@@ -354,7 +356,7 @@ function flush() {
|
|
|
354
356
|
try {
|
|
355
357
|
for (let i = 0;i < queuedEffects.length; i++) {
|
|
356
358
|
const effect = queuedEffects[i];
|
|
357
|
-
if (effect.flags & FLAG_DIRTY)
|
|
359
|
+
if (effect.flags & (FLAG_DIRTY | FLAG_CHECK))
|
|
358
360
|
refresh(effect);
|
|
359
361
|
}
|
|
360
362
|
queuedEffects.length = 0;
|
|
@@ -397,6 +399,15 @@ function createScope(fn) {
|
|
|
397
399
|
activeOwner = prevOwner;
|
|
398
400
|
}
|
|
399
401
|
}
|
|
402
|
+
function unown(fn) {
|
|
403
|
+
const prev = activeOwner;
|
|
404
|
+
activeOwner = null;
|
|
405
|
+
try {
|
|
406
|
+
return fn();
|
|
407
|
+
} finally {
|
|
408
|
+
activeOwner = prev;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
400
411
|
// src/nodes/state.ts
|
|
401
412
|
function createState(value, options) {
|
|
402
413
|
validateSignalValue(TYPE_STATE, value, options?.guard);
|
|
@@ -797,9 +808,7 @@ function createMemo(fn, options) {
|
|
|
797
808
|
if (activeSink) {
|
|
798
809
|
if (!node.sinks)
|
|
799
810
|
node.stop = watched(() => {
|
|
800
|
-
node
|
|
801
|
-
for (let e = node.sinks;e; e = e.nextSink)
|
|
802
|
-
propagate(e.sink);
|
|
811
|
+
propagate(node);
|
|
803
812
|
if (batchDepth === 0)
|
|
804
813
|
flush();
|
|
805
814
|
});
|
|
@@ -848,9 +857,7 @@ function createTask(fn, options) {
|
|
|
848
857
|
if (activeSink) {
|
|
849
858
|
if (!node.sinks)
|
|
850
859
|
node.stop = watched(() => {
|
|
851
|
-
node
|
|
852
|
-
for (let e = node.sinks;e; e = e.nextSink)
|
|
853
|
-
propagate(e.sink);
|
|
860
|
+
propagate(node);
|
|
854
861
|
if (batchDepth === 0)
|
|
855
862
|
flush();
|
|
856
863
|
});
|
|
@@ -1606,6 +1613,7 @@ function isSlot(value) {
|
|
|
1606
1613
|
export {
|
|
1607
1614
|
valueString,
|
|
1608
1615
|
untrack,
|
|
1616
|
+
unown,
|
|
1609
1617
|
match,
|
|
1610
1618
|
isTask,
|
|
1611
1619
|
isStore,
|
package/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function g($){return typeof $==="function"}function i($){return g($)&&$.constructor.name==="AsyncFunction"}function z$($){return g($)&&$.constructor.name!=="AsyncFunction"}function A($,J){return Object.prototype.toString.call($)===`[object ${J}]`}function L($){return A($,"Object")}function A$($,J=(z)=>z!=null){return Array.isArray($)&&$.every(J)}function m$($){return typeof $==="string"?`"${$}"`:!!$&&typeof $==="object"?JSON.stringify($):String($)}class X$ extends Error{constructor($){super(`[${$}] Circular dependency detected`);this.name="CircularDependencyError"}}class Y$ extends TypeError{constructor($){super(`[${$}] Signal value cannot be null or undefined`);this.name="NullishSignalValueError"}}class o extends Error{constructor($){super(`[${$}] Signal value is unset`);this.name="UnsetSignalValueError"}}class Z$ extends TypeError{constructor($,J){super(`[${$}] Signal value ${m$(J)} is invalid`);this.name="InvalidSignalValueError"}}class b$ extends TypeError{constructor($,J){super(`[${$}] Callback ${m$(J)} is invalid`);this.name="InvalidCallbackError"}}class P$ extends Error{constructor($){super(`[${$}] Signal is read-only`);this.name="ReadonlySignalError"}}class D$ extends Error{constructor($){super(`[${$}] Active owner is required`);this.name="RequiredOwnerError"}}class e extends Error{constructor($,J,z){super(`[${$}] Could not add key "${J}"${z?` with value ${JSON.stringify(z)}`:""} because it already exists`);this.name="DuplicateKeyError"}}function K($,J,z){if(J==null)throw new Y$($);if(z&&!z(J))throw new Z$($,J)}function j$($,J){if(J==null)throw new o($)}function T($,J,z=g){if(!z(J))throw new b$($,J)}var c="State",u="Memo",d="Task",t="Sensor",E="List",l="Collection",r="Store",s="Slot",S=0,C$=1,D=2,M$=4,b=8,N=null,y=null,G$=[],R=0,_$=!1,k=($,J)=>$===J,L$=($,J)=>!1;function g$($,J){let z=J.sourcesTail;if(z){let X=J.sources;while(X){if(X===$)return!0;if(X===z)break;X=X.nextSource}}return!1}function F($,J){let z=J.sourcesTail;if(z?.source===$)return;let X=null,W=J.flags&M$;if(W){if(X=z?z.nextSource:J.sources,X?.source===$){J.sourcesTail=X;return}}let H=$.sinksTail;if(H?.sink===J&&(!W||g$(H,J)))return;let P={source:$,sink:J,nextSource:X,prevSink:H,nextSink:null};if(J.sourcesTail=$.sinksTail=P,z)z.nextSource=P;else J.sources=P;if(H)H.nextSink=P;else $.sinks=P}function k$($){let{source:J,nextSource:z,nextSink:X,prevSink:W}=$;if(X)X.prevSink=W;else J.sinksTail=W;if(W)W.nextSink=X;else J.sinks=X;if(!J.sinks){if(J.stop)J.stop(),J.stop=void 0;if("sources"in J&&J.sources){let H=J;H.sourcesTail=null,W$(H)}}return z}function W$($){let J=$.sourcesTail,z=J?J.nextSource:$.sources;while(z)z=k$(z);if(J)J.nextSource=null;else $.sources=null}function x($,J=D){let z=$.flags;if("sinks"in $){if((z&(D|C$))>=J)return;if($.flags=z|J,"controller"in $&&$.controller)$.controller.abort(),$.controller=void 0;for(let X=$.sinks;X;X=X.nextSink)x(X.sink,C$)}else{if(z&D)return;$.flags=D,G$.push($)}}function U$($,J){if($.equals($.value,J))return;$.value=J;for(let z=$.sinks;z;z=z.nextSink)x(z.sink);if(R===0)w()}function $$($,J){if(!$.cleanup)$.cleanup=J;else if(Array.isArray($.cleanup))$.cleanup.push(J);else $.cleanup=[$.cleanup,J]}function K$($){if(!$.cleanup)return;if(Array.isArray($.cleanup))for(let J=0;J<$.cleanup.length;J++)$.cleanup[J]();else $.cleanup();$.cleanup=null}function v$($){let J=N;N=$,$.sourcesTail=null,$.flags=M$;let z=!1;try{let X=$.fn($.value);if($.error||!$.equals(X,$.value))$.value=X,$.error=void 0,z=!0}catch(X){z=!0,$.error=X instanceof Error?X:Error(String(X))}finally{N=J,W$($)}if(z){for(let X=$.sinks;X;X=X.nextSink)if(X.sink.flags&C$)X.sink.flags|=D}$.flags=S}function c$($){$.controller?.abort();let J=new AbortController;$.controller=J,$.error=void 0;let z=N;N=$,$.sourcesTail=null,$.flags=M$;let X;try{X=$.fn($.value,J.signal)}catch(W){$.controller=void 0,$.error=W instanceof Error?W:Error(String(W));return}finally{N=z,W$($)}X.then((W)=>{if(J.signal.aborted)return;if($.controller=void 0,$.error||!$.equals(W,$.value)){$.value=W,$.error=void 0;for(let H=$.sinks;H;H=H.nextSink)x(H.sink);if(R===0)w()}},(W)=>{if(J.signal.aborted)return;$.controller=void 0;let H=W instanceof Error?W:Error(String(W));if(!$.error||H.name!==$.error.name||H.message!==$.error.message){$.error=H;for(let P=$.sinks;P;P=P.nextSink)x(P.sink);if(R===0)w()}}),$.flags=S}function T$($){K$($);let J=N,z=y;N=y=$,$.sourcesTail=null,$.flags=M$;try{let X=$.fn();if(typeof X==="function")$$($,X)}finally{N=J,y=z,W$($)}$.flags=S}function I($){if($.flags&C$)for(let J=$.sources;J;J=J.nextSource){if("fn"in J.source)I(J.source);if($.flags&D)break}if($.flags&M$)throw new X$("controller"in $?d:("value"in $)?u:"Effect");if($.flags&D)if("controller"in $)c$($);else if("value"in $)v$($);else T$($);else $.flags=S}function w(){if(_$)return;_$=!0;try{for(let $=0;$<G$.length;$++){let J=G$[$];if(J.flags&D)I(J)}G$.length=0}finally{_$=!1}}function J$($){R++;try{$()}finally{if(R--,R===0)w()}}function v($){let J=N;N=null;try{return $()}finally{N=J}}function u$($){let J=y,z={cleanup:null};y=z;try{let X=$();if(typeof X==="function")$$(z,X);let W=()=>K$(z);if(J)$$(J,W);return W}finally{y=J}}function p($,J){K(c,$,J?.guard);let z={value:$,sinks:null,sinksTail:null,equals:J?.equals??k,guard:J?.guard};return{[Symbol.toStringTag]:c,get(){if(N)F(z,N);return z.value},set(X){K(c,X,z.guard),U$(z,X)},update(X){T(c,X);let W=X(z.value);K(c,W,z.guard),U$(z,W)}}}function N$($){return A($,c)}function n($,J,z){if(Object.is($,J))return!0;if(typeof $!==typeof J)return!1;if($==null||typeof $!=="object"||J==null||typeof J!=="object")return!1;if(!z)z=new WeakSet;if(z.has($)||z.has(J))throw new X$("isEqual");z.add($),z.add(J);try{let X=Array.isArray($);if(X!==Array.isArray(J))return!1;if(X){let W=$,H=J;if(W.length!==H.length)return!1;for(let P=0;P<W.length;P++)if(!n(W[P],H[P],z))return!1;return!0}if(L($)&&L(J)){let W=Object.keys($),H=Object.keys(J);if(W.length!==H.length)return!1;for(let P of W){if(!(P in J))return!1;if(!n($[P],J[P],z))return!1}return!0}return!1}finally{z.delete($),z.delete(J)}}function O$($,J){if($.length!==J.length)return!1;for(let z=0;z<$.length;z++)if($[z]!==J[z])return!1;return!0}function E$($){let J=0,z=typeof $==="function";return[typeof $==="string"?()=>`${$}${J++}`:z?(X)=>$(X)||String(J++):()=>String(J++),z]}function d$($,J,z,X,W){let H=new WeakSet,P={},M={},C={},U=[],Q=!1,j=new Map;for(let q=0;q<$.length;q++){let Z=z[q];if(Z&&$[q])j.set(Z,$[q])}let G=new Set;for(let q=0;q<J.length;q++){let Z=J[q];if(Z===void 0)continue;let B=W?X(Z):z[q]??X(Z);if(G.has(B))throw new e(E,B,Z);if(U.push(B),G.add(B),!j.has(B))P[B]=Z,Q=!0;else if(!n(j.get(B),Z,H))M[B]=Z,Q=!0}for(let[q]of j)if(!G.has(q))C[q]=null,Q=!0;if(!Q&&!O$(z,U))Q=!0;return{add:P,change:M,remove:C,newKeys:U,changed:Q}}function H$($,J){K(E,$,Array.isArray);let z=new Map,X=[],[W,H]=E$(J?.keyConfig),P=()=>X.map((Z)=>z.get(Z)?.get()).filter((Z)=>Z!==void 0),M={fn:P,value:$,flags:D,sources:null,sourcesTail:null,sinks:null,sinksTail:null,equals:n,error:void 0},C=(Z)=>{let B={};for(let V=0;V<Z.length;V++){let m=Z[V];if(m===void 0)continue;let O=X[V];if(!O)O=W(m),X[V]=O;B[O]=m}return B},U=(Z)=>{let B=!1;for(let V in Z.add){let m=Z.add[V];K(`${E} item for key "${V}"`,m),z.set(V,p(m)),B=!0}if(Object.keys(Z.change).length)J$(()=>{for(let V in Z.change){let m=Z.change[V];K(`${E} item for key "${V}"`,m);let O=z.get(V);if(O)O.set(m)}});for(let V in Z.remove){z.delete(V);let m=X.indexOf(V);if(m!==-1)X.splice(m,1);B=!0}if(B)M.flags|=b;return Z.changed},Q=J?.watched,j=Q?()=>{if(N){if(!M.sinks)M.stop=Q();F(M,N)}}:()=>{if(N)F(M,N)},G=C($);for(let Z in G){let B=G[Z];K(`${E} item for key "${Z}"`,B),z.set(Z,p(B))}M.value=$,M.flags=0;let q={[Symbol.toStringTag]:E,[Symbol.isConcatSpreadable]:!0,*[Symbol.iterator](){for(let Z of X){let B=z.get(Z);if(B)yield B}},get length(){return j(),X.length},get(){if(j(),M.sources){if(M.flags){let Z=M.flags&b;if(M.value=v(P),Z){if(M.flags=D,I(M),M.error)throw M.error}else M.flags=S}}else if(I(M),M.error)throw M.error;return M.value},set(Z){let B=M.flags&D?P():M.value,V=d$(B,Z,X,W,H);if(V.changed){X=V.newKeys,U(V),M.flags|=D;for(let m=M.sinks;m;m=m.nextSink)x(m.sink);if(R===0)w()}},update(Z){q.set(Z(q.get()))},at(Z){return z.get(X[Z])},keys(){return j(),X.values()},byKey(Z){return z.get(Z)},keyAt(Z){return X[Z]},indexOfKey(Z){return X.indexOf(Z)},add(Z){let B=W(Z);if(z.has(B))throw new e(E,B,Z);if(!X.includes(B))X.push(B);K(`${E} item for key "${B}"`,Z),z.set(B,p(Z)),M.flags|=D|b;for(let V=M.sinks;V;V=V.nextSink)x(V.sink);if(R===0)w();return B},remove(Z){let B=typeof Z==="number"?X[Z]:Z;if(z.delete(B)){let m=typeof Z==="number"?Z:X.indexOf(B);if(m>=0)X.splice(m,1);M.flags|=D|b;for(let O=M.sinks;O;O=O.nextSink)x(O.sink);if(R===0)w()}},sort(Z){let V=X.map((m)=>[m,z.get(m)?.get()]).sort(g(Z)?(m,O)=>Z(m[1],O[1]):(m,O)=>String(m[1]).localeCompare(String(O[1]))).map(([m])=>m);if(!O$(X,V)){X=V,M.flags|=D;for(let m=M.sinks;m;m=m.nextSink)x(m.sink);if(R===0)w()}},splice(Z,B,...V){let m=X.length,O=Z<0?Math.max(0,m+Z):Math.min(Z,m),f=Math.max(0,Math.min(B??Math.max(0,m-Math.max(0,O)),m-O)),Y={},_={};for(let h=0;h<f;h++){let a=O+h,f$=X[a];if(f$){let y$=z.get(f$);if(y$)_[f$]=y$.get()}}let I$=X.slice(0,O);for(let h of V){let a=W(h);if(z.has(a)&&!(a in _))throw new e(E,a,h);I$.push(a),Y[a]=h}I$.push(...X.slice(O+f));let p$=!!(Object.keys(Y).length||Object.keys(_).length);if(p$){U({add:Y,change:{},remove:_,changed:p$}),X=I$,M.flags|=D;for(let h=M.sinks;h;h=h.nextSink)x(h.sink);if(R===0)w()}return Object.values(_)},deriveCollection(Z){return R$(q,Z)}};return q}function F$($){return A($,E)}function Q$($,J){if(T(u,$,z$),J?.value!==void 0)K(u,J.value,J?.guard);let z={fn:$,value:J?.value,flags:D,sources:null,sourcesTail:null,sinks:null,sinksTail:null,equals:J?.equals??k,error:void 0,stop:void 0},X=J?.watched,W=X?()=>{if(N){if(!z.sinks)z.stop=X(()=>{z.flags|=D;for(let H=z.sinks;H;H=H.nextSink)x(H.sink);if(R===0)w()});F(z,N)}}:()=>{if(N)F(z,N)};return{[Symbol.toStringTag]:u,get(){if(W(),I(z),z.error)throw z.error;return j$(u,z.value),z.value}}}function S$($){return A($,u)}function B$($,J){if(T(d,$,i),J?.value!==void 0)K(d,J.value,J?.guard);let z={fn:$,value:J?.value,sources:null,sourcesTail:null,sinks:null,sinksTail:null,flags:D,equals:J?.equals??k,controller:void 0,error:void 0,stop:void 0},X=J?.watched,W=X?()=>{if(N){if(!z.sinks)z.stop=X(()=>{z.flags|=D;for(let H=z.sinks;H;H=H.nextSink)x(H.sink);if(R===0)w()});F(z,N)}}:()=>{if(N)F(z,N)};return{[Symbol.toStringTag]:d,get(){if(W(),I(z),z.error)throw z.error;return j$(d,z.value),z.value},isPending(){return!!z.controller},abort(){z.controller?.abort(),z.controller=void 0}}}function h$($){return A($,d)}function R$($,J){T(l,J);let z=i(J),X=new Map,W=[],H=(q)=>{let Z=z?B$(async(B,V)=>{let m=$.byKey(q)?.get();if(m==null)return B;return J(m,V)}):Q$(()=>{let B=$.byKey(q)?.get();if(B==null)return;return J(B)});X.set(q,Z)};function P(q){if(!O$(W,q)){let Z=new Set(W),B=new Set(q);for(let V of W)if(!B.has(V))X.delete(V);for(let V of q)if(!Z.has(V))H(V);W=q,U.flags|=b}}function M(){P(Array.from($.keys()));let q=[];for(let Z of W)try{let B=X.get(Z)?.get();if(B!=null)q.push(B)}catch(B){if(!(B instanceof o))throw B}return q}let U={fn:M,value:[],flags:D,sources:null,sourcesTail:null,sinks:null,sinksTail:null,equals:(q,Z)=>{if(q.length!==Z.length)return!1;for(let B=0;B<q.length;B++)if(q[B]!==Z[B])return!1;return!0},error:void 0};function Q(){if(U.sources){if(U.flags)if(U.value=v(M),U.flags&b){if(U.flags=D,I(U),U.error)throw U.error}else U.flags=S}else if(U.sinks){if(I(U),U.error)throw U.error}else U.value=v(M)}let j=Array.from(v(()=>$.keys()));for(let q of j)H(q);W=j;let G={[Symbol.toStringTag]:l,[Symbol.isConcatSpreadable]:!0,*[Symbol.iterator](){for(let q of W){let Z=X.get(q);if(Z)yield Z}},get length(){if(N)F(U,N);return Q(),W.length},keys(){if(N)F(U,N);return Q(),W.values()},get(){if(N)F(U,N);return Q(),U.value},at(q){return X.get(W[q])},byKey(q){return X.get(q)},keyAt(q){return W[q]},indexOfKey(q){return W.indexOf(q)},deriveCollection(q){return R$(G,q)}};return G}function t$($,J){let z=J?.value??[];if(z.length)K(l,z,Array.isArray);T(l,$,z$);let X=new Map,W=[],H=new Map,[P,M]=E$(J?.keyConfig),C=(Z)=>H.get(Z)??(M?P(Z):void 0),U=J?.createItem??p;function Q(){let Z=[];for(let B of W)try{let V=X.get(B)?.get();if(V!=null)Z.push(V)}catch(V){if(!(V instanceof o))throw V}return Z}let j={fn:Q,value:z,flags:D,sources:null,sourcesTail:null,sinks:null,sinksTail:null,equals:L$,error:void 0};for(let Z of z){let B=P(Z);X.set(B,U(Z)),H.set(Z,B),W.push(B)}j.value=z,j.flags=D;function G(){if(N){if(!j.sinks)j.stop=$((Z)=>{let{add:B,change:V,remove:m}=Z;if(!B?.length&&!V?.length&&!m?.length)return;let O=!1;J$(()=>{if(B)for(let f of B){let Y=P(f);if(X.set(Y,U(f)),H.set(f,Y),!W.includes(Y))W.push(Y);O=!0}if(V)for(let f of V){let Y=C(f);if(!Y)continue;let _=X.get(Y);if(_&&N$(_))H.delete(_.get()),_.set(f),H.set(f,Y)}if(m)for(let f of m){let Y=C(f);if(!Y)continue;H.delete(f),X.delete(Y);let _=W.indexOf(Y);if(_!==-1)W.splice(_,1);O=!0}j.flags=D|(O?b:0);for(let f=j.sinks;f;f=f.nextSink)x(f.sink)})});F(j,N)}}let q={[Symbol.toStringTag]:l,[Symbol.isConcatSpreadable]:!0,*[Symbol.iterator](){for(let Z of W){let B=X.get(Z);if(B)yield B}},get length(){return G(),W.length},keys(){return G(),W.values()},get(){if(G(),j.sources){if(j.flags){let Z=j.flags&b;if(j.value=v(Q),Z){if(j.flags=D,I(j),j.error)throw j.error}else j.flags=S}}else if(I(j),j.error)throw j.error;return j.value},at(Z){return X.get(W[Z])},byKey(Z){return X.get(Z)},keyAt(Z){return W[Z]},indexOfKey(Z){return W.indexOf(Z)},deriveCollection(Z){return R$(q,Z)}};return q}function l$($){return A($,l)}function r$($){T("Effect",$);let J={fn:$,flags:D,sources:null,sourcesTail:null,cleanup:null},z=()=>{K$(J),J.fn=void 0,J.flags=S,J.sourcesTail=null,W$(J)};if(y)$$(y,z);return T$(J),z}function s$($,J){if(!y)throw new D$("match");let{ok:z,err:X=console.error,nil:W}=J,H,P=!1,M=Array($.length);for(let U=0;U<$.length;U++)try{M[U]=$[U].get()}catch(Q){if(Q instanceof o){P=!0;continue}if(!H)H=[];H.push(Q instanceof Error?Q:Error(String(Q)))}let C;try{if(P)C=W?.();else if(H)C=X(H);else C=z(M)}catch(U){X([U instanceof Error?U:Error(String(U))])}if(typeof C==="function")return C;if(C instanceof Promise){let U=y,Q=new AbortController;$$(U,()=>Q.abort()),C.then((j)=>{if(!Q.signal.aborted&&typeof j==="function")$$(U,j)}).catch((j)=>{X([j instanceof Error?j:Error(String(j))])})}}function i$($,J){if(T(t,$,z$),J?.value!==void 0)K(t,J.value,J?.guard);let z={value:J?.value,sinks:null,sinksTail:null,equals:J?.equals??k,guard:J?.guard,stop:void 0};return{[Symbol.toStringTag]:t,get(){if(N){if(!z.sinks)z.stop=$((X)=>{K(t,X,z.guard),U$(z,X)});F(z,N)}return j$(t,z.value),z.value}}}function o$($){return A($,t)}function n$($,J){let z=L($)||Array.isArray($),X=L(J)||Array.isArray(J);if(!z||!X){let j=!Object.is($,J);return{changed:j,add:j&&X?J:{},change:{},remove:j&&z?$:{}}}let W=new WeakSet,H={},P={},M={},C=!1,U=Object.keys($),Q=Object.keys(J);for(let j of Q)if(j in $){if(!n($[j],J[j],W))P[j]=J[j],C=!0}else H[j]=J[j],C=!0;for(let j of U)if(!(j in J))M[j]=void 0,C=!0;return{add:H,change:P,remove:M,changed:C}}function V$($,J){K(r,$,L);let z=new Map,X=(Q,j)=>{if(K(`${r} for key "${Q}"`,j),Array.isArray(j))z.set(Q,H$(j));else if(L(j))z.set(Q,V$(j));else z.set(Q,p(j))},W=()=>{let Q={};return z.forEach((j,G)=>{Q[G]=j.get()}),Q},H={fn:W,value:$,flags:D,sources:null,sourcesTail:null,sinks:null,sinksTail:null,equals:n,error:void 0},P=(Q)=>{let j=!1;for(let G in Q.add)X(G,Q.add[G]),j=!0;if(Object.keys(Q.change).length)J$(()=>{for(let G in Q.change){let q=Q.change[G];K(`${r} for key "${G}"`,q);let Z=z.get(G);if(Z)if(L(q)!==x$(Z))X(G,q),j=!0;else Z.set(q)}});for(let G in Q.remove)z.delete(G),j=!0;if(j)H.flags|=b;return Q.changed},M=J?.watched,C=M?()=>{if(N){if(!H.sinks)H.stop=M();F(H,N)}}:()=>{if(N)F(H,N)};for(let Q of Object.keys($))X(Q,$[Q]);let U={[Symbol.toStringTag]:r,[Symbol.isConcatSpreadable]:!1,*[Symbol.iterator](){for(let Q of Array.from(z.keys())){let j=z.get(Q);if(j)yield[Q,j]}},keys(){return C(),z.keys()},byKey(Q){return z.get(Q)},get(){if(C(),H.sources){if(H.flags){let Q=H.flags&b;if(H.value=v(W),Q){if(H.flags=D,I(H),H.error)throw H.error}else H.flags=S}}else if(I(H),H.error)throw H.error;return H.value},set(Q){let j=H.flags&D?W():H.value,G=n$(j,Q);if(P(G)){H.flags|=D;for(let q=H.sinks;q;q=q.nextSink)x(q.sink);if(R===0)w()}},update(Q){U.set(Q(U.get()))},add(Q,j){if(z.has(Q))throw new e(r,Q,j);X(Q,j),H.flags|=D|b;for(let G=H.sinks;G;G=G.nextSink)x(G.sink);if(R===0)w();return Q},remove(Q){if(z.delete(Q)){H.flags|=D|b;for(let G=H.sinks;G;G=G.nextSink)x(G.sink);if(R===0)w()}}};return new Proxy(U,{get(Q,j){if(j in Q)return Reflect.get(Q,j);if(typeof j!=="symbol")return Q.byKey(j)},has(Q,j){if(j in Q)return!0;return Q.byKey(String(j))!==void 0},ownKeys(Q){return Array.from(Q.keys())},getOwnPropertyDescriptor(Q,j){if(j in Q)return Reflect.getOwnPropertyDescriptor(Q,j);if(typeof j==="symbol")return;let G=Q.byKey(String(j));return G?{enumerable:!0,configurable:!0,writable:!0,value:G}:void 0}})}function x$($){return A($,r)}function a$($,J){return i($)?B$($,J):Q$($,J)}function e$($){if(q$($))return $;if($==null)throw new Z$("createSignal",$);if(i($))return B$($);if(g($))return Q$($);if(A$($))return H$($);if(L($))return V$($);return p($)}function $J($){if(w$($))return $;if($==null||g($)||q$($))throw new Z$("createMutableSignal",$);if(A$($))return H$($);if(L($))return V$($);return p($)}function JJ($){return S$($)||h$($)}function q$($){let J=[c,u,d,t,s,E,l,r],z=Object.prototype.toString.call($).slice(8,-1);return J.includes(z)}function w$($){return N$($)||x$($)||F$($)}function zJ($,J){K(s,$,q$);let z=$,X=J?.guard,W={fn:()=>z.get(),value:void 0,flags:D,sources:null,sourcesTail:null,sinks:null,sinksTail:null,equals:J?.equals??k,error:void 0},H=()=>{if(N)F(W,N);if(I(W),W.error)throw W.error;return W.value},P=(C)=>{if(!w$(z))throw new P$(s);K(s,C,X),z.set(C)},M=(C)=>{K(s,C,q$),z=C,W.flags|=D;for(let U=W.sinks;U;U=U.nextSink)x(U.sink);if(R===0)w()};return{[Symbol.toStringTag]:s,configurable:!0,enumerable:!0,get:H,set:P,replace:M,current:()=>z}}function XJ($){return A($,s)}export{m$ as valueString,v as untrack,s$ as match,h$ as isTask,x$ as isStore,N$ as isState,XJ as isSlot,q$ as isSignal,o$ as isSensor,L as isRecord,A as isObjectOfType,w$ as isMutableSignal,S$ as isMemo,F$ as isList,g as isFunction,n as isEqual,JJ as isComputed,l$ as isCollection,i as isAsyncFunction,B$ as createTask,V$ as createStore,p as createState,zJ as createSlot,e$ as createSignal,i$ as createSensor,u$ as createScope,$J as createMutableSignal,Q$ as createMemo,H$ as createList,r$ as createEffect,a$ as createComputed,t$ as createCollection,J$ as batch,o as UnsetSignalValueError,L$ as SKIP_EQUALITY,D$ as RequiredOwnerError,P$ as ReadonlySignalError,Y$ as NullishSignalValueError,Z$ as InvalidSignalValueError,b$ as InvalidCallbackError,X$ as CircularDependencyError};
|
|
1
|
+
function g($){return typeof $==="function"}function o($){return g($)&&$.constructor.name==="AsyncFunction"}function X$($){return g($)&&$.constructor.name!=="AsyncFunction"}function Y($,J){return Object.prototype.toString.call($)===`[object ${J}]`}function T($){return Y($,"Object")}function Y$($,J=(z)=>z!=null){return Array.isArray($)&&$.every(J)}function D$($){return typeof $==="string"?`"${$}"`:!!$&&typeof $==="object"?JSON.stringify($):String($)}class Z$ extends Error{constructor($){super(`[${$}] Circular dependency detected`);this.name="CircularDependencyError"}}class A$ extends TypeError{constructor($){super(`[${$}] Signal value cannot be null or undefined`);this.name="NullishSignalValueError"}}class i extends Error{constructor($){super(`[${$}] Signal value is unset`);this.name="UnsetSignalValueError"}}class j$ extends TypeError{constructor($,J){super(`[${$}] Signal value ${D$(J)} is invalid`);this.name="InvalidSignalValueError"}}class b$ extends TypeError{constructor($,J){super(`[${$}] Callback ${D$(J)} is invalid`);this.name="InvalidCallbackError"}}class P$ extends Error{constructor($){super(`[${$}] Signal is read-only`);this.name="ReadonlySignalError"}}class G$ extends Error{constructor($){super(`[${$}] Active owner is required`);this.name="RequiredOwnerError"}}class e extends Error{constructor($,J,z){super(`[${$}] Could not add key "${J}"${z?` with value ${JSON.stringify(z)}`:""} because it already exists`);this.name="DuplicateKeyError"}}function O($,J,z){if(J==null)throw new A$($);if(z&&!z(J))throw new j$($,J)}function W$($,J){if(J==null)throw new i($)}function E($,J,z=g){if(!z(J))throw new b$($,J)}var c="State",u="Memo",d="Task",t="Sensor",S="List",s="Collection",l="Store",r="Slot",p=0,$$=1,G=2,U$=4,b=8,m=null,_=null,C$=[],x=0,_$=!1,k=($,J)=>$===J,L$=($,J)=>!1;function g$($,J){let z=J.sourcesTail;if(z){let X=J.sources;while(X){if(X===$)return!0;if(X===z)break;X=X.nextSource}}return!1}function R($,J){let z=J.sourcesTail;if(z?.source===$)return;let X=null,W=J.flags&U$;if(W){if(X=z?z.nextSource:J.sources,X?.source===$){J.sourcesTail=X;return}}let Q=$.sinksTail;if(Q?.sink===J&&(!W||g$(Q,J)))return;let D={source:$,sink:J,nextSource:X,prevSink:Q,nextSink:null};if(J.sourcesTail=$.sinksTail=D,z)z.nextSource=D;else J.sources=D;if(Q)Q.nextSink=D;else $.sinks=D}function k$($){let{source:J,nextSource:z,nextSink:X,prevSink:W}=$;if(X)X.prevSink=W;else J.sinksTail=W;if(W)W.nextSink=X;else J.sinks=X;if(!J.sinks){if(J.stop)J.stop(),J.stop=void 0;if("sources"in J&&J.sources){let Q=J;Q.sourcesTail=null,H$(Q)}}return z}function H$($){let J=$.sourcesTail,z=J?J.nextSource:$.sources;while(z)z=k$(z);if(J)J.nextSource=null;else $.sources=null}function F($,J=G){let z=$.flags;if("sinks"in $){if((z&(G|$$))>=J)return;if($.flags=z|J,"controller"in $&&$.controller)$.controller.abort(),$.controller=void 0;for(let X=$.sinks;X;X=X.nextSink)F(X.sink,$$)}else{if((z&(G|$$))>=J)return;let X=z&(G|$$);if($.flags=J,!X)C$.push($)}}function m$($,J){if($.equals($.value,J))return;$.value=J;for(let z=$.sinks;z;z=z.nextSink)F(z.sink);if(x===0)I()}function J$($,J){if(!$.cleanup)$.cleanup=J;else if(Array.isArray($.cleanup))$.cleanup.push(J);else $.cleanup=[$.cleanup,J]}function O$($){if(!$.cleanup)return;if(Array.isArray($.cleanup))for(let J=0;J<$.cleanup.length;J++)$.cleanup[J]();else $.cleanup();$.cleanup=null}function v$($){let J=m;m=$,$.sourcesTail=null,$.flags=U$;let z=!1;try{let X=$.fn($.value);if($.error||!$.equals(X,$.value))$.value=X,$.error=void 0,z=!0}catch(X){z=!0,$.error=X instanceof Error?X:Error(String(X))}finally{m=J,H$($)}if(z){for(let X=$.sinks;X;X=X.nextSink)if(X.sink.flags&$$)X.sink.flags|=G}$.flags=p}function c$($){$.controller?.abort();let J=new AbortController;$.controller=J,$.error=void 0;let z=m;m=$,$.sourcesTail=null,$.flags=U$;let X;try{X=$.fn($.value,J.signal)}catch(W){$.controller=void 0,$.error=W instanceof Error?W:Error(String(W));return}finally{m=z,H$($)}X.then((W)=>{if(J.signal.aborted)return;if($.controller=void 0,$.error||!$.equals(W,$.value)){$.value=W,$.error=void 0;for(let Q=$.sinks;Q;Q=Q.nextSink)F(Q.sink);if(x===0)I()}},(W)=>{if(J.signal.aborted)return;$.controller=void 0;let Q=W instanceof Error?W:Error(String(W));if(!$.error||Q.name!==$.error.name||Q.message!==$.error.message){$.error=Q;for(let D=$.sinks;D;D=D.nextSink)F(D.sink);if(x===0)I()}}),$.flags=p}function T$($){O$($);let J=m,z=_;m=_=$,$.sourcesTail=null,$.flags=U$;try{let X=$.fn();if(typeof X==="function")J$($,X)}finally{m=J,_=z,H$($)}$.flags=p}function f($){if($.flags&$$)for(let J=$.sources;J;J=J.nextSource){if("fn"in J.source)f(J.source);if($.flags&G)break}if($.flags&U$)throw new Z$("controller"in $?d:("value"in $)?u:"Effect");if($.flags&G)if("controller"in $)c$($);else if("value"in $)v$($);else T$($);else $.flags=p}function I(){if(_$)return;_$=!0;try{for(let $=0;$<C$.length;$++){let J=C$[$];if(J.flags&(G|$$))f(J)}C$.length=0}finally{_$=!1}}function z$($){x++;try{$()}finally{if(x--,x===0)I()}}function v($){let J=m;m=null;try{return $()}finally{m=J}}function u$($){let J=_,z={cleanup:null};_=z;try{let X=$();if(typeof X==="function")J$(z,X);let W=()=>O$(z);if(J)J$(J,W);return W}finally{_=J}}function d$($){let J=_;_=null;try{return $()}finally{_=J}}function y($,J){O(c,$,J?.guard);let z={value:$,sinks:null,sinksTail:null,equals:J?.equals??k,guard:J?.guard};return{[Symbol.toStringTag]:c,get(){if(m)R(z,m);return z.value},set(X){O(c,X,z.guard),m$(z,X)},update(X){E(c,X);let W=X(z.value);O(c,W,z.guard),m$(z,W)}}}function N$($){return Y($,c)}function n($,J,z){if(Object.is($,J))return!0;if(typeof $!==typeof J)return!1;if($==null||typeof $!=="object"||J==null||typeof J!=="object")return!1;if(!z)z=new WeakSet;if(z.has($)||z.has(J))throw new Z$("isEqual");z.add($),z.add(J);try{let X=Array.isArray($);if(X!==Array.isArray(J))return!1;if(X){let W=$,Q=J;if(W.length!==Q.length)return!1;for(let D=0;D<W.length;D++)if(!n(W[D],Q[D],z))return!1;return!0}if(T($)&&T(J)){let W=Object.keys($),Q=Object.keys(J);if(W.length!==Q.length)return!1;for(let D of W){if(!(D in J))return!1;if(!n($[D],J[D],z))return!1}return!0}return!1}finally{z.delete($),z.delete(J)}}function K$($,J){if($.length!==J.length)return!1;for(let z=0;z<$.length;z++)if($[z]!==J[z])return!1;return!0}function E$($){let J=0,z=typeof $==="function";return[typeof $==="string"?()=>`${$}${J++}`:z?(X)=>$(X)||String(J++):()=>String(J++),z]}function t$($,J,z,X,W){let Q=new WeakSet,D={},M={},C={},U=[],H=!1,j=new Map;for(let q=0;q<$.length;q++){let Z=z[q];if(Z&&$[q])j.set(Z,$[q])}let P=new Set;for(let q=0;q<J.length;q++){let Z=J[q];if(Z===void 0)continue;let B=W?X(Z):z[q]??X(Z);if(P.has(B))throw new e(S,B,Z);if(U.push(B),P.add(B),!j.has(B))D[B]=Z,H=!0;else if(!n(j.get(B),Z,Q))M[B]=Z,H=!0}for(let[q]of j)if(!P.has(q))C[q]=null,H=!0;if(!H&&!K$(z,U))H=!0;return{add:D,change:M,remove:C,newKeys:U,changed:H}}function Q$($,J){O(S,$,Array.isArray);let z=new Map,X=[],[W,Q]=E$(J?.keyConfig),D=()=>X.map((Z)=>z.get(Z)?.get()).filter((Z)=>Z!==void 0),M={fn:D,value:$,flags:G,sources:null,sourcesTail:null,sinks:null,sinksTail:null,equals:n,error:void 0},C=(Z)=>{let B={};for(let N=0;N<Z.length;N++){let V=Z[N];if(V===void 0)continue;let K=X[N];if(!K)K=W(V),X[N]=K;B[K]=V}return B},U=(Z)=>{let B=!1;for(let N in Z.add){let V=Z.add[N];O(`${S} item for key "${N}"`,V),z.set(N,y(V)),B=!0}if(Object.keys(Z.change).length)z$(()=>{for(let N in Z.change){let V=Z.change[N];O(`${S} item for key "${N}"`,V);let K=z.get(N);if(K)K.set(V)}});for(let N in Z.remove){z.delete(N);let V=X.indexOf(N);if(V!==-1)X.splice(V,1);B=!0}if(B)M.flags|=b;return Z.changed},H=J?.watched,j=H?()=>{if(m){if(!M.sinks)M.stop=H();R(M,m)}}:()=>{if(m)R(M,m)},P=C($);for(let Z in P){let B=P[Z];O(`${S} item for key "${Z}"`,B),z.set(Z,y(B))}M.value=$,M.flags=0;let q={[Symbol.toStringTag]:S,[Symbol.isConcatSpreadable]:!0,*[Symbol.iterator](){for(let Z of X){let B=z.get(Z);if(B)yield B}},get length(){return j(),X.length},get(){if(j(),M.sources){if(M.flags){let Z=M.flags&b;if(M.value=v(D),Z){if(M.flags=G,f(M),M.error)throw M.error}else M.flags=p}}else if(f(M),M.error)throw M.error;return M.value},set(Z){let B=M.flags&G?D():M.value,N=t$(B,Z,X,W,Q);if(N.changed){X=N.newKeys,U(N),M.flags|=G;for(let V=M.sinks;V;V=V.nextSink)F(V.sink);if(x===0)I()}},update(Z){q.set(Z(q.get()))},at(Z){return z.get(X[Z])},keys(){return j(),X.values()},byKey(Z){return z.get(Z)},keyAt(Z){return X[Z]},indexOfKey(Z){return X.indexOf(Z)},add(Z){let B=W(Z);if(z.has(B))throw new e(S,B,Z);if(!X.includes(B))X.push(B);O(`${S} item for key "${B}"`,Z),z.set(B,y(Z)),M.flags|=G|b;for(let N=M.sinks;N;N=N.nextSink)F(N.sink);if(x===0)I();return B},remove(Z){let B=typeof Z==="number"?X[Z]:Z;if(z.delete(B)){let V=typeof Z==="number"?Z:X.indexOf(B);if(V>=0)X.splice(V,1);M.flags|=G|b;for(let K=M.sinks;K;K=K.nextSink)F(K.sink);if(x===0)I()}},sort(Z){let N=X.map((V)=>[V,z.get(V)?.get()]).sort(g(Z)?(V,K)=>Z(V[1],K[1]):(V,K)=>String(V[1]).localeCompare(String(K[1]))).map(([V])=>V);if(!K$(X,N)){X=N,M.flags|=G;for(let V=M.sinks;V;V=V.nextSink)F(V.sink);if(x===0)I()}},splice(Z,B,...N){let V=X.length,K=Z<0?Math.max(0,V+Z):Math.min(Z,V),w=Math.max(0,Math.min(B??Math.max(0,V-Math.max(0,K)),V-K)),A={},L={};for(let h=0;h<w;h++){let a=K+h,w$=X[a];if(w$){let y$=z.get(w$);if(y$)L[w$]=y$.get()}}let f$=X.slice(0,K);for(let h of N){let a=W(h);if(z.has(a)&&!(a in L))throw new e(S,a,h);f$.push(a),A[a]=h}f$.push(...X.slice(K+w));let h$=!!(Object.keys(A).length||Object.keys(L).length);if(h$){U({add:A,change:{},remove:L,changed:h$}),X=f$,M.flags|=G;for(let h=M.sinks;h;h=h.nextSink)F(h.sink);if(x===0)I()}return Object.values(L)},deriveCollection(Z){return x$(q,Z)}};return q}function R$($){return Y($,S)}function B$($,J){if(E(u,$,X$),J?.value!==void 0)O(u,J.value,J?.guard);let z={fn:$,value:J?.value,flags:G,sources:null,sourcesTail:null,sinks:null,sinksTail:null,equals:J?.equals??k,error:void 0,stop:void 0},X=J?.watched,W=X?()=>{if(m){if(!z.sinks)z.stop=X(()=>{if(F(z),x===0)I()});R(z,m)}}:()=>{if(m)R(z,m)};return{[Symbol.toStringTag]:u,get(){if(W(),f(z),z.error)throw z.error;return W$(u,z.value),z.value}}}function S$($){return Y($,u)}function q$($,J){if(E(d,$,o),J?.value!==void 0)O(d,J.value,J?.guard);let z={fn:$,value:J?.value,sources:null,sourcesTail:null,sinks:null,sinksTail:null,flags:G,equals:J?.equals??k,controller:void 0,error:void 0,stop:void 0},X=J?.watched,W=X?()=>{if(m){if(!z.sinks)z.stop=X(()=>{if(F(z),x===0)I()});R(z,m)}}:()=>{if(m)R(z,m)};return{[Symbol.toStringTag]:d,get(){if(W(),f(z),z.error)throw z.error;return W$(d,z.value),z.value},isPending(){return!!z.controller},abort(){z.controller?.abort(),z.controller=void 0}}}function p$($){return Y($,d)}function x$($,J){E(s,J);let z=o(J),X=new Map,W=[],Q=(q)=>{let Z=z?q$(async(B,N)=>{let V=$.byKey(q)?.get();if(V==null)return B;return J(V,N)}):B$(()=>{let B=$.byKey(q)?.get();if(B==null)return;return J(B)});X.set(q,Z)};function D(q){if(!K$(W,q)){let Z=new Set(W),B=new Set(q);for(let N of W)if(!B.has(N))X.delete(N);for(let N of q)if(!Z.has(N))Q(N);W=q,U.flags|=b}}function M(){D(Array.from($.keys()));let q=[];for(let Z of W)try{let B=X.get(Z)?.get();if(B!=null)q.push(B)}catch(B){if(!(B instanceof i))throw B}return q}let U={fn:M,value:[],flags:G,sources:null,sourcesTail:null,sinks:null,sinksTail:null,equals:(q,Z)=>{if(q.length!==Z.length)return!1;for(let B=0;B<q.length;B++)if(q[B]!==Z[B])return!1;return!0},error:void 0};function H(){if(U.sources){if(U.flags)if(U.value=v(M),U.flags&b){if(U.flags=G,f(U),U.error)throw U.error}else U.flags=p}else if(U.sinks){if(f(U),U.error)throw U.error}else U.value=v(M)}let j=Array.from(v(()=>$.keys()));for(let q of j)Q(q);W=j;let P={[Symbol.toStringTag]:s,[Symbol.isConcatSpreadable]:!0,*[Symbol.iterator](){for(let q of W){let Z=X.get(q);if(Z)yield Z}},get length(){if(m)R(U,m);return H(),W.length},keys(){if(m)R(U,m);return H(),W.values()},get(){if(m)R(U,m);return H(),U.value},at(q){return X.get(W[q])},byKey(q){return X.get(q)},keyAt(q){return W[q]},indexOfKey(q){return W.indexOf(q)},deriveCollection(q){return x$(P,q)}};return P}function s$($,J){let z=J?.value??[];if(z.length)O(s,z,Array.isArray);E(s,$,X$);let X=new Map,W=[],Q=new Map,[D,M]=E$(J?.keyConfig),C=(Z)=>Q.get(Z)??(M?D(Z):void 0),U=J?.createItem??y;function H(){let Z=[];for(let B of W)try{let N=X.get(B)?.get();if(N!=null)Z.push(N)}catch(N){if(!(N instanceof i))throw N}return Z}let j={fn:H,value:z,flags:G,sources:null,sourcesTail:null,sinks:null,sinksTail:null,equals:L$,error:void 0};for(let Z of z){let B=D(Z);X.set(B,U(Z)),Q.set(Z,B),W.push(B)}j.value=z,j.flags=G;function P(){if(m){if(!j.sinks)j.stop=$((Z)=>{let{add:B,change:N,remove:V}=Z;if(!B?.length&&!N?.length&&!V?.length)return;let K=!1;z$(()=>{if(B)for(let w of B){let A=D(w);if(X.set(A,U(w)),Q.set(w,A),!W.includes(A))W.push(A);K=!0}if(N)for(let w of N){let A=C(w);if(!A)continue;let L=X.get(A);if(L&&N$(L))Q.delete(L.get()),L.set(w),Q.set(w,A)}if(V)for(let w of V){let A=C(w);if(!A)continue;Q.delete(w),X.delete(A);let L=W.indexOf(A);if(L!==-1)W.splice(L,1);K=!0}j.flags=G|(K?b:0);for(let w=j.sinks;w;w=w.nextSink)F(w.sink)})});R(j,m)}}let q={[Symbol.toStringTag]:s,[Symbol.isConcatSpreadable]:!0,*[Symbol.iterator](){for(let Z of W){let B=X.get(Z);if(B)yield B}},get length(){return P(),W.length},keys(){return P(),W.values()},get(){if(P(),j.sources){if(j.flags){let Z=j.flags&b;if(j.value=v(H),Z){if(j.flags=G,f(j),j.error)throw j.error}else j.flags=p}}else if(f(j),j.error)throw j.error;return j.value},at(Z){return X.get(W[Z])},byKey(Z){return X.get(Z)},keyAt(Z){return W[Z]},indexOfKey(Z){return W.indexOf(Z)},deriveCollection(Z){return x$(q,Z)}};return q}function l$($){return Y($,s)}function r$($){E("Effect",$);let J={fn:$,flags:G,sources:null,sourcesTail:null,cleanup:null},z=()=>{O$(J),J.fn=void 0,J.flags=p,J.sourcesTail=null,H$(J)};if(_)J$(_,z);return T$(J),z}function o$($,J){if(!_)throw new G$("match");let{ok:z,err:X=console.error,nil:W}=J,Q,D=!1,M=Array($.length);for(let U=0;U<$.length;U++)try{M[U]=$[U].get()}catch(H){if(H instanceof i){D=!0;continue}if(!Q)Q=[];Q.push(H instanceof Error?H:Error(String(H)))}let C;try{if(D)C=W?.();else if(Q)C=X(Q);else C=z(M)}catch(U){X([U instanceof Error?U:Error(String(U))])}if(typeof C==="function")return C;if(C instanceof Promise){let U=_,H=new AbortController;J$(U,()=>H.abort()),C.then((j)=>{if(!H.signal.aborted&&typeof j==="function")J$(U,j)}).catch((j)=>{X([j instanceof Error?j:Error(String(j))])})}}function i$($,J){if(E(t,$,X$),J?.value!==void 0)O(t,J.value,J?.guard);let z={value:J?.value,sinks:null,sinksTail:null,equals:J?.equals??k,guard:J?.guard,stop:void 0};return{[Symbol.toStringTag]:t,get(){if(m){if(!z.sinks)z.stop=$((X)=>{O(t,X,z.guard),m$(z,X)});R(z,m)}return W$(t,z.value),z.value}}}function n$($){return Y($,t)}function a$($,J){let z=T($)||Array.isArray($),X=T(J)||Array.isArray(J);if(!z||!X){let j=!Object.is($,J);return{changed:j,add:j&&X?J:{},change:{},remove:j&&z?$:{}}}let W=new WeakSet,Q={},D={},M={},C=!1,U=Object.keys($),H=Object.keys(J);for(let j of H)if(j in $){if(!n($[j],J[j],W))D[j]=J[j],C=!0}else Q[j]=J[j],C=!0;for(let j of U)if(!(j in J))M[j]=void 0,C=!0;return{add:Q,change:D,remove:M,changed:C}}function V$($,J){O(l,$,T);let z=new Map,X=(H,j)=>{if(O(`${l} for key "${H}"`,j),Array.isArray(j))z.set(H,Q$(j));else if(T(j))z.set(H,V$(j));else z.set(H,y(j))},W=()=>{let H={};return z.forEach((j,P)=>{H[P]=j.get()}),H},Q={fn:W,value:$,flags:G,sources:null,sourcesTail:null,sinks:null,sinksTail:null,equals:n,error:void 0},D=(H)=>{let j=!1;for(let P in H.add)X(P,H.add[P]),j=!0;if(Object.keys(H.change).length)z$(()=>{for(let P in H.change){let q=H.change[P];O(`${l} for key "${P}"`,q);let Z=z.get(P);if(Z)if(T(q)!==F$(Z))X(P,q),j=!0;else Z.set(q)}});for(let P in H.remove)z.delete(P),j=!0;if(j)Q.flags|=b;return H.changed},M=J?.watched,C=M?()=>{if(m){if(!Q.sinks)Q.stop=M();R(Q,m)}}:()=>{if(m)R(Q,m)};for(let H of Object.keys($))X(H,$[H]);let U={[Symbol.toStringTag]:l,[Symbol.isConcatSpreadable]:!1,*[Symbol.iterator](){for(let H of Array.from(z.keys())){let j=z.get(H);if(j)yield[H,j]}},keys(){return C(),z.keys()},byKey(H){return z.get(H)},get(){if(C(),Q.sources){if(Q.flags){let H=Q.flags&b;if(Q.value=v(W),H){if(Q.flags=G,f(Q),Q.error)throw Q.error}else Q.flags=p}}else if(f(Q),Q.error)throw Q.error;return Q.value},set(H){let j=Q.flags&G?W():Q.value,P=a$(j,H);if(D(P)){Q.flags|=G;for(let q=Q.sinks;q;q=q.nextSink)F(q.sink);if(x===0)I()}},update(H){U.set(H(U.get()))},add(H,j){if(z.has(H))throw new e(l,H,j);X(H,j),Q.flags|=G|b;for(let P=Q.sinks;P;P=P.nextSink)F(P.sink);if(x===0)I();return H},remove(H){if(z.delete(H)){Q.flags|=G|b;for(let P=Q.sinks;P;P=P.nextSink)F(P.sink);if(x===0)I()}}};return new Proxy(U,{get(H,j){if(j in H)return Reflect.get(H,j);if(typeof j!=="symbol")return H.byKey(j)},has(H,j){if(j in H)return!0;return H.byKey(String(j))!==void 0},ownKeys(H){return Array.from(H.keys())},getOwnPropertyDescriptor(H,j){if(j in H)return Reflect.getOwnPropertyDescriptor(H,j);if(typeof j==="symbol")return;let P=H.byKey(String(j));return P?{enumerable:!0,configurable:!0,writable:!0,value:P}:void 0}})}function F$($){return Y($,l)}function e$($,J){return o($)?q$($,J):B$($,J)}function $J($){if(M$($))return $;if($==null)throw new j$("createSignal",$);if(o($))return q$($);if(g($))return B$($);if(Y$($))return Q$($);if(T($))return V$($);return y($)}function JJ($){if(I$($))return $;if($==null||g($)||M$($))throw new j$("createMutableSignal",$);if(Y$($))return Q$($);if(T($))return V$($);return y($)}function zJ($){return S$($)||p$($)}function M$($){let J=[c,u,d,t,r,S,s,l],z=Object.prototype.toString.call($).slice(8,-1);return J.includes(z)}function I$($){return N$($)||F$($)||R$($)}function XJ($,J){O(r,$,M$);let z=$,X=J?.guard,W={fn:()=>z.get(),value:void 0,flags:G,sources:null,sourcesTail:null,sinks:null,sinksTail:null,equals:J?.equals??k,error:void 0},Q=()=>{if(m)R(W,m);if(f(W),W.error)throw W.error;return W.value},D=(C)=>{if(!I$(z))throw new P$(r);O(r,C,X),z.set(C)},M=(C)=>{O(r,C,M$),z=C,W.flags|=G;for(let U=W.sinks;U;U=U.nextSink)F(U.sink);if(x===0)I()};return{[Symbol.toStringTag]:r,configurable:!0,enumerable:!0,get:Q,set:D,replace:M,current:()=>z}}function ZJ($){return Y($,r)}export{D$ as valueString,v as untrack,d$ as unown,o$ as match,p$ as isTask,F$ as isStore,N$ as isState,ZJ as isSlot,M$ as isSignal,n$ as isSensor,T as isRecord,Y as isObjectOfType,I$ as isMutableSignal,S$ as isMemo,R$ as isList,g as isFunction,n as isEqual,zJ as isComputed,l$ as isCollection,o as isAsyncFunction,q$ as createTask,V$ as createStore,y as createState,XJ as createSlot,$J as createSignal,i$ as createSensor,u$ as createScope,JJ as createMutableSignal,B$ as createMemo,Q$ as createList,r$ as createEffect,e$ as createComputed,s$ as createCollection,z$ as batch,i as UnsetSignalValueError,L$ as SKIP_EQUALITY,G$ as RequiredOwnerError,P$ as ReadonlySignalError,A$ as NullishSignalValueError,j$ as InvalidSignalValueError,b$ as InvalidCallbackError,Z$ as CircularDependencyError};
|
package/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @name Cause & Effect
|
|
3
|
-
* @version 0.18.
|
|
3
|
+
* @version 0.18.5
|
|
4
4
|
* @author Esther Brunner
|
|
5
5
|
*/
|
|
6
6
|
|
|
@@ -26,6 +26,7 @@ export {
|
|
|
26
26
|
type SignalOptions,
|
|
27
27
|
SKIP_EQUALITY,
|
|
28
28
|
type TaskCallback,
|
|
29
|
+
unown,
|
|
29
30
|
untrack,
|
|
30
31
|
} from './src/graph'
|
|
31
32
|
export {
|
package/package.json
CHANGED
package/src/graph.ts
CHANGED
|
@@ -292,11 +292,12 @@ function propagate(node: SinkNode, newFlag = FLAG_DIRTY): void {
|
|
|
292
292
|
for (let e = node.sinks; e; e = e.nextSink)
|
|
293
293
|
propagate(e.sink, FLAG_CHECK)
|
|
294
294
|
} else {
|
|
295
|
-
if (flags & FLAG_DIRTY) return
|
|
295
|
+
if ((flags & (FLAG_DIRTY | FLAG_CHECK)) >= newFlag) return
|
|
296
296
|
|
|
297
297
|
// Enqueue effect for later execution
|
|
298
|
-
|
|
299
|
-
|
|
298
|
+
const wasQueued = flags & (FLAG_DIRTY | FLAG_CHECK)
|
|
299
|
+
node.flags = newFlag
|
|
300
|
+
if (!wasQueued) queuedEffects.push(node as EffectNode)
|
|
300
301
|
}
|
|
301
302
|
}
|
|
302
303
|
|
|
@@ -471,7 +472,7 @@ function flush(): void {
|
|
|
471
472
|
try {
|
|
472
473
|
for (let i = 0; i < queuedEffects.length; i++) {
|
|
473
474
|
const effect = queuedEffects[i]
|
|
474
|
-
if (effect.flags & FLAG_DIRTY) refresh(effect)
|
|
475
|
+
if (effect.flags & (FLAG_DIRTY | FLAG_CHECK)) refresh(effect)
|
|
475
476
|
}
|
|
476
477
|
queuedEffects.length = 0
|
|
477
478
|
} finally {
|
|
@@ -579,6 +580,25 @@ function createScope(fn: () => MaybeCleanup): Cleanup {
|
|
|
579
580
|
}
|
|
580
581
|
}
|
|
581
582
|
|
|
583
|
+
/**
|
|
584
|
+
* Runs a callback without any active owner.
|
|
585
|
+
* Any scopes or effects created inside the callback will not be registered as
|
|
586
|
+
* children of the current active owner (e.g. a re-runnable effect). Use this
|
|
587
|
+
* when a component or resource manages its own lifecycle independently of the
|
|
588
|
+
* reactive graph.
|
|
589
|
+
*
|
|
590
|
+
* @since 0.18.5
|
|
591
|
+
*/
|
|
592
|
+
function unown<T>(fn: () => T): T {
|
|
593
|
+
const prev = activeOwner
|
|
594
|
+
activeOwner = null
|
|
595
|
+
try {
|
|
596
|
+
return fn()
|
|
597
|
+
} finally {
|
|
598
|
+
activeOwner = prev
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
582
602
|
export {
|
|
583
603
|
type Cleanup,
|
|
584
604
|
type ComputedOptions,
|
|
@@ -601,6 +621,7 @@ export {
|
|
|
601
621
|
createScope,
|
|
602
622
|
DEFAULT_EQUALITY,
|
|
603
623
|
SKIP_EQUALITY,
|
|
624
|
+
FLAG_CHECK,
|
|
604
625
|
FLAG_CLEAN,
|
|
605
626
|
FLAG_DIRTY,
|
|
606
627
|
FLAG_RELINK,
|
|
@@ -622,5 +643,6 @@ export {
|
|
|
622
643
|
TYPE_STORE,
|
|
623
644
|
TYPE_TASK,
|
|
624
645
|
unlink,
|
|
646
|
+
unown,
|
|
625
647
|
untrack,
|
|
626
648
|
}
|
package/src/nodes/memo.ts
CHANGED
|
@@ -110,9 +110,7 @@ function createMemo<T extends {}>(
|
|
|
110
110
|
if (activeSink) {
|
|
111
111
|
if (!node.sinks)
|
|
112
112
|
node.stop = watched(() => {
|
|
113
|
-
node
|
|
114
|
-
for (let e = node.sinks; e; e = e.nextSink)
|
|
115
|
-
propagate(e.sink)
|
|
113
|
+
propagate(node as unknown as SinkNode)
|
|
116
114
|
if (batchDepth === 0) flush()
|
|
117
115
|
})
|
|
118
116
|
link(node, activeSink)
|
package/src/nodes/task.ts
CHANGED
|
@@ -129,9 +129,7 @@ function createTask<T extends {}>(
|
|
|
129
129
|
if (activeSink) {
|
|
130
130
|
if (!node.sinks)
|
|
131
131
|
node.stop = watched(() => {
|
|
132
|
-
node
|
|
133
|
-
for (let e = node.sinks; e; e = e.nextSink)
|
|
134
|
-
propagate(e.sink)
|
|
132
|
+
propagate(node as unknown as SinkNode)
|
|
135
133
|
if (batchDepth === 0) flush()
|
|
136
134
|
})
|
|
137
135
|
link(node, activeSink)
|
package/test/effect.test.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { describe, expect, mock, test } from 'bun:test'
|
|
2
2
|
import {
|
|
3
|
+
batch,
|
|
3
4
|
createEffect,
|
|
4
5
|
createMemo,
|
|
5
6
|
createScope,
|
|
@@ -140,6 +141,209 @@ describe('createEffect', () => {
|
|
|
140
141
|
})
|
|
141
142
|
})
|
|
142
143
|
|
|
144
|
+
describe('Watched memo equality', () => {
|
|
145
|
+
test('should skip effect re-run when watched memo recomputes to same value', () => {
|
|
146
|
+
let invalidate!: () => void
|
|
147
|
+
let effectCount = 0
|
|
148
|
+
|
|
149
|
+
// Memo whose computed value does not change on invalidation
|
|
150
|
+
const memo = createMemo(() => 42, {
|
|
151
|
+
value: 42,
|
|
152
|
+
watched: inv => {
|
|
153
|
+
invalidate = inv
|
|
154
|
+
return () => {}
|
|
155
|
+
},
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
const dispose = createScope(() => {
|
|
159
|
+
createEffect(() => {
|
|
160
|
+
void memo.get()
|
|
161
|
+
effectCount++
|
|
162
|
+
})
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
expect(effectCount).toBe(1)
|
|
166
|
+
|
|
167
|
+
// Invalidate — memo recomputes but returns same value (42)
|
|
168
|
+
invalidate()
|
|
169
|
+
|
|
170
|
+
// Because equals(42, 42) is true, the effect should NOT re-run
|
|
171
|
+
expect(effectCount).toBe(1)
|
|
172
|
+
|
|
173
|
+
dispose()
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
test('should re-run effect when watched memo recomputes to different value', () => {
|
|
177
|
+
let invalidate!: () => void
|
|
178
|
+
let effectCount = 0
|
|
179
|
+
let externalValue = 1
|
|
180
|
+
|
|
181
|
+
const memo = createMemo(() => externalValue, {
|
|
182
|
+
value: 0,
|
|
183
|
+
watched: inv => {
|
|
184
|
+
invalidate = inv
|
|
185
|
+
return () => {}
|
|
186
|
+
},
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
let observed = 0
|
|
190
|
+
const dispose = createScope(() => {
|
|
191
|
+
createEffect(() => {
|
|
192
|
+
observed = memo.get()
|
|
193
|
+
effectCount++
|
|
194
|
+
})
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
expect(effectCount).toBe(1)
|
|
198
|
+
expect(observed).toBe(1)
|
|
199
|
+
|
|
200
|
+
// Change external value and invalidate — memo returns a new value
|
|
201
|
+
externalValue = 99
|
|
202
|
+
invalidate()
|
|
203
|
+
|
|
204
|
+
expect(effectCount).toBe(2)
|
|
205
|
+
expect(observed).toBe(99)
|
|
206
|
+
|
|
207
|
+
dispose()
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
test('should respect custom equals to skip effect re-run', () => {
|
|
211
|
+
let invalidate!: () => void
|
|
212
|
+
let effectCount = 0
|
|
213
|
+
let externalValue = 3
|
|
214
|
+
|
|
215
|
+
// Custom equals: treat values as equal when they round to the same integer
|
|
216
|
+
const memo = createMemo(() => externalValue, {
|
|
217
|
+
value: 0,
|
|
218
|
+
equals: (a, b) => Math.floor(a) === Math.floor(b),
|
|
219
|
+
watched: inv => {
|
|
220
|
+
invalidate = inv
|
|
221
|
+
return () => {}
|
|
222
|
+
},
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
const dispose = createScope(() => {
|
|
226
|
+
createEffect(() => {
|
|
227
|
+
void memo.get()
|
|
228
|
+
effectCount++
|
|
229
|
+
})
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
expect(effectCount).toBe(1)
|
|
233
|
+
|
|
234
|
+
// External value changes slightly but rounds to same integer
|
|
235
|
+
externalValue = 3.7
|
|
236
|
+
invalidate()
|
|
237
|
+
expect(effectCount).toBe(1) // equals says same → effect skipped
|
|
238
|
+
|
|
239
|
+
// External value changes to a different integer
|
|
240
|
+
externalValue = 4.1
|
|
241
|
+
invalidate()
|
|
242
|
+
expect(effectCount).toBe(2) // equals says different → effect runs
|
|
243
|
+
|
|
244
|
+
dispose()
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
test('should skip effect re-run through memo chain when watched memo value unchanged', () => {
|
|
248
|
+
let invalidate!: () => void
|
|
249
|
+
let effectCount = 0
|
|
250
|
+
|
|
251
|
+
const watchedMemo = createMemo(() => 42, {
|
|
252
|
+
value: 42,
|
|
253
|
+
watched: inv => {
|
|
254
|
+
invalidate = inv
|
|
255
|
+
return () => {}
|
|
256
|
+
},
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
// Downstream memo that doubles the watched memo value
|
|
260
|
+
const doubled = createMemo(() => watchedMemo.get() * 2)
|
|
261
|
+
|
|
262
|
+
const dispose = createScope(() => {
|
|
263
|
+
createEffect(() => {
|
|
264
|
+
void doubled.get()
|
|
265
|
+
effectCount++
|
|
266
|
+
})
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
expect(effectCount).toBe(1)
|
|
270
|
+
|
|
271
|
+
// Invalidate — watchedMemo recomputes to same value, so doubled
|
|
272
|
+
// should also remain unchanged, and the effect should not re-run
|
|
273
|
+
invalidate()
|
|
274
|
+
expect(effectCount).toBe(1)
|
|
275
|
+
|
|
276
|
+
dispose()
|
|
277
|
+
})
|
|
278
|
+
|
|
279
|
+
test('should skip effect when invalidate is called inside batch and value unchanged', () => {
|
|
280
|
+
let invalidate!: () => void
|
|
281
|
+
let effectCount = 0
|
|
282
|
+
|
|
283
|
+
const memo = createMemo(() => 42, {
|
|
284
|
+
value: 42,
|
|
285
|
+
watched: inv => {
|
|
286
|
+
invalidate = inv
|
|
287
|
+
return () => {}
|
|
288
|
+
},
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
const dispose = createScope(() => {
|
|
292
|
+
createEffect(() => {
|
|
293
|
+
void memo.get()
|
|
294
|
+
effectCount++
|
|
295
|
+
})
|
|
296
|
+
})
|
|
297
|
+
|
|
298
|
+
expect(effectCount).toBe(1)
|
|
299
|
+
|
|
300
|
+
batch(() => {
|
|
301
|
+
invalidate()
|
|
302
|
+
})
|
|
303
|
+
|
|
304
|
+
// Value didn't change so effect should still be at 1
|
|
305
|
+
expect(effectCount).toBe(1)
|
|
306
|
+
|
|
307
|
+
dispose()
|
|
308
|
+
})
|
|
309
|
+
|
|
310
|
+
test('should still run effect for dirty state even when watched memo unchanged', () => {
|
|
311
|
+
let invalidate!: () => void
|
|
312
|
+
let effectCount = 0
|
|
313
|
+
const state = createState(1)
|
|
314
|
+
|
|
315
|
+
const memo = createMemo(() => 42, {
|
|
316
|
+
value: 42,
|
|
317
|
+
watched: inv => {
|
|
318
|
+
invalidate = inv
|
|
319
|
+
return () => {}
|
|
320
|
+
},
|
|
321
|
+
})
|
|
322
|
+
|
|
323
|
+
let observedState = 0
|
|
324
|
+
const dispose = createScope(() => {
|
|
325
|
+
createEffect(() => {
|
|
326
|
+
observedState = state.get()
|
|
327
|
+
void memo.get()
|
|
328
|
+
effectCount++
|
|
329
|
+
})
|
|
330
|
+
})
|
|
331
|
+
|
|
332
|
+
expect(effectCount).toBe(1)
|
|
333
|
+
|
|
334
|
+
// Change the state AND invalidate — effect must run because state changed
|
|
335
|
+
batch(() => {
|
|
336
|
+
state.set(2)
|
|
337
|
+
invalidate()
|
|
338
|
+
})
|
|
339
|
+
|
|
340
|
+
expect(effectCount).toBe(2)
|
|
341
|
+
expect(observedState).toBe(2)
|
|
342
|
+
|
|
343
|
+
dispose()
|
|
344
|
+
})
|
|
345
|
+
})
|
|
346
|
+
|
|
143
347
|
describe('Input Validation', () => {
|
|
144
348
|
test('should throw InvalidCallbackError for non-function', () => {
|
|
145
349
|
// @ts-expect-error - Testing invalid input
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test'
|
|
2
|
+
import {
|
|
3
|
+
createEffect,
|
|
4
|
+
createScope,
|
|
5
|
+
createState,
|
|
6
|
+
unown,
|
|
7
|
+
} from '../index.ts'
|
|
8
|
+
|
|
9
|
+
describe('unown', () => {
|
|
10
|
+
|
|
11
|
+
test('should return the value of the callback', () => {
|
|
12
|
+
const result = unown(() => 42)
|
|
13
|
+
expect(result).toBe(42)
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
test('should run the callback immediately and synchronously', () => {
|
|
17
|
+
let ran = false
|
|
18
|
+
unown(() => { ran = true })
|
|
19
|
+
expect(ran).toBe(true)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
test('scope created inside unown is not registered on the enclosing scope', () => {
|
|
23
|
+
let innerCleanupRan = false
|
|
24
|
+
const outerDispose = createScope(() => {
|
|
25
|
+
unown(() => {
|
|
26
|
+
createScope(() => {
|
|
27
|
+
return () => { innerCleanupRan = true }
|
|
28
|
+
})
|
|
29
|
+
})
|
|
30
|
+
})
|
|
31
|
+
outerDispose()
|
|
32
|
+
expect(innerCleanupRan).toBe(false)
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
test('scope created inside unown is not registered on the enclosing effect', () => {
|
|
36
|
+
const trigger = createState(0)
|
|
37
|
+
let innerCleanupRuns = 0
|
|
38
|
+
|
|
39
|
+
const outerDispose = createScope(() => {
|
|
40
|
+
createEffect((): undefined => {
|
|
41
|
+
trigger.get()
|
|
42
|
+
unown(() => {
|
|
43
|
+
createScope(() => {
|
|
44
|
+
return () => { innerCleanupRuns++ }
|
|
45
|
+
})
|
|
46
|
+
})
|
|
47
|
+
})
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
expect(innerCleanupRuns).toBe(0)
|
|
51
|
+
trigger.set(1)
|
|
52
|
+
expect(innerCleanupRuns).toBe(0)
|
|
53
|
+
trigger.set(2)
|
|
54
|
+
expect(innerCleanupRuns).toBe(0)
|
|
55
|
+
|
|
56
|
+
outerDispose()
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
test('effects inside an unowned scope survive effect re-runs (ownership bug regression)', () => {
|
|
60
|
+
const listChange = createState(0)
|
|
61
|
+
let componentEffectRuns = 0
|
|
62
|
+
let componentCleanupRuns = 0
|
|
63
|
+
|
|
64
|
+
const connectComponent = () => unown(() =>
|
|
65
|
+
createScope(() => {
|
|
66
|
+
createEffect((): undefined => {
|
|
67
|
+
componentEffectRuns++
|
|
68
|
+
})
|
|
69
|
+
return () => { componentCleanupRuns++ }
|
|
70
|
+
})
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
const outerDispose = createScope(() => {
|
|
74
|
+
createEffect((): undefined => {
|
|
75
|
+
listChange.get()
|
|
76
|
+
if (listChange.get() === 0) connectComponent()
|
|
77
|
+
})
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
expect(componentEffectRuns).toBe(1)
|
|
81
|
+
expect(componentCleanupRuns).toBe(0)
|
|
82
|
+
|
|
83
|
+
listChange.set(1)
|
|
84
|
+
expect(componentEffectRuns).toBe(1)
|
|
85
|
+
expect(componentCleanupRuns).toBe(0)
|
|
86
|
+
|
|
87
|
+
outerDispose()
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
test('effects inside an unowned scope still run reactively', () => {
|
|
91
|
+
const source = createState('a')
|
|
92
|
+
let effectRuns = 0
|
|
93
|
+
|
|
94
|
+
const dispose = unown(() =>
|
|
95
|
+
createScope(() => {
|
|
96
|
+
createEffect((): undefined => {
|
|
97
|
+
source.get()
|
|
98
|
+
effectRuns++
|
|
99
|
+
})
|
|
100
|
+
})
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
expect(effectRuns).toBe(1)
|
|
104
|
+
source.set('b')
|
|
105
|
+
expect(effectRuns).toBe(2)
|
|
106
|
+
|
|
107
|
+
dispose()
|
|
108
|
+
source.set('c')
|
|
109
|
+
expect(effectRuns).toBe(2)
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
test('dispose returned from an unowned scope still works', () => {
|
|
113
|
+
let cleanupRan = false
|
|
114
|
+
const dispose = unown(() =>
|
|
115
|
+
createScope(() => {
|
|
116
|
+
return () => { cleanupRan = true }
|
|
117
|
+
})
|
|
118
|
+
)
|
|
119
|
+
expect(cleanupRan).toBe(false)
|
|
120
|
+
dispose()
|
|
121
|
+
expect(cleanupRan).toBe(true)
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
test('nested unown calls work correctly', () => {
|
|
125
|
+
let innerCleanupRan = false
|
|
126
|
+
const outerDispose = createScope(() => {
|
|
127
|
+
unown(() => {
|
|
128
|
+
unown(() => {
|
|
129
|
+
createScope(() => {
|
|
130
|
+
return () => { innerCleanupRan = true }
|
|
131
|
+
})
|
|
132
|
+
})
|
|
133
|
+
})
|
|
134
|
+
})
|
|
135
|
+
outerDispose()
|
|
136
|
+
expect(innerCleanupRan).toBe(false)
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
test('restores the active owner after the callback completes', () => {
|
|
140
|
+
let postCleanupRan = false
|
|
141
|
+
const outerDispose = createScope(() => {
|
|
142
|
+
unown(() => { /* some unowned work */ })
|
|
143
|
+
createScope(() => {
|
|
144
|
+
return () => { postCleanupRan = true }
|
|
145
|
+
})
|
|
146
|
+
})
|
|
147
|
+
outerDispose()
|
|
148
|
+
expect(postCleanupRan).toBe(true)
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
test('restores the active owner even if the callback throws', () => {
|
|
152
|
+
let postCleanupRan = false
|
|
153
|
+
const outerDispose = createScope(() => {
|
|
154
|
+
try {
|
|
155
|
+
unown(() => { throw new Error('boom') })
|
|
156
|
+
} catch {
|
|
157
|
+
// swallow
|
|
158
|
+
}
|
|
159
|
+
createScope(() => {
|
|
160
|
+
return () => { postCleanupRan = true }
|
|
161
|
+
})
|
|
162
|
+
})
|
|
163
|
+
outerDispose()
|
|
164
|
+
expect(postCleanupRan).toBe(true)
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
test('works correctly when called outside any scope or effect', () => {
|
|
168
|
+
let ran = false
|
|
169
|
+
const dispose = unown(() => {
|
|
170
|
+
ran = true
|
|
171
|
+
return createScope(() => {
|
|
172
|
+
return () => {}
|
|
173
|
+
})
|
|
174
|
+
})
|
|
175
|
+
expect(ran).toBe(true)
|
|
176
|
+
expect(typeof dispose).toBe('function')
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
})
|