@zeix/cause-effect 0.18.4 → 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/CHANGELOG.md +10 -0
- package/CLAUDE.md +36 -397
- package/OWNERSHIP_BUG.md +95 -0
- package/README.md +1 -1
- package/index.dev.js +10 -0
- package/index.js +1 -1
- package/index.ts +2 -1
- package/package.json +1 -1
- package/src/graph.ts +20 -0
- package/test/unown.test.ts +179 -0
- package/types/index.d.ts +2 -2
- package/types/src/graph.d.ts +11 -1
- package/.ai-context.md +0 -281
- package/examples/events-sensor.ts +0 -187
- package/examples/selector-sensor.ts +0 -173
package/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function g($){return typeof $==="function"}function i($){return g($)&&$.constructor.name==="AsyncFunction"}function X$($){return g($)&&$.constructor.name!=="AsyncFunction"}function Y($,J){return Object.prototype.toString.call($)===`[object ${J}]`}function L($){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 o 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 C($,J,z){if(J==null)throw new A$($);if(z&&!z(J))throw new j$($,J)}function W$($,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,$$=1,G=2,U$=4,b=8,N=null,y=null,O$=[],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)O$.push($)}}function N$($,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 C$($){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=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{N=J,H$($)}if(z){for(let X=$.sinks;X;X=X.nextSink)if(X.sink.flags&$$)X.sink.flags|=G}$.flags=S}function c$($){$.controller?.abort();let J=new AbortController;$.controller=J,$.error=void 0;let z=N;N=$,$.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{N=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=S}function T$($){C$($);let J=N,z=y;N=y=$,$.sourcesTail=null,$.flags=U$;try{let X=$.fn();if(typeof X==="function")J$($,X)}finally{N=J,y=z,H$($)}$.flags=S}function w($){if($.flags&$$)for(let J=$.sources;J;J=J.nextSource){if("fn"in J.source)w(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=S}function I(){if(_$)return;_$=!0;try{for(let $=0;$<O$.length;$++){let J=O$[$];if(J.flags&(G|$$))w(J)}O$.length=0}finally{_$=!1}}function z$($){x++;try{$()}finally{if(x--,x===0)I()}}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")J$(z,X);let W=()=>C$(z);if(J)J$(J,W);return W}finally{y=J}}function p($,J){C(c,$,J?.guard);let z={value:$,sinks:null,sinksTail:null,equals:J?.equals??k,guard:J?.guard};return{[Symbol.toStringTag]:c,get(){if(N)R(z,N);return z.value},set(X){C(c,X,z.guard),N$(z,X)},update(X){T(c,X);let W=X(z.value);C(c,W,z.guard),N$(z,W)}}}function V$($){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(L($)&&L(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 d$($,J,z,X,W){let Q=new WeakSet,D={},M={},O={},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(E,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))O[q]=null,H=!0;if(!H&&!K$(z,U))H=!0;return{add:D,change:M,remove:O,newKeys:U,changed:H}}function Q$($,J){C(E,$,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},O=(Z)=>{let B={};for(let V=0;V<Z.length;V++){let m=Z[V];if(m===void 0)continue;let K=X[V];if(!K)K=W(m),X[V]=K;B[K]=m}return B},U=(Z)=>{let B=!1;for(let V in Z.add){let m=Z.add[V];C(`${E} item for key "${V}"`,m),z.set(V,p(m)),B=!0}if(Object.keys(Z.change).length)z$(()=>{for(let V in Z.change){let m=Z.change[V];C(`${E} item for key "${V}"`,m);let K=z.get(V);if(K)K.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},H=J?.watched,j=H?()=>{if(N){if(!M.sinks)M.stop=H();R(M,N)}}:()=>{if(N)R(M,N)},P=O($);for(let Z in P){let B=P[Z];C(`${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(D),Z){if(M.flags=G,w(M),M.error)throw M.error}else M.flags=S}}else if(w(M),M.error)throw M.error;return M.value},set(Z){let B=M.flags&G?D():M.value,V=d$(B,Z,X,W,Q);if(V.changed){X=V.newKeys,U(V),M.flags|=G;for(let m=M.sinks;m;m=m.nextSink)F(m.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(E,B,Z);if(!X.includes(B))X.push(B);C(`${E} item for key "${B}"`,Z),z.set(B,p(Z)),M.flags|=G|b;for(let V=M.sinks;V;V=V.nextSink)F(V.sink);if(x===0)I();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|=G|b;for(let K=M.sinks;K;K=K.nextSink)F(K.sink);if(x===0)I()}},sort(Z){let V=X.map((m)=>[m,z.get(m)?.get()]).sort(g(Z)?(m,K)=>Z(m[1],K[1]):(m,K)=>String(m[1]).localeCompare(String(K[1]))).map(([m])=>m);if(!K$(X,V)){X=V,M.flags|=G;for(let m=M.sinks;m;m=m.nextSink)F(m.sink);if(x===0)I()}},splice(Z,B,...V){let m=X.length,K=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,K)),m-K)),A={},_={};for(let h=0;h<f;h++){let a=K+h,f$=X[a];if(f$){let y$=z.get(f$);if(y$)_[f$]=y$.get()}}let w$=X.slice(0,K);for(let h of V){let a=W(h);if(z.has(a)&&!(a in _))throw new e(E,a,h);w$.push(a),A[a]=h}w$.push(...X.slice(K+f));let p$=!!(Object.keys(A).length||Object.keys(_).length);if(p$){U({add:A,change:{},remove:_,changed:p$}),X=w$,M.flags|=G;for(let h=M.sinks;h;h=h.nextSink)F(h.sink);if(x===0)I()}return Object.values(_)},deriveCollection(Z){return x$(q,Z)}};return q}function R$($){return Y($,E)}function B$($,J){if(T(u,$,X$),J?.value!==void 0)C(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(N){if(!z.sinks)z.stop=X(()=>{if(F(z),x===0)I()});R(z,N)}}:()=>{if(N)R(z,N)};return{[Symbol.toStringTag]:u,get(){if(W(),w(z),z.error)throw z.error;return W$(u,z.value),z.value}}}function S$($){return Y($,u)}function q$($,J){if(T(d,$,i),J?.value!==void 0)C(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(N){if(!z.sinks)z.stop=X(()=>{if(F(z),x===0)I()});R(z,N)}}:()=>{if(N)R(z,N)};return{[Symbol.toStringTag]:d,get(){if(W(),w(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 h$($){return Y($,d)}function x$($,J){T(l,J);let z=i(J),X=new Map,W=[],Q=(q)=>{let Z=z?q$(async(B,V)=>{let m=$.byKey(q)?.get();if(m==null)return B;return J(m,V)}):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 V of W)if(!B.has(V))X.delete(V);for(let V of q)if(!Z.has(V))Q(V);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 o))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,w(U),U.error)throw U.error}else U.flags=S}else if(U.sinks){if(w(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]:l,[Symbol.isConcatSpreadable]:!0,*[Symbol.iterator](){for(let q of W){let Z=X.get(q);if(Z)yield Z}},get length(){if(N)R(U,N);return H(),W.length},keys(){if(N)R(U,N);return H(),W.values()},get(){if(N)R(U,N);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 t$($,J){let z=J?.value??[];if(z.length)C(l,z,Array.isArray);T(l,$,X$);let X=new Map,W=[],Q=new Map,[D,M]=E$(J?.keyConfig),O=(Z)=>Q.get(Z)??(M?D(Z):void 0),U=J?.createItem??p;function H(){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: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(N){if(!j.sinks)j.stop=$((Z)=>{let{add:B,change:V,remove:m}=Z;if(!B?.length&&!V?.length&&!m?.length)return;let K=!1;z$(()=>{if(B)for(let f of B){let A=D(f);if(X.set(A,U(f)),Q.set(f,A),!W.includes(A))W.push(A);K=!0}if(V)for(let f of V){let A=O(f);if(!A)continue;let _=X.get(A);if(_&&V$(_))Q.delete(_.get()),_.set(f),Q.set(f,A)}if(m)for(let f of m){let A=O(f);if(!A)continue;Q.delete(f),X.delete(A);let _=W.indexOf(A);if(_!==-1)W.splice(_,1);K=!0}j.flags=G|(K?b:0);for(let f=j.sinks;f;f=f.nextSink)F(f.sink)})});R(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 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,w(j),j.error)throw j.error}else j.flags=S}}else if(w(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($,l)}function r$($){T("Effect",$);let J={fn:$,flags:G,sources:null,sourcesTail:null,cleanup:null},z=()=>{C$(J),J.fn=void 0,J.flags=S,J.sourcesTail=null,H$(J)};if(y)J$(y,z);return T$(J),z}function s$($,J){if(!y)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 o){D=!0;continue}if(!Q)Q=[];Q.push(H instanceof Error?H:Error(String(H)))}let O;try{if(D)O=W?.();else if(Q)O=X(Q);else O=z(M)}catch(U){X([U instanceof Error?U:Error(String(U))])}if(typeof O==="function")return O;if(O instanceof Promise){let U=y,H=new AbortController;J$(U,()=>H.abort()),O.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(T(t,$,X$),J?.value!==void 0)C(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)=>{C(t,X,z.guard),N$(z,X)});R(z,N)}return W$(t,z.value),z.value}}}function o$($){return Y($,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,Q={},D={},M={},O=!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],O=!0}else Q[j]=J[j],O=!0;for(let j of U)if(!(j in J))M[j]=void 0,O=!0;return{add:Q,change:D,remove:M,changed:O}}function m$($,J){C(r,$,L);let z=new Map,X=(H,j)=>{if(C(`${r} for key "${H}"`,j),Array.isArray(j))z.set(H,Q$(j));else if(L(j))z.set(H,m$(j));else z.set(H,p(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];C(`${r} for key "${P}"`,q);let Z=z.get(P);if(Z)if(L(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,O=M?()=>{if(N){if(!Q.sinks)Q.stop=M();R(Q,N)}}:()=>{if(N)R(Q,N)};for(let H of Object.keys($))X(H,$[H]);let U={[Symbol.toStringTag]:r,[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 O(),z.keys()},byKey(H){return z.get(H)},get(){if(O(),Q.sources){if(Q.flags){let H=Q.flags&b;if(Q.value=v(W),H){if(Q.flags=G,w(Q),Q.error)throw Q.error}else Q.flags=S}}else if(w(Q),Q.error)throw Q.error;return Q.value},set(H){let j=Q.flags&G?W():Q.value,P=n$(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(r,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($,r)}function a$($,J){return i($)?q$($,J):B$($,J)}function e$($){if(M$($))return $;if($==null)throw new j$("createSignal",$);if(i($))return q$($);if(g($))return B$($);if(Y$($))return Q$($);if(L($))return m$($);return p($)}function $J($){if(I$($))return $;if($==null||g($)||M$($))throw new j$("createMutableSignal",$);if(Y$($))return Q$($);if(L($))return m$($);return p($)}function JJ($){return S$($)||h$($)}function M$($){let J=[c,u,d,t,s,E,l,r],z=Object.prototype.toString.call($).slice(8,-1);return J.includes(z)}function I$($){return V$($)||F$($)||R$($)}function zJ($,J){C(s,$,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(N)R(W,N);if(w(W),W.error)throw W.error;return W.value},D=(O)=>{if(!I$(z))throw new P$(s);C(s,O,X),z.set(O)},M=(O)=>{C(s,O,M$),z=O,W.flags|=G;for(let U=W.sinks;U;U=U.nextSink)F(U.sink);if(x===0)I()};return{[Symbol.toStringTag]:s,configurable:!0,enumerable:!0,get:Q,set:D,replace:M,current:()=>z}}function XJ($){return Y($,s)}export{D$ as valueString,v as untrack,s$ as match,h$ as isTask,F$ as isStore,V$ as isState,XJ as isSlot,M$ as isSignal,o$ as isSensor,L as isRecord,Y as isObjectOfType,I$ as isMutableSignal,S$ as isMemo,R$ as isList,g as isFunction,n as isEqual,JJ as isComputed,l$ as isCollection,i as isAsyncFunction,q$ as createTask,m$ as createStore,p as createState,zJ as createSlot,e$ as createSignal,i$ as createSensor,u$ as createScope,$J as createMutableSignal,B$ as createMemo,Q$ as createList,r$ as createEffect,a$ as createComputed,t$ as createCollection,z$ as batch,o as UnsetSignalValueError,L$ as SKIP_EQUALITY,G$ as RequiredOwnerError,P$ as ReadonlySignalError,A$ as NullishSignalValueError,j$ as InvalidSignalValueError,b$ as InvalidCallbackError,Z$ 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
|
@@ -580,6 +580,25 @@ function createScope(fn: () => MaybeCleanup): Cleanup {
|
|
|
580
580
|
}
|
|
581
581
|
}
|
|
582
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
|
+
|
|
583
602
|
export {
|
|
584
603
|
type Cleanup,
|
|
585
604
|
type ComputedOptions,
|
|
@@ -624,5 +643,6 @@ export {
|
|
|
624
643
|
TYPE_STORE,
|
|
625
644
|
TYPE_TASK,
|
|
626
645
|
unlink,
|
|
646
|
+
unown,
|
|
627
647
|
untrack,
|
|
628
648
|
}
|
|
@@ -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
|
+
})
|
package/types/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
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
|
export { CircularDependencyError, type Guard, InvalidCallbackError, InvalidSignalValueError, NullishSignalValueError, ReadonlySignalError, RequiredOwnerError, UnsetSignalValueError, } from './src/errors';
|
|
7
|
-
export { batch, type Cleanup, type ComputedOptions, createScope, type EffectCallback, type MaybeCleanup, type MemoCallback, type Signal, type SignalOptions, SKIP_EQUALITY, type TaskCallback, untrack, } from './src/graph';
|
|
7
|
+
export { batch, type Cleanup, type ComputedOptions, createScope, type EffectCallback, type MaybeCleanup, type MemoCallback, type Signal, type SignalOptions, SKIP_EQUALITY, type TaskCallback, unown, untrack, } from './src/graph';
|
|
8
8
|
export { type Collection, type CollectionCallback, type CollectionChanges, type CollectionOptions, createCollection, type DeriveCollectionCallback, isCollection, } from './src/nodes/collection';
|
|
9
9
|
export { createEffect, type MatchHandlers, type MaybePromise, match, } from './src/nodes/effect';
|
|
10
10
|
export { createList, isEqual, isList, type KeyConfig, type List, type ListOptions, } from './src/nodes/list';
|
package/types/src/graph.d.ts
CHANGED
|
@@ -218,4 +218,14 @@ declare function untrack<T>(fn: () => T): T;
|
|
|
218
218
|
* ```
|
|
219
219
|
*/
|
|
220
220
|
declare function createScope(fn: () => MaybeCleanup): Cleanup;
|
|
221
|
-
|
|
221
|
+
/**
|
|
222
|
+
* Runs a callback without any active owner.
|
|
223
|
+
* Any scopes or effects created inside the callback will not be registered as
|
|
224
|
+
* children of the current active owner (e.g. a re-runnable effect). Use this
|
|
225
|
+
* when a component or resource manages its own lifecycle independently of the
|
|
226
|
+
* reactive graph.
|
|
227
|
+
*
|
|
228
|
+
* @since 0.18.5
|
|
229
|
+
*/
|
|
230
|
+
declare function unown<T>(fn: () => T): T;
|
|
231
|
+
export { type Cleanup, type ComputedOptions, type EffectCallback, type EffectNode, type MaybeCleanup, type MemoCallback, type MemoNode, type Scope, type Signal, type SignalOptions, type SinkNode, type StateNode, type TaskCallback, type TaskNode, activeOwner, activeSink, batch, batchDepth, createScope, DEFAULT_EQUALITY, SKIP_EQUALITY, FLAG_CHECK, FLAG_CLEAN, FLAG_DIRTY, FLAG_RELINK, flush, link, propagate, refresh, registerCleanup, runCleanup, runEffect, setState, trimSources, TYPE_COLLECTION, TYPE_LIST, TYPE_MEMO, TYPE_SENSOR, TYPE_STATE, TYPE_SLOT, TYPE_STORE, TYPE_TASK, unlink, unown, untrack, };
|
package/.ai-context.md
DELETED
|
@@ -1,281 +0,0 @@
|
|
|
1
|
-
# AI Context for Cause & Effect
|
|
2
|
-
|
|
3
|
-
## What is Cause & Effect?
|
|
4
|
-
|
|
5
|
-
Cause & Effect is a modern reactive state management library for JavaScript/TypeScript that implements the signals pattern. It provides fine-grained reactivity with automatic dependency tracking, making it easy to build responsive applications with predictable state updates.
|
|
6
|
-
|
|
7
|
-
## Core Architecture
|
|
8
|
-
|
|
9
|
-
### Graph-Based Reactivity (`src/graph.ts`)
|
|
10
|
-
|
|
11
|
-
The reactive engine is a linked graph of source and sink nodes connected by `Edge` entries:
|
|
12
|
-
- **Sources** (StateNode) maintain a linked list of sink edges
|
|
13
|
-
- **Sinks** (MemoNode, TaskNode, EffectNode) maintain a linked list of source edges
|
|
14
|
-
- `link()` creates edges between sources and sinks during `.get()` calls
|
|
15
|
-
- `propagate()` flags sinks as dirty when sources change
|
|
16
|
-
- `flush()` processes queued effects after propagation
|
|
17
|
-
- `trimSources()` removes stale edges after recomputation
|
|
18
|
-
|
|
19
|
-
### Node Types
|
|
20
|
-
```
|
|
21
|
-
StateNode<T> — source-only with equality + guard (State, Sensor)
|
|
22
|
-
MemoNode<T> — source + sink (Memo, Slot, Store, List, Collection)
|
|
23
|
-
TaskNode<T> — source + sink + async (Task)
|
|
24
|
-
EffectNode — sink + owner (Effect)
|
|
25
|
-
Scope — owner-only (createScope)
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
### Signal Types
|
|
29
|
-
- **State** (`createState`): Mutable signals for primitive values and objects
|
|
30
|
-
- **Sensor** (`createSensor`): Read-only signals for external input streams with automatic state updates. Use `SKIP_EQUALITY` for mutable object observation.
|
|
31
|
-
- **Memo** (`createMemo`): Synchronous derived computations with memoization, reducer capabilities, and optional `watched(invalidate)` for external invalidation
|
|
32
|
-
- **Task** (`createTask`): Async derived computations with automatic abort/cancellation and optional `watched(invalidate)` for external invalidation
|
|
33
|
-
- **Store** (`createStore`): Mutable object signals with individually reactive properties via Proxy
|
|
34
|
-
- **List** (`createList`): Mutable array signals with stable keys and reactive items
|
|
35
|
-
- **Collection** (`createCollection`): Reactive collections — either externally-driven with watched lifecycle, or derived from List/Collection with item-level memoization
|
|
36
|
-
- **Slot** (`createSlot`): Stable delegation signal with swappable backing signal, designed for integration layers (property descriptors, custom elements)
|
|
37
|
-
- **Effect** (`createEffect`): Side effect handlers that react to signal changes
|
|
38
|
-
|
|
39
|
-
### Key Principles
|
|
40
|
-
1. **Functional API**: All signals created via `create*()` factory functions (no classes)
|
|
41
|
-
2. **Type Safety**: Full TypeScript support with strict type constraints (`T extends {}`)
|
|
42
|
-
3. **Performance**: Flag-based dirty checking, linked-list edge traversal, batched flushing
|
|
43
|
-
4. **Async Support**: Built-in cancellation with AbortSignal in Tasks
|
|
44
|
-
5. **Tree-shaking**: Optimized for minimal bundle size with `/*#__PURE__*/` annotations
|
|
45
|
-
|
|
46
|
-
## Project Structure
|
|
47
|
-
|
|
48
|
-
```
|
|
49
|
-
cause-effect/
|
|
50
|
-
├── src/
|
|
51
|
-
│ ├── graph.ts # Core reactive engine (nodes, edges, link, propagate, flush, batch)
|
|
52
|
-
│ ├── nodes/
|
|
53
|
-
│ │ ├── state.ts # createState — mutable state signals
|
|
54
|
-
│ │ ├── sensor.ts # createSensor — external input tracking (also covers mutable object observation)
|
|
55
|
-
│ │ ├── memo.ts # createMemo — synchronous derived computations
|
|
56
|
-
│ │ ├── task.ts # createTask — async derived computations
|
|
57
|
-
│ │ ├── effect.ts # createEffect, match — side effects
|
|
58
|
-
│ │ ├── store.ts # createStore — reactive object stores
|
|
59
|
-
│ │ ├── list.ts # createList — reactive arrays with stable keys
|
|
60
|
-
│ │ ├── collection.ts # createCollection — externally-driven and derived collections
|
|
61
|
-
│ │ └── slot.ts # createSlot — stable delegation with swappable backing signal
|
|
62
|
-
│ ├── util.ts # Utility functions and type checks
|
|
63
|
-
│ └── ...
|
|
64
|
-
├── index.ts # Entry point / main export file
|
|
65
|
-
├── test/
|
|
66
|
-
│ ├── state.test.ts
|
|
67
|
-
│ ├── memo.test.ts
|
|
68
|
-
│ ├── task.test.ts
|
|
69
|
-
│ ├── effect.test.ts
|
|
70
|
-
│ ├── store.test.ts
|
|
71
|
-
│ ├── list.test.ts
|
|
72
|
-
│ └── collection.test.ts
|
|
73
|
-
└── package.json
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
## API Patterns
|
|
77
|
-
|
|
78
|
-
### Signal Creation
|
|
79
|
-
```typescript
|
|
80
|
-
// State for primitives and objects
|
|
81
|
-
const count = createState(42)
|
|
82
|
-
const name = createState('Alice')
|
|
83
|
-
|
|
84
|
-
// Sensor for external input
|
|
85
|
-
const mousePos = createSensor<{ x: number; y: number }>((set) => {
|
|
86
|
-
const handler = (e: MouseEvent) => set({ x: e.clientX, y: e.clientY })
|
|
87
|
-
window.addEventListener('mousemove', handler)
|
|
88
|
-
return () => window.removeEventListener('mousemove', handler)
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
// Sensor for mutable object observation (SKIP_EQUALITY)
|
|
92
|
-
const element = createSensor<HTMLElement>((set) => {
|
|
93
|
-
const node = document.getElementById('box')!
|
|
94
|
-
set(node)
|
|
95
|
-
const obs = new MutationObserver(() => set(node))
|
|
96
|
-
obs.observe(node, { attributes: true })
|
|
97
|
-
return () => obs.disconnect()
|
|
98
|
-
}, { value: node, equals: SKIP_EQUALITY })
|
|
99
|
-
|
|
100
|
-
// Store for objects with reactive properties
|
|
101
|
-
const user = createStore({ name: 'Alice', age: 30 })
|
|
102
|
-
|
|
103
|
-
// List with stable keys for arrays
|
|
104
|
-
const items = createList(['apple', 'banana', 'cherry'])
|
|
105
|
-
const users = createList(
|
|
106
|
-
[{ id: 'alice', name: 'Alice' }],
|
|
107
|
-
{ keyConfig: user => user.id }
|
|
108
|
-
)
|
|
109
|
-
|
|
110
|
-
// Memo for synchronous derived values
|
|
111
|
-
const doubled = createMemo(() => count.get() * 2)
|
|
112
|
-
|
|
113
|
-
// Memo with reducer capabilities (access to previous value)
|
|
114
|
-
const counter = createMemo(prev => {
|
|
115
|
-
const action = actions.get()
|
|
116
|
-
return action === 'increment' ? prev + 1 : prev - 1
|
|
117
|
-
}, { value: 0 })
|
|
118
|
-
|
|
119
|
-
// Task for async derived values with cancellation
|
|
120
|
-
const userData = createTask(async (prev, abort) => {
|
|
121
|
-
const id = userId.get()
|
|
122
|
-
if (!id) return prev
|
|
123
|
-
const response = await fetch(`/users/${id}`, { signal: abort })
|
|
124
|
-
return response.json()
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
// Collection for derived transformations
|
|
128
|
-
const doubled = numbers.deriveCollection((value: number) => value * 2)
|
|
129
|
-
const enriched = users.deriveCollection(async (user, abort) => {
|
|
130
|
-
const res = await fetch(`/api/${user.id}`, { signal: abort })
|
|
131
|
-
return { ...user, details: await res.json() }
|
|
132
|
-
})
|
|
133
|
-
|
|
134
|
-
// Collection for externally-driven data
|
|
135
|
-
const feed = createCollection<{ id: string; text: string }>((applyChanges) => {
|
|
136
|
-
const ws = new WebSocket('/feed')
|
|
137
|
-
ws.onmessage = (e) => applyChanges(JSON.parse(e.data))
|
|
138
|
-
return () => ws.close()
|
|
139
|
-
}, { keyConfig: item => item.id })
|
|
140
|
-
|
|
141
|
-
// Slot for stable property delegation
|
|
142
|
-
const local = createState('default')
|
|
143
|
-
const slot = createSlot(local)
|
|
144
|
-
Object.defineProperty(element, 'label', slot)
|
|
145
|
-
slot.replace(createMemo(() => parentState.get())) // swap backing signal
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
### Reactivity
|
|
149
|
-
```typescript
|
|
150
|
-
// Effects run when dependencies change
|
|
151
|
-
const dispose = createEffect(() => {
|
|
152
|
-
console.log(`Count: ${count.get()}`)
|
|
153
|
-
})
|
|
154
|
-
|
|
155
|
-
// Effects can return cleanup functions
|
|
156
|
-
createEffect(() => {
|
|
157
|
-
const timer = setInterval(() => console.log(count.get()), 1000)
|
|
158
|
-
return () => clearInterval(timer)
|
|
159
|
-
})
|
|
160
|
-
|
|
161
|
-
// match() for ergonomic signal value extraction inside effects
|
|
162
|
-
createEffect(() => {
|
|
163
|
-
match([userData], {
|
|
164
|
-
ok: ([data]) => updateUI(data),
|
|
165
|
-
nil: () => showLoading(),
|
|
166
|
-
err: errors => showError(errors[0].message)
|
|
167
|
-
})
|
|
168
|
-
})
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
### Value Access Patterns
|
|
172
|
-
```typescript
|
|
173
|
-
// All signals use .get() for value access
|
|
174
|
-
const value = signal.get()
|
|
175
|
-
|
|
176
|
-
// State has .set() and .update()
|
|
177
|
-
state.set(newValue)
|
|
178
|
-
state.update(current => current + 1)
|
|
179
|
-
|
|
180
|
-
// Store properties are individually reactive via Proxy
|
|
181
|
-
user.name.set('Bob') // Only name watchers trigger
|
|
182
|
-
user.age.update(age => age + 1) // Only age watchers trigger
|
|
183
|
-
|
|
184
|
-
// List with stable keys
|
|
185
|
-
const items = createList(['apple', 'banana'], { keyConfig: 'fruit' })
|
|
186
|
-
const appleSignal = items.byKey('fruit0')
|
|
187
|
-
const firstKey = items.keyAt(0)
|
|
188
|
-
const appleIndex = items.indexOfKey('fruit0')
|
|
189
|
-
items.splice(1, 0, 'cherry')
|
|
190
|
-
items.sort()
|
|
191
|
-
|
|
192
|
-
// Collections via deriveCollection
|
|
193
|
-
const processed = items.deriveCollection(item => item.toUpperCase())
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
## Coding Conventions
|
|
197
|
-
|
|
198
|
-
### TypeScript Style
|
|
199
|
-
- Generic constraints: `T extends {}` to exclude null/undefined
|
|
200
|
-
- Use `const` for immutable values
|
|
201
|
-
- Function overloads for complex type scenarios (e.g., `createCollection`, `deriveCollection`)
|
|
202
|
-
- JSDoc comments on all public APIs
|
|
203
|
-
- Pure function annotations: `/*#__PURE__*/` for tree-shaking
|
|
204
|
-
|
|
205
|
-
### Naming Conventions
|
|
206
|
-
- Factory functions: `create*` prefix (createState, createMemo, createEffect, createStore, createList, createCollection, createSensor, createSlot)
|
|
207
|
-
- Type predicates: `is*` prefix (isState, isMemo, isTask, isStore, isList, isCollection, isSensor, isSlot)
|
|
208
|
-
- Type constants: `TYPE_*` format (TYPE_STATE, TYPE_STORE, TYPE_SENSOR, TYPE_COLLECTION)
|
|
209
|
-
- Callback types: `*Callback` suffix (MemoCallback, TaskCallback, EffectCallback, SensorCallback, CollectionCallback, DeriveCollectionCallback)
|
|
210
|
-
|
|
211
|
-
### Error Handling
|
|
212
|
-
- Custom error classes in `src/errors.ts`: CircularDependencyError, NullishSignalValueError, InvalidSignalValueError, InvalidCallbackError, RequiredOwnerError, UnsetSignalValueError
|
|
213
|
-
- Descriptive error messages with `[TypeName]` prefix
|
|
214
|
-
- Input validation via `validateSignalValue()` and `validateCallback()`
|
|
215
|
-
- Optional type guards via `guard` option in SignalOptions
|
|
216
|
-
|
|
217
|
-
## Performance Considerations
|
|
218
|
-
|
|
219
|
-
### Optimization Patterns
|
|
220
|
-
- Linked-list edges for O(1) link/unlink operations
|
|
221
|
-
- Flag-based dirty checking: FLAG_CLEAN, FLAG_CHECK, FLAG_DIRTY, FLAG_RUNNING
|
|
222
|
-
- Batched updates via `batch()` to minimize effect re-runs
|
|
223
|
-
- Lazy evaluation: Memos only recompute when accessed and dirty
|
|
224
|
-
- Automatic abort of in-flight Tasks when sources change
|
|
225
|
-
|
|
226
|
-
### Memory Management
|
|
227
|
-
- `trimSources()` removes stale edges after each recomputation
|
|
228
|
-
- `unlink()` calls `source.stop()` when last sink disconnects (auto-cleanup for Sensor/Collection/Store/List)
|
|
229
|
-
- AbortSignal integration for canceling async operations
|
|
230
|
-
- `createScope()` for hierarchical cleanup of nested effects
|
|
231
|
-
|
|
232
|
-
## Resource Management
|
|
233
|
-
|
|
234
|
-
**Sensor and Collection** use a watched callback that returns a Cleanup function:
|
|
235
|
-
```typescript
|
|
236
|
-
const sensor = createSensor<T>((set) => {
|
|
237
|
-
// setup input tracking, call set(value) to update
|
|
238
|
-
return () => { /* cleanup */ }
|
|
239
|
-
})
|
|
240
|
-
|
|
241
|
-
const feed = createCollection<T>((applyChanges) => {
|
|
242
|
-
// setup external data source, call applyChanges(diffResult) on changes
|
|
243
|
-
return () => { /* cleanup */ }
|
|
244
|
-
}, { keyConfig: item => item.id })
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
**Memo and Task** use an optional `watched` callback in options that receives an `invalidate` function:
|
|
248
|
-
```typescript
|
|
249
|
-
const derived = createMemo(() => element.get().textContent ?? '', {
|
|
250
|
-
watched: (invalidate) => {
|
|
251
|
-
const obs = new MutationObserver(() => invalidate())
|
|
252
|
-
obs.observe(element.get(), { childList: true })
|
|
253
|
-
return () => obs.disconnect()
|
|
254
|
-
}
|
|
255
|
-
})
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
**Store and List** use an optional `watched` callback in options:
|
|
259
|
-
```typescript
|
|
260
|
-
const store = createStore(initialValue, {
|
|
261
|
-
watched: () => {
|
|
262
|
-
// setup resources
|
|
263
|
-
return () => { /* cleanup */ }
|
|
264
|
-
}
|
|
265
|
-
})
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
Resources activate on first sink link and cleanup when last sink unlinks.
|
|
269
|
-
|
|
270
|
-
## Build and Development
|
|
271
|
-
|
|
272
|
-
### Tools
|
|
273
|
-
- **Runtime**: Bun (also works with Node.js)
|
|
274
|
-
- **Build**: Bun build with TypeScript compilation
|
|
275
|
-
- **Testing**: Bun test runner (`bun test`)
|
|
276
|
-
- **Linting**: Biome for code formatting and linting
|
|
277
|
-
|
|
278
|
-
### Package Configuration
|
|
279
|
-
- ES modules only (`"type": "module"`)
|
|
280
|
-
- TypeScript declarations generated automatically
|
|
281
|
-
- Tree-shaking friendly with proper sideEffects configuration
|