@zeix/cause-effect 0.17.0 → 0.17.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.ai-context.md +26 -5
- package/.cursorrules +8 -3
- package/.github/copilot-instructions.md +13 -4
- package/CLAUDE.md +191 -262
- package/README.md +268 -420
- package/archive/collection.ts +23 -25
- package/archive/computed.ts +5 -4
- package/archive/list.ts +21 -28
- package/archive/memo.ts +4 -2
- package/archive/state.ts +2 -1
- package/archive/store.ts +21 -32
- package/archive/task.ts +6 -9
- package/index.dev.js +411 -220
- package/index.js +1 -1
- package/index.ts +25 -8
- package/package.json +1 -1
- package/src/classes/collection.ts +103 -77
- package/src/classes/composite.ts +28 -33
- package/src/classes/computed.ts +90 -31
- package/src/classes/list.ts +39 -33
- package/src/classes/ref.ts +96 -0
- package/src/classes/state.ts +41 -8
- package/src/classes/store.ts +47 -30
- package/src/diff.ts +2 -1
- package/src/effect.ts +19 -9
- package/src/errors.ts +31 -1
- package/src/match.ts +5 -12
- package/src/resolve.ts +3 -2
- package/src/signal.ts +0 -1
- package/src/system.ts +159 -43
- package/src/util.ts +0 -10
- package/test/collection.test.ts +383 -67
- package/test/computed.test.ts +268 -11
- package/test/effect.test.ts +2 -2
- package/test/list.test.ts +249 -21
- package/test/ref.test.ts +381 -0
- package/test/state.test.ts +13 -13
- package/test/store.test.ts +473 -28
- package/types/index.d.ts +6 -5
- package/types/src/classes/collection.d.ts +27 -12
- package/types/src/classes/composite.d.ts +4 -4
- package/types/src/classes/computed.d.ts +17 -0
- package/types/src/classes/list.d.ts +6 -6
- package/types/src/classes/ref.d.ts +48 -0
- package/types/src/classes/state.d.ts +9 -0
- package/types/src/classes/store.d.ts +4 -4
- package/types/src/effect.d.ts +1 -2
- package/types/src/errors.d.ts +9 -1
- package/types/src/system.d.ts +40 -24
- package/types/src/util.d.ts +1 -3
package/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var B=Symbol(),o=($)=>typeof $==="string",s=($)=>typeof $==="number",W=($)=>typeof $==="symbol",q=($)=>typeof $==="function",j=($)=>q($)&&$.constructor.name==="AsyncFunction",Y$=($)=>q($)&&$.constructor.name!=="AsyncFunction",J$=($)=>$!=null&&typeof $==="object",F=($,J)=>Object.prototype.toString.call($)===`[object ${J}]`,Y=($)=>F($,"Object"),c=($)=>Y($)||Array.isArray($),z$=($,J=(z)=>z!=null)=>Array.isArray($)&&$.every(J);var E=($)=>$ instanceof DOMException&&$.name==="AbortError",I=($)=>$ instanceof Error?$:Error(String($)),f=($)=>o($)?`"${$}"`:!!$&&typeof $==="object"?JSON.stringify($):String($);var L=($,J,z)=>{if(Object.is($,J))return!0;if(typeof $!==typeof J)return!1;if(!J$($)||!J$(J))return!1;if(!z)z=new WeakSet;if(z.has($)||z.has(J))throw new P("isEqual");z.add($),z.add(J);try{if(Array.isArray($)&&Array.isArray(J)){if($.length!==J.length)return!1;for(let G=0;G<$.length;G++)if(!L($[G],J[G],z))return!1;return!0}if(Array.isArray($)!==Array.isArray(J))return!1;if(Y($)&&Y(J)){let G=Object.keys($),X=Object.keys(J);if(G.length!==X.length)return!1;for(let Z of G){if(!(Z in J))return!1;if(!L($[Z],J[Z],z))return!1}return!0}return!1}finally{z.delete($),z.delete(J)}},w=($,J)=>{let z=c($),G=c(J);if(!z||!G){let M=!Object.is($,J);return{changed:M,add:M&&G?J:{},change:{},remove:M&&z?$:{}}}let X=new WeakSet,Z={},Q={},A={},V=Object.keys($),u=Object.keys(J),U=new Set([...V,...u]);for(let M of U){let C=M in $,m=M in J;if(!C&&m){Z[M]=J[M];continue}else if(C&&!m){A[M]=B;continue}let P$=$[M],K$=J[M];if(!L(P$,K$,X))Q[M]=K$}return{add:Z,change:Q,remove:A,changed:!!(Object.keys(Z).length||Object.keys(Q).length||Object.keys(A).length)}};var S,g=new Set,i=0,R=($)=>{let J=new Set,z=$;return z.onCleanup=(G)=>{J.add(G)},z.stop=()=>{for(let G of J)G();J.clear()},z},D=($)=>{if(S&&!$.has(S)){let J=S;J.onCleanup(()=>$.delete(J)),$.add(J)}},H=($)=>{for(let J of $)if(i)g.add(J);else J()},p=()=>{while(g.size){let $=Array.from(g);g.clear();for(let J of $)J()}},G$=($)=>{i++;try{$()}finally{p(),i--}},_=($,J)=>{let z=S;S=$||void 0;try{J()}finally{S=z}},x=($,J)=>{for(let z of $)if(i)g.add(()=>z(J));else z(J)};var t="Computed";class b{#J=new Set;#z;#G;#$;#X=!0;#Q=!1;#Z;constructor($,J=B){N("memo",$,l),K("memo",J),this.#z=$,this.#G=J,this.#Z=R(()=>{if(this.#X=!0,this.#J.size)H(this.#J);else this.#Z.stop()})}get[Symbol.toStringTag](){return t}get(){if(D(this.#J),p(),this.#X)_(this.#Z,()=>{if(this.#Q)throw new P("memo");let $;this.#Q=!0;try{$=this.#z(this.#G)}catch(J){this.#G=B,this.#$=I(J),this.#Q=!1;return}if($==null||B===$)this.#G=B,this.#$=void 0;else this.#G=$,this.#$=void 0,this.#X=!1;this.#Q=!1});if(this.#$)throw this.#$;return this.#G}}class y{#J=new Set;#z;#G;#$;#X=!0;#Q=!1;#Z=!1;#H;#B;constructor($,J=B){N("task",$,r),K("task",J),this.#z=$,this.#G=J,this.#H=R(()=>{if(this.#X=!0,this.#B?.abort(),this.#J.size)H(this.#J);else this.#H.stop()}),this.#H.onCleanup(()=>{this.#B?.abort()})}get[Symbol.toStringTag](){return t}get(){D(this.#J),p();let $=(Z)=>{if(!L(Z,this.#G))this.#G=Z,this.#Z=!0;this.#$=void 0,this.#X=!1},J=()=>{this.#Z=B!==this.#G,this.#G=B,this.#$=void 0},z=(Z)=>{let Q=I(Z);this.#Z=!this.#$||Q.name!==this.#$.name||Q.message!==this.#$.message,this.#G=B,this.#$=Q},G=(Z)=>(Q)=>{if(this.#Q=!1,this.#B=void 0,Z(Q),this.#Z)H(this.#J)},X=()=>_(this.#H,()=>{if(this.#Q)throw new P("task");if(this.#Z=!1,this.#B)return this.#G;this.#B=new AbortController,this.#B.signal.addEventListener("abort",()=>{this.#Q=!1,this.#B=void 0,X()},{once:!0});let Z;this.#Q=!0;try{Z=this.#z(this.#G,this.#B.signal)}catch(Q){if(E(Q))J();else z(Q);this.#Q=!1;return}if(Z instanceof Promise)Z.then(G($),G(z));else if(Z==null||B===Z)J();else $(Z);this.#Q=!1});if(this.#X)X();if(this.#$)throw this.#$;return this.#G}}var X$=($,J=B)=>j($)?new y($,J):new b($,J),Z$=($)=>F($,t),l=($)=>Y$($)&&$.length<2,r=($)=>j($)&&$.length<3;class k{signals=new Map;#J;#z;#G=new Map;#$={add:new Set,change:new Set,remove:new Set};#X=!1;constructor($,J,z){this.#J=J,this.#z=z,this.change({add:$,change:{},remove:{},changed:!0},!0)}#Q($){let J=R(()=>{_(J,()=>{if(this.signals.get($)?.get(),!this.#X)x(this.#$.change,[$])})});this.#G.set($,J),J()}add($,J){if(!this.#J($,J))return!1;if(this.signals.set($,this.#z(J)),this.#$.change.size)this.#Q($);if(!this.#X)x(this.#$.add,[$]);return!0}remove($){if(!this.signals.delete($))return!1;let z=this.#G.get($);if(z)z.stop(),this.#G.delete($);if(!this.#X)x(this.#$.remove,[$]);return!0}change($,J){if(this.#X=!0,Object.keys($.add).length){for(let G in $.add)this.add(G,$.add[G]);let z=()=>x(this.#$.add,Object.keys($.add));if(J)setTimeout(z,0);else z()}if(Object.keys($.change).length)G$(()=>{for(let z in $.change){let G=$.change[z];if(!this.#J(z,G))continue;let X=this.signals.get(z);if(I$(`list item "${z}"`,G,X))X.set(G)}}),x(this.#$.change,Object.keys($.change));if(Object.keys($.remove).length){for(let z in $.remove)this.remove(z);x(this.#$.remove,Object.keys($.remove))}return this.#X=!1,$.changed}clear(){let $=Array.from(this.signals.keys());return this.signals.clear(),this.#G.clear(),x(this.#$.remove,$),!0}on($,J){if(this.#$[$].add(J),$==="change"&&!this.#G.size){this.#X=!0;for(let z of this.signals.keys())this.#Q(z);this.#X=!1}return()=>{if(this.#$[$].delete(J),$==="change"&&!this.#$.change.size){if(this.#G.size){for(let z of this.#G.values())z.stop();this.#G.clear()}}}}}var Q$="State";class T{#J=new Set;#z;constructor($){K("state",$),this.#z=$}get[Symbol.toStringTag](){return Q$}get(){return D(this.#J),this.#z}set($){if(K("state",$),L(this.#z,$))return;if(this.#z=$,H(this.#J),B===this.#z)this.#J.clear()}update($){N("state update",$),this.set($(this.#z))}}var a=($)=>F($,Q$);var B$="List";class v{#J;#z=new Set;#G={sort:new Set};#$=[];#X;constructor($,J){K("list",$,Array.isArray);let z=0;this.#X=o(J)?()=>`${J}${z++}`:q(J)?(G)=>J(G):()=>String(z++),this.#J=new k(this.#Q($),(G,X)=>{return K(`list for key "${G}"`,X),!0},(G)=>new T(G))}#Q($){let J={};for(let z=0;z<$.length;z++){let G=$[z];if(G===void 0)continue;let X=this.#$[z];if(!X)X=this.#X(G),this.#$[z]=X;J[X]=G}return J}get#Z(){return this.#$.map(($)=>this.#J.signals.get($)?.get()).filter(($)=>$!==void 0)}get[Symbol.toStringTag](){return B$}get[Symbol.isConcatSpreadable](){return!0}*[Symbol.iterator](){for(let $ of this.#$){let J=this.#J.signals.get($);if(J)yield J}}get length(){return D(this.#z),this.#$.length}get(){return D(this.#z),this.#Z}set($){if(B===$){this.#J.clear(),H(this.#z),this.#z.clear();return}let J=this.#Z,z=w(this.#Q(J),this.#Q($)),G=Object.keys(z.remove);if(this.#J.change(z)){for(let Z of G){let Q=this.#$.indexOf(Z);if(Q!==-1)this.#$.splice(Q,1)}this.#$=this.#$.filter(()=>!0),H(this.#z)}}update($){this.set($(this.get()))}at($){return this.#J.signals.get(this.#$[$])}keys(){return this.#$.values()}byKey($){return this.#J.signals.get($)}keyAt($){return this.#$[$]}indexOfKey($){return this.#$.indexOf($)}add($){let J=this.#X($);if(this.#J.signals.has(J))throw new O("store",J,$);if(!this.#$.includes(J))this.#$.push(J);if(this.#J.add(J,$))H(this.#z);return J}remove($){let J=s($)?this.#$[$]:$;if(this.#J.remove(J)){let G=s($)?$:this.#$.indexOf(J);if(G>=0)this.#$.splice(G,1);this.#$=this.#$.filter(()=>!0),H(this.#z)}}sort($){let z=this.#$.map((G)=>[G,this.#J.signals.get(G)?.get()]).sort(q($)?(G,X)=>$(G[1],X[1]):(G,X)=>String(G[1]).localeCompare(String(X[1]))).map(([G])=>G);if(!L(this.#$,z))this.#$=z,H(this.#z),x(this.#G.sort,this.#$)}splice($,J,...z){let G=this.#$.length,X=$<0?Math.max(0,G+$):Math.min($,G),Z=Math.max(0,Math.min(J??Math.max(0,G-Math.max(0,X)),G-X)),Q={},A={};for(let U=0;U<Z;U++){let M=X+U,C=this.#$[M];if(C){let m=this.#J.signals.get(C);if(m)A[C]=m.get()}}let V=this.#$.slice(0,X);for(let U of z){let M=this.#X(U);V.push(M),Q[M]=U}V.push(...this.#$.slice(X+Z));let u=!!(Object.keys(Q).length||Object.keys(A).length);if(u)this.#J.change({add:Q,change:{},remove:A,changed:u}),this.#$=V.filter(()=>!0),H(this.#z);return Object.values(A)}on($,J){if($==="sort")return this.#G.sort.add(J),()=>this.#G.sort.delete(J);return this.#J.on($,J)}deriveCollection($){return new d(this,$)}}var h=($)=>F($,B$);var H$="Store";class M${#J;#z=new Set;constructor($){K("store",$,Y),this.#J=new k($,(J,z)=>{return K(`store for key "${J}"`,z),!0},(J)=>L$(J))}get#G(){let $={};for(let[J,z]of this.#J.signals.entries())$[J]=z.get();return $}get[Symbol.toStringTag](){return H$}get[Symbol.isConcatSpreadable](){return!1}*[Symbol.iterator](){for(let[$,J]of this.#J.signals.entries())yield[$,J]}get(){return D(this.#z),this.#G}set($){if(B===$){this.#J.clear(),H(this.#z),this.#z.clear();return}let J=this.#G;if(this.#J.change(w(J,$)))H(this.#z)}keys(){return this.#J.signals.keys()}byKey($){return this.#J.signals.get($)}update($){this.set($(this.get()))}add($,J){if(this.#J.signals.has($))throw new O("store",$,J);if(this.#J.add($,J))H(this.#z);return $}remove($){if(this.#J.remove($))H(this.#z)}on($,J){return this.#J.on($,J)}}var e=($)=>{let J=new M$($);return new Proxy(J,{get(z,G){if(G in z){let X=Reflect.get(z,G);return q(X)?X.bind(z):X}if(!W(G))return z.byKey(G)},has(z,G){if(G in z)return!0;return z.byKey(String(G))!==void 0},ownKeys(z){return Array.from(z.keys())},getOwnPropertyDescriptor(z,G){if(G in z)return Reflect.getOwnPropertyDescriptor(z,G);if(W(G))return;let X=z.byKey(String(G));return X?{enumerable:!0,configurable:!0,writable:!0,value:X}:void 0}})},$$=($)=>F($,H$);var U$=($)=>a($)||Z$($)||$$($),q$=($)=>a($)||$$($)||h($);function j$($){if(l($))return new b($);if(r($))return new y($);if(z$($))return new v($);if(Y($))return e($);return new T($)}function L$($){if(z$($))return new v($);if(Y($))return e($);return new T($)}class P extends Error{constructor($){super(`Circular dependency detected in ${$}`);this.name="CircularDependencyError"}}class O extends Error{constructor($,J,z){super(`Could not add ${$} key "${J}"${z?` with value ${f(z)}`:""} because it already exists`);this.name="DuplicateKeyError"}}class n extends TypeError{constructor($,J){super(`Invalid ${$} callback ${f(J)}`);this.name="InvalidCallbackError"}}class x$ extends TypeError{constructor($,J){super(`Invalid signal value ${f(J)} in ${$}`);this.name="InvalidSignalValueError"}}class A$ extends TypeError{constructor($){super(`Nullish signal values are not allowed in ${$}`);this.name="NullishSignalValueError"}}class D$ extends Error{constructor($,J){super(`Could not set ${$} to ${f(J)} because signal is read-only`);this.name="ReadonlySignalError"}}var N=($,J,z=q)=>{if(!z(J))throw new n($,J)},K=($,J,z=()=>!(W(J)&&J!==B)||q(J))=>{if(J==null)throw new A$($);if(!z(J))throw new x$($,J)},I$=($,J,z)=>{if(!q$(z))throw new D$($,J);return!0};var F$="Collection";class d{#J=new Set;#z;#G;#$=new Map;#X=new Map;#Q={add:new Set,change:new Set,remove:new Set,sort:new Set};#Z=[];constructor($,J){if(N("collection",J),q($))$=$();if(!N$($))throw Error("Invalid collection source");this.#z=$,this.#G=J;for(let z=0;z<this.#z.length;z++){let G=this.#z.keyAt(z);if(!G)continue;this.#B(G)}this.#z.on("add",(z)=>{for(let G of z)if(!this.#$.has(G)){this.#B(G);let X=this.#$.get(G);if(X&&R$(this.#G))X.get()}H(this.#J),x(this.#Q.add,z)}),this.#z.on("remove",(z)=>{for(let G of z){if(!this.#$.has(G))continue;this.#$.delete(G);let X=this.#Z.indexOf(G);if(X>=0)this.#Z.splice(X,1);this.#q(G)}this.#Z=this.#Z.filter(()=>!0),H(this.#J),x(this.#Q.remove,z)}),this.#z.on("sort",(z)=>{this.#Z=[...z],H(this.#J),x(this.#Q.sort,z)})}get#H(){return this.#Z.map(($)=>this.#$.get($)?.get()).filter(($)=>$!=null&&$!==B)}#B($){let J=R$(this.#G)?async(G,X)=>{let Z=this.#z.byKey($);if(!Z)return B;let Q=Z.get();if(Q===B)return B;return this.#G(Q,X)}:()=>{let G=this.#z.byKey($);if(!G)return B;let X=G.get();if(X===B)return B;return this.#G(X)},z=X$(J);if(this.#$.set($,z),!this.#Z.includes($))this.#Z.push($);if(this.#Q.change.size)this.#M($);return!0}#M($){let J=R(()=>{_(J,()=>{this.#$.get($)?.get()})});this.#X.set($,J),J()}#q($){let J=this.#X.get($);if(J)J.stop(),this.#X.delete($)}get[Symbol.toStringTag](){return F$}get[Symbol.isConcatSpreadable](){return!0}*[Symbol.iterator](){for(let $ of this.#Z){let J=this.#$.get($);if(J)yield J}}get length(){return D(this.#J),this.#Z.length}get(){return D(this.#J),this.#H}at($){return this.#$.get(this.#Z[$])}keys(){return this.#Z.values()}byKey($){return this.#$.get($)}keyAt($){return this.#Z[$]}indexOfKey($){return this.#Z.indexOf($)}on($,J){if(this.#Q[$].add(J),$==="change"&&!this.#X.size)for(let z of this.#$.keys())this.#M(z);return()=>{if(this.#Q[$].delete(J),$==="change"&&!this.#Q.change.size){if(this.#X.size){for(let z of this.#X.values())z.stop();this.#X.clear()}}}}deriveCollection($){return new d(this,$)}}var _$=($)=>F($,F$),N$=($)=>h($)||_$($),R$=($)=>j($);var T$=($)=>{if(!q($)||$.length>1)throw new n("effect",$);let J=j($),z=!1,G,X=R(()=>_(X,()=>{if(z)throw new P("effect");z=!0,G?.abort(),G=void 0;let Z;try{if(J){G=new AbortController;let Q=G;$(G.signal).then((A)=>{if(q(A)&&G===Q)X.onCleanup(A)}).catch((A)=>{if(!E(A))console.error("Async effect error:",A)})}else if(Z=$(),q(Z))X.onCleanup(Z)}catch(Q){if(!E(Q))console.error("Effect callback error:",Q)}z=!1}));return X(),()=>{G?.abort(),X.stop()}};function C$($,J){try{if($.pending)J.nil?.();else if($.errors)J.err?.($.errors);else if($.ok)J.ok($.values)}catch(z){if(J.err&&(!$.errors||!$.errors.includes(I(z))))J.err($.errors?[...$.errors,I(z)]:[I(z)]);else throw z}}function W$($){let J=[],z=!1,G={};for(let[X,Z]of Object.entries($))try{let Q=Z.get();if(Q===B)z=!0;else G[X]=Q}catch(Q){J.push(I(Q))}if(z)return{ok:!1,pending:!0};if(J.length>0)return{ok:!1,errors:J};return{ok:!0,values:G}}export{f as valueString,_ as trackSignalReads,I as toError,D as subscribeActiveWatcher,W$ as resolve,H as notifyWatchers,C$ as match,r as isTaskCallback,W as isSymbol,o as isString,$$ as isStore,a as isState,U$ as isSignal,c as isRecordOrArray,Y as isRecord,F as isObjectOfType,s as isNumber,q$ as isMutableSignal,l as isMemoCallback,h as isList,q as isFunction,L as isEqual,Z$ as isComputed,_$ as isCollection,j as isAsyncFunction,E as isAbortError,p as flushPendingReactions,x as emitNotification,w as diff,R as createWatcher,e as createStore,j$ as createSignal,T$ as createEffect,X$ as createComputed,G$ as batchSignalWrites,B as UNSET,y as Task,H$ as TYPE_STORE,Q$ as TYPE_STATE,B$ as TYPE_LIST,t as TYPE_COMPUTED,F$ as TYPE_COLLECTION,T as State,D$ as ReadonlySignalError,A$ as NullishSignalValueError,b as Memo,v as List,x$ as InvalidSignalValueError,n as InvalidCallbackError,O as DuplicateKeyError,d as Collection,P as CircularDependencyError,M$ as BaseStore};
|
|
1
|
+
var Z$=($)=>typeof $==="string",Q$=($)=>typeof $==="number",p=($)=>typeof $==="symbol",q=($)=>typeof $==="function",H=($)=>q($)&&$.constructor.name==="AsyncFunction",_$=($)=>q($)&&$.constructor.name!=="AsyncFunction",U$=($)=>$!=null&&typeof $==="object",L=($,J)=>Object.prototype.toString.call($)===`[object ${J}]`,P=($)=>L($,"Object"),B$=($)=>P($)||Array.isArray($),Y$=($,J=(z)=>z!=null)=>Array.isArray($)&&$.every(J);var y=($)=>$ instanceof DOMException&&$.name==="AbortError",C=($)=>Z$($)?`"${$}"`:!!$&&typeof $==="object"?JSON.stringify($):String($);var b,o=new WeakMap,x$=new Set,L$=0,x=Symbol(),A="add",N="change",m="cleanup",K="remove",v="sort",F="watch",S=($)=>{let J=new Set,z=$;return z.on=(X,Z)=>{if(X===m)J.add(Z);else throw new M("watcher",X)},z.stop=()=>{try{for(let X of J)X()}finally{J.clear()}},z},I=($,J)=>{if(!$.size&&J?.size){let z=j(J);if(z){let X=o.get($)??new Set;if(X.add(z),!o.has($))o.set($,X)}}if(b&&!$.has(b)){let z=b;z.on(m,()=>{if($.delete(z),!$.size){let X=o.get($);if(X)try{for(let Z of X)Z()}finally{X.clear(),o.delete($)}}}),$.add(z)}},G=($)=>{if(!$.size)return!1;for(let J of $)if(L$)x$.add(J);else J();return!0},s=()=>{while(x$.size){let $=Array.from(x$);x$.clear();for(let J of $)J()}},N$=($)=>{L$++;try{$()}finally{s(),L$--}},W=($,J)=>{let z=b;b=$||void 0;try{J()}finally{b=z}},j=($,J)=>{if(!$)return;let z=[],X=[],Z=(Q)=>{if(X.length){if(X.length===1)throw X[0];throw AggregateError(X,`Errors in hook ${Q?"cleanup":"callback"}:`)}};for(let Q of $)try{let B=Q(J);if(q(B))z.push(B)}catch(B){X.push(R(B))}if(Z(),!z.length)return;if(z.length===1)return z[0];return()=>{for(let Q of z)try{Q()}catch(B){X.push(R(B))}Z(!0)}},f=($,J)=>J.includes($);var V=($,J,z)=>{if(Object.is($,J))return!0;if(typeof $!==typeof J)return!1;if(!U$($)||!U$(J))return!1;if(!z)z=new WeakSet;if(z.has($)||z.has(J))throw new _("isEqual");z.add($),z.add(J);try{if(Array.isArray($)&&Array.isArray(J)){if($.length!==J.length)return!1;for(let X=0;X<$.length;X++)if(!V($[X],J[X],z))return!1;return!0}if(Array.isArray($)!==Array.isArray(J))return!1;if(P($)&&P(J)){let X=Object.keys($),Z=Object.keys(J);if(X.length!==Z.length)return!1;for(let Q of X){if(!(Q in J))return!1;if(!V($[Q],J[Q],z))return!1}return!0}return!1}finally{z.delete($),z.delete(J)}},t=($,J)=>{let z=B$($),X=B$(J);if(!z||!X){let D=!Object.is($,J);return{changed:D,add:D&&X?J:{},change:{},remove:D&&z?$:{}}}let Z=new WeakSet,Q={},B={},Y={},k=Object.keys($),X$=Object.keys(J),T=new Set([...k,...X$]);for(let D of T){let w=D in $,i=D in J;if(!w&&i){Q[D]=J[D];continue}else if(w&&!i){Y[D]=x;continue}let g$=$[D],m$=J[D];if(!V(g$,m$,Z))B[D]=m$}return{add:Q,change:B,remove:Y,changed:!!(Object.keys(Q).length||Object.keys(B).length||Object.keys(Y).length)}};var G$="Computed";class c{#z=new Set;#X;#J;#$;#B=!0;#Q=!1;#Z;#x;constructor($,J=x){E(this.constructor.name,$,q$),U(this.constructor.name,J),this.#X=$,this.#J=J}#G(){if(!this.#Z)this.#Z=S(()=>{if(this.#B=!0,!G(this.#z))this.#Z?.stop()}),this.#Z.on(m,()=>{this.#Z=void 0});return this.#Z}get[Symbol.toStringTag](){return G$}get(){if(I(this.#z,this.#x),s(),this.#B){let $=this.#G();W($,()=>{if(this.#Q)throw new _("memo");let J;this.#Q=!0;try{J=this.#X(this.#J)}catch(z){this.#J=x,this.#$=R(z),this.#Q=!1;return}if(J==null||x===J)this.#J=x,this.#$=void 0;else this.#J=J,this.#$=void 0,this.#B=!1;this.#Q=!1})}if(this.#$)throw this.#$;return this.#J}on($,J){if($===F)return this.#x||=new Set,this.#x.add(J),()=>{this.#x?.delete(J)};throw new M(this.constructor.name,$)}}class r{#z=new Set;#X;#J;#$;#B=!0;#Q=!1;#Z=!1;#x;#G;#q;constructor($,J=x){E(this.constructor.name,$,F$),U(this.constructor.name,J),this.#X=$,this.#J=J}#F(){if(!this.#x)this.#x=S(()=>{if(this.#B=!0,this.#G?.abort(),!G(this.#z))this.#x?.stop()}),this.#x.on(m,()=>{this.#G?.abort(),this.#G=void 0,this.#x=void 0});return this.#x}get[Symbol.toStringTag](){return G$}get(){I(this.#z,this.#q),s();let $=(Q)=>{if(!V(Q,this.#J))this.#J=Q,this.#Z=!0;this.#$=void 0,this.#B=!1},J=()=>{this.#Z=x!==this.#J,this.#J=x,this.#$=void 0},z=(Q)=>{let B=R(Q);this.#Z=!this.#$||B.name!==this.#$.name||B.message!==this.#$.message,this.#J=x,this.#$=B},X=(Q)=>(B)=>{if(this.#Q=!1,this.#G=void 0,Q(B),this.#Z&&!G(this.#z))this.#x?.stop()},Z=()=>W(this.#F(),()=>{if(this.#Q)throw new _("task");if(this.#Z=!1,this.#G)return this.#J;this.#G=new AbortController,this.#G.signal.addEventListener("abort",()=>{this.#Q=!1,this.#G=void 0,Z()},{once:!0});let Q;this.#Q=!0;try{Q=this.#X(this.#J,this.#G.signal)}catch(B){if(y(B))J();else z(B);this.#Q=!1;return}if(Q instanceof Promise)Q.then(X($),X(z));else if(Q==null||x===Q)J();else $(Q);this.#Q=!1});if(this.#B)Z();if(this.#$)throw this.#$;return this.#J}on($,J){if($===F)return this.#q||=new Set,this.#q.add(J),()=>{this.#q?.delete(J)};throw new M(this.constructor.name,$)}}var R$=($,J=x)=>H($)?new r($,J):new c($,J),P$=($)=>L($,G$),q$=($)=>_$($)&&$.length<2,F$=($)=>H($)&&$.length<3;class l{signals=new Map;#z;#X;#J=new Map;#$={};#B=!1;constructor($,J,z){this.#z=J,this.#X=z,this.change({add:$,change:{},remove:{},changed:!0},!0)}#Q($){let J=S(()=>{W(J,()=>{if(this.signals.get($)?.get(),!this.#B)j(this.#$.change,[$])})});this.#J.set($,J),J()}add($,J){if(!this.#z($,J))return!1;if(this.signals.set($,this.#X(J)),this.#$.change?.size)this.#Q($);if(!this.#B)j(this.#$.add,[$]);return!0}remove($){if(!this.signals.delete($))return!1;let z=this.#J.get($);if(z)z.stop(),this.#J.delete($);if(!this.#B)j(this.#$.remove,[$]);return!0}change($,J){if(this.#B=!0,Object.keys($.add).length){for(let X in $.add)this.add(X,$.add[X]);let z=()=>j(this.#$.add,Object.keys($.add));if(J)setTimeout(z,0);else z()}if(Object.keys($.change).length)N$(()=>{for(let z in $.change){let X=$.change[z];if(!this.#z(z,X))continue;let Z=this.signals.get(z);if(A$(`list item "${z}"`,X,Z))Z.set(X)}}),j(this.#$.change,Object.keys($.change));if(Object.keys($.remove).length){for(let z in $.remove)this.remove(z);j(this.#$.remove,Object.keys($.remove))}return this.#B=!1,$.changed}clear(){let $=Array.from(this.signals.keys());return this.signals.clear(),this.#J.clear(),j(this.#$.remove,$),!0}on($,J){if(!f($,[A,N,K]))throw new M("Composite",$);if(this.#$[$]||=new Set,this.#$[$].add(J),$===N&&!this.#J.size){this.#B=!0;for(let z of this.signals.keys())this.#Q(z);this.#B=!1}return()=>{if(this.#$[$]?.delete(J),$===N&&!this.#$.change?.size){if(this.#J.size){for(let z of this.#J.values())z.stop();this.#J.clear()}}}}}var n="State";class g{#z=new Set;#X;#J;constructor($){U(n,$),this.#X=$}get[Symbol.toStringTag](){return n}get(){return I(this.#z,this.#J),this.#X}set($){if(U(n,$),V(this.#X,$))return;if(this.#X=$,this.#z.size)G(this.#z);if(x===this.#X)this.#z.clear()}update($){E(`${n} update`,$),this.set($(this.#X))}on($,J){if($===F)return this.#J||=new Set,this.#J.add(J),()=>{this.#J?.delete(J)};throw new M(this.constructor.name,$)}}var M$=($)=>L($,n);var d="List";class a{#z;#X=new Set;#J={};#$=[];#B;constructor($,J){U(d,$,Array.isArray);let z=0;this.#B=Z$(J)?()=>`${J}${z++}`:q(J)?(X)=>J(X):()=>String(z++),this.#z=new l(this.#Q($),(X,Z)=>{return U(`${d} for key "${X}"`,Z),!0},(X)=>new g(X))}#Q($){let J={};for(let z=0;z<$.length;z++){let X=$[z];if(X===void 0)continue;let Z=this.#$[z];if(!Z)Z=this.#B(X),this.#$[z]=Z;J[Z]=X}return J}get#Z(){return this.#$.map(($)=>this.#z.signals.get($)?.get()).filter(($)=>$!==void 0)}get[Symbol.toStringTag](){return d}get[Symbol.isConcatSpreadable](){return!0}*[Symbol.iterator](){for(let $ of this.#$){let J=this.#z.signals.get($);if(J)yield J}}get length(){return I(this.#X,this.#J[F]),this.#$.length}get(){return I(this.#X,this.#J[F]),this.#Z}set($){if(x===$){this.#z.clear(),G(this.#X),this.#X.clear();return}let J=this.#Z,z=t(this.#Q(J),this.#Q($)),X=Object.keys(z.remove);if(this.#z.change(z)){for(let Q of X){let B=this.#$.indexOf(Q);if(B!==-1)this.#$.splice(B,1)}this.#$=this.#$.filter(()=>!0),G(this.#X)}}update($){this.set($(this.get()))}at($){return this.#z.signals.get(this.#$[$])}keys(){return this.#$.values()}byKey($){return this.#z.signals.get($)}keyAt($){return this.#$[$]}indexOfKey($){return this.#$.indexOf($)}add($){let J=this.#B($);if(this.#z.signals.has(J))throw new h("store",J,$);if(!this.#$.includes(J))this.#$.push(J);if(this.#z.add(J,$))G(this.#X);return J}remove($){let J=Q$($)?this.#$[$]:$;if(this.#z.remove(J)){let X=Q$($)?$:this.#$.indexOf(J);if(X>=0)this.#$.splice(X,1);this.#$=this.#$.filter(()=>!0),G(this.#X)}}sort($){let z=this.#$.map((X)=>[X,this.#z.signals.get(X)?.get()]).sort(q($)?(X,Z)=>$(X[1],Z[1]):(X,Z)=>String(X[1]).localeCompare(String(Z[1]))).map(([X])=>X);if(!V(this.#$,z))this.#$=z,G(this.#X),j(this.#J.sort,this.#$)}splice($,J,...z){let X=this.#$.length,Z=$<0?Math.max(0,X+$):Math.min($,X),Q=Math.max(0,Math.min(J??Math.max(0,X-Math.max(0,Z)),X-Z)),B={},Y={};for(let T=0;T<Q;T++){let D=Z+T,w=this.#$[D];if(w){let i=this.#z.signals.get(w);if(i)Y[w]=i.get()}}let k=this.#$.slice(0,Z);for(let T of z){let D=this.#B(T);k.push(D),B[D]=T}k.push(...this.#$.slice(Z+Q));let X$=!!(Object.keys(B).length||Object.keys(Y).length);if(X$)this.#z.change({add:B,change:{},remove:Y,changed:X$}),this.#$=k.filter(()=>!0),G(this.#X);return Object.values(Y)}on($,J){if(f($,[v,F]))return this.#J[$]||=new Set,this.#J[$].add(J),()=>{this.#J[$]?.delete(J)};else if(f($,[A,N,K]))return this.#z.on($,J);throw new M(d,$)}deriveCollection($){return new $$(this,$)}}var e=($)=>L($,d);var O="Store";class K${#z;#X=new Set;#J;constructor($){U(O,$,P),this.#z=new l($,(J,z)=>{return U(`${O} for key "${J}"`,z),!0},(J)=>T$(J))}get#$(){let $={};for(let[J,z]of this.#z.signals.entries())$[J]=z.get();return $}get[Symbol.toStringTag](){return O}get[Symbol.isConcatSpreadable](){return!1}*[Symbol.iterator](){for(let[$,J]of this.#z.signals.entries())yield[$,J]}keys(){return this.#z.signals.keys()}byKey($){return this.#z.signals.get($)}get(){return I(this.#X,this.#J),this.#$}set($){if(x===$){this.#z.clear(),G(this.#X),this.#X.clear();return}let J=this.#$;if(this.#z.change(t(J,$)))G(this.#X)}update($){this.set($(this.get()))}add($,J){if(this.#z.signals.has($))throw new h(O,$,J);if(this.#z.add($,J))G(this.#X);return $}remove($){if(this.#z.remove($))G(this.#X)}on($,J){if($===F)return this.#J||=new Set,this.#J.add(J),()=>{this.#J?.delete(J)};else if(f($,[A,N,K]))return this.#z.on($,J);throw new M(O,$)}}var D$=($)=>{let J=new K$($);return new Proxy(J,{get(z,X){if(X in z){let Z=Reflect.get(z,X);return q(Z)?Z.bind(z):Z}if(!p(X))return z.byKey(X)},has(z,X){if(X in z)return!0;return z.byKey(String(X))!==void 0},ownKeys(z){return Array.from(z.keys())},getOwnPropertyDescriptor(z,X){if(X in z)return Reflect.getOwnPropertyDescriptor(z,X);if(p(X))return;let Z=z.byKey(String(X));return Z?{enumerable:!0,configurable:!0,writable:!0,value:Z}:void 0}})},I$=($)=>L($,O);var O$=($)=>M$($)||P$($)||I$($),S$=($)=>M$($)||I$($)||e($);function w$($){if(q$($))return new c($);if(F$($))return new r($);if(Y$($))return new a($);if(P($))return D$($);return new g($)}function T$($){if(Y$($))return new a($);if(P($))return D$($);return new g($)}class _ extends Error{constructor($){super(`Circular dependency detected in ${$}`);this.name="CircularDependencyError"}}class h extends Error{constructor($,J,z){super(`Could not add ${$} key "${J}"${z?` with value ${C(z)}`:""} because it already exists`);this.name="DuplicateKeyError"}}class J$ extends TypeError{constructor($,J){super(`Invalid ${$} callback ${C(J)}`);this.name="InvalidCallbackError"}}class j$ extends TypeError{constructor($,J){super(`Invalid ${$} source ${C(J)}`);this.name="InvalidCollectionSourceError"}}class M extends TypeError{constructor($,J){super(`Invalid hook "${J}" in ${$}`);this.name="InvalidHookError"}}class W$ extends TypeError{constructor($,J){super(`Invalid signal value ${C(J)} in ${$}`);this.name="InvalidSignalValueError"}}class f$ extends TypeError{constructor($){super(`Nullish signal values are not allowed in ${$}`);this.name="NullishSignalValueError"}}class V$ extends Error{constructor($,J){super(`Could not set ${$} to ${C(J)} because signal is read-only`);this.name="ReadonlySignalError"}}var R=($)=>$ instanceof Error?$:Error(String($)),E=($,J,z=q)=>{if(!z(J))throw new J$($,J)},U=($,J,z=()=>!(p(J)&&J!==x)||q(J))=>{if(J==null)throw new f$($);if(!z(J))throw new W$($,J)},A$=($,J,z)=>{if(!S$(z))throw new V$($,J);return!0};var u="Collection";class $${#z=new Set;#X;#J;#$=new Map;#B=new Map;#Q={};#Z=[];constructor($,J){if(E(u,J),q($))$=$();if(!p$($))throw new j$(u,$);this.#X=$,this.#J=J;for(let z=0;z<this.#X.length;z++){let X=this.#X.keyAt(z);if(!X)continue;this.#x(X)}this.#X.on(A,(z)=>{if(!z)return;for(let X of z)if(!this.#$.has(X)){this.#x(X);let Z=this.#$.get(X);if(Z&&H$(this.#J))Z.get()}G(this.#z),j(this.#Q.add,z)}),this.#X.on(K,(z)=>{if(!z)return;for(let X of z){if(!this.#$.has(X))continue;this.#$.delete(X);let Z=this.#Z.indexOf(X);if(Z>=0)this.#Z.splice(Z,1);let Q=this.#B.get(X);if(Q)Q.stop(),this.#B.delete(X)}this.#Z=this.#Z.filter(()=>!0),G(this.#z),j(this.#Q.remove,z)}),this.#X.on(v,(z)=>{if(z)this.#Z=[...z];G(this.#z),j(this.#Q.sort,z)})}#x($){let J=H$(this.#J)?async(X,Z)=>{let Q=this.#X.byKey($)?.get();if(Q===x)return x;return this.#J(Q,Z)}:()=>{let X=this.#X.byKey($)?.get();if(X===x)return x;return this.#J(X)},z=R$(J);if(this.#$.set($,z),!this.#Z.includes($))this.#Z.push($);if(this.#Q.change?.size)this.#G($);return!0}#G($){let J=S(()=>{W(J,()=>{this.#$.get($)?.get()})});this.#B.set($,J),J()}get[Symbol.toStringTag](){return u}get[Symbol.isConcatSpreadable](){return!0}*[Symbol.iterator](){for(let $ of this.#Z){let J=this.#$.get($);if(J)yield J}}keys(){return this.#Z.values()}get(){return I(this.#z,this.#Q[F]),this.#Z.map(($)=>this.#$.get($)?.get()).filter(($)=>$!=null&&$!==x)}at($){return this.#$.get(this.#Z[$])}byKey($){return this.#$.get($)}keyAt($){return this.#Z[$]}indexOfKey($){return this.#Z.indexOf($)}on($,J){if(f($,[A,N,K,v,F])){if(this.#Q[$]||=new Set,this.#Q[$].add(J),$===N&&!this.#B.size)for(let z of this.#$.keys())this.#G(z);return()=>{if(this.#Q[$]?.delete(J),$===N&&!this.#Q.change?.size){if(this.#B.size){for(let z of this.#B.values())z.stop();this.#B.clear()}}}}throw new M(u,$)}deriveCollection($){return new $$(this,$)}get length(){return I(this.#z,this.#Q[F]),this.#Z.length}}var E$=($)=>L($,u),p$=($)=>e($)||E$($),H$=($)=>H($);var z$="Ref";class C${#z=new Set;#X;#J;constructor($,J){U(z$,$,J),this.#X=$}get[Symbol.toStringTag](){return z$}get(){return I(this.#z,this.#J),this.#X}notify(){G(this.#z)}on($,J){if($===F)return this.#J||=new Set,this.#J.add(J),()=>{this.#J?.delete(J)};throw new M(z$,$)}}var y$=($)=>L($,z$);var b$=($)=>{if(!q($)||$.length>1)throw new J$("effect",$);let J=H($),z=!1,X,Z=S(()=>W(Z,()=>{if(z)throw new _("effect");z=!0,X?.abort(),X=void 0;let Q;try{if(J){X=new AbortController;let B=X;$(X.signal).then((Y)=>{if(q(Y)&&X===B)Z.on(m,Y)}).catch((Y)=>{if(!y(Y))console.error("Error in async effect callback:",Y)})}else if(Q=$(),q(Q))Z.on(m,Q)}catch(B){if(!y(B))console.error("Error in effect callback:",B)}z=!1}));return Z(),()=>{X?.abort();try{Z.stop()}catch(Q){console.error("Error in effect cleanup:",Q)}}};function v$($,J){try{if($.pending)J.nil?.();else if($.errors)J.err?.($.errors);else if($.ok)J.ok($.values)}catch(z){let X=R(z);if(J.err&&(!$.errors||!$.errors.includes(X)))J.err($.errors?[...$.errors,X]:[X]);else throw X}}function n$($){let J=[],z=!1,X={};for(let[Z,Q]of Object.entries($))try{let B=Q.get();if(B===x)z=!0;else X[Z]=B}catch(B){J.push(R(B))}if(z)return{ok:!1,pending:!0};if(J.length>0)return{ok:!1,errors:J};return{ok:!0,values:X}}export{C as valueString,U as validateSignalValue,E as validateCallback,j as triggerHook,W as trackSignalReads,I as subscribeActiveWatcher,n$ as resolve,G as notifyWatchers,v$ as match,F$ as isTaskCallback,p as isSymbol,Z$ as isString,I$ as isStore,M$ as isState,O$ as isSignal,y$ as isRef,B$ as isRecordOrArray,P as isRecord,L as isObjectOfType,Q$ as isNumber,S$ as isMutableSignal,q$ as isMemoCallback,e as isList,f as isHandledHook,q as isFunction,V as isEqual,P$ as isComputed,E$ as isCollection,H as isAsyncFunction,y as isAbortError,A$ as guardMutableSignal,s as flushPendingReactions,t as diff,S as createWatcher,D$ as createStore,w$ as createSignal,R as createError,b$ as createEffect,R$ as createComputed,N$ as batchSignalWrites,x as UNSET,r as Task,O as TYPE_STORE,n as TYPE_STATE,z$ as TYPE_REF,d as TYPE_LIST,G$ as TYPE_COMPUTED,u as TYPE_COLLECTION,g as State,C$ as Ref,V$ as ReadonlySignalError,f$ as NullishSignalValueError,c as Memo,a as List,W$ as InvalidSignalValueError,j$ as InvalidCollectionSourceError,J$ as InvalidCallbackError,F as HOOK_WATCH,v as HOOK_SORT,K as HOOK_REMOVE,m as HOOK_CLEANUP,N as HOOK_CHANGE,A as HOOK_ADD,h as DuplicateKeyError,$$ as DerivedCollection,_ as CircularDependencyError,K$ as BaseStore};
|
package/index.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @name Cause & Effect
|
|
3
|
-
* @version 0.17.
|
|
3
|
+
* @version 0.17.2
|
|
4
4
|
* @author Esther Brunner
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
export {
|
|
8
|
-
Collection,
|
|
8
|
+
type Collection,
|
|
9
9
|
type CollectionCallback,
|
|
10
|
+
type CollectionSource,
|
|
11
|
+
DerivedCollection,
|
|
10
12
|
isCollection,
|
|
11
13
|
TYPE_COLLECTION,
|
|
12
14
|
} from './src/classes/collection'
|
|
@@ -29,6 +31,7 @@ export {
|
|
|
29
31
|
List,
|
|
30
32
|
TYPE_LIST,
|
|
31
33
|
} from './src/classes/list'
|
|
34
|
+
export { isRef, Ref, TYPE_REF } from './src/classes/ref'
|
|
32
35
|
export { isState, State, TYPE_STATE } from './src/classes/state'
|
|
33
36
|
export {
|
|
34
37
|
BaseStore,
|
|
@@ -51,11 +54,17 @@ export {
|
|
|
51
54
|
} from './src/effect'
|
|
52
55
|
export {
|
|
53
56
|
CircularDependencyError,
|
|
57
|
+
createError,
|
|
54
58
|
DuplicateKeyError,
|
|
59
|
+
type Guard,
|
|
60
|
+
guardMutableSignal,
|
|
55
61
|
InvalidCallbackError,
|
|
62
|
+
InvalidCollectionSourceError,
|
|
56
63
|
InvalidSignalValueError,
|
|
57
64
|
NullishSignalValueError,
|
|
58
65
|
ReadonlySignalError,
|
|
66
|
+
validateCallback,
|
|
67
|
+
validateSignalValue,
|
|
59
68
|
} from './src/errors'
|
|
60
69
|
export { type MatchHandlers, match } from './src/match'
|
|
61
70
|
export { type ResolveResult, resolve } from './src/resolve'
|
|
@@ -71,14 +80,24 @@ export {
|
|
|
71
80
|
batchSignalWrites,
|
|
72
81
|
type Cleanup,
|
|
73
82
|
createWatcher,
|
|
74
|
-
emitNotification,
|
|
75
83
|
flushPendingReactions,
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
84
|
+
HOOK_ADD,
|
|
85
|
+
HOOK_CHANGE,
|
|
86
|
+
HOOK_CLEANUP,
|
|
87
|
+
HOOK_REMOVE,
|
|
88
|
+
HOOK_SORT,
|
|
89
|
+
HOOK_WATCH,
|
|
90
|
+
type Hook,
|
|
91
|
+
type CleanupHook,
|
|
92
|
+
type WatchHook,
|
|
93
|
+
type HookCallback,
|
|
94
|
+
type HookCallbacks,
|
|
95
|
+
isHandledHook,
|
|
79
96
|
notifyWatchers,
|
|
80
97
|
subscribeActiveWatcher,
|
|
81
98
|
trackSignalReads,
|
|
99
|
+
triggerHook,
|
|
100
|
+
UNSET,
|
|
82
101
|
type Watcher,
|
|
83
102
|
} from './src/system'
|
|
84
103
|
export {
|
|
@@ -91,7 +110,5 @@ export {
|
|
|
91
110
|
isRecordOrArray,
|
|
92
111
|
isString,
|
|
93
112
|
isSymbol,
|
|
94
|
-
toError,
|
|
95
|
-
UNSET,
|
|
96
113
|
valueString,
|
|
97
114
|
} from './src/util'
|
package/package.json
CHANGED
|
@@ -1,57 +1,81 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
InvalidCollectionSourceError,
|
|
3
|
+
InvalidHookError,
|
|
4
|
+
validateCallback,
|
|
5
|
+
} from '../errors'
|
|
6
|
+
import type { Signal } from '../signal'
|
|
2
7
|
import {
|
|
3
8
|
type Cleanup,
|
|
4
9
|
createWatcher,
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
10
|
+
HOOK_ADD,
|
|
11
|
+
HOOK_CHANGE,
|
|
12
|
+
HOOK_REMOVE,
|
|
13
|
+
HOOK_SORT,
|
|
14
|
+
HOOK_WATCH,
|
|
15
|
+
type Hook,
|
|
16
|
+
type HookCallback,
|
|
17
|
+
type HookCallbacks,
|
|
18
|
+
isHandledHook,
|
|
8
19
|
notifyWatchers,
|
|
9
20
|
subscribeActiveWatcher,
|
|
10
21
|
trackSignalReads,
|
|
22
|
+
triggerHook,
|
|
23
|
+
UNSET,
|
|
11
24
|
type Watcher,
|
|
12
25
|
} from '../system'
|
|
13
|
-
import { isAsyncFunction, isFunction, isObjectOfType
|
|
26
|
+
import { isAsyncFunction, isFunction, isObjectOfType } from '../util'
|
|
14
27
|
import { type Computed, createComputed } from './computed'
|
|
15
28
|
import { isList, type List } from './list'
|
|
16
29
|
|
|
17
30
|
/* === Types === */
|
|
18
31
|
|
|
19
|
-
|
|
20
|
-
type CollectionSource<T extends {}> = List<T> | Collection<T, any>
|
|
32
|
+
type CollectionSource<T extends {}> = List<T> | Collection<T>
|
|
21
33
|
|
|
22
34
|
type CollectionCallback<T extends {}, U extends {}> =
|
|
23
35
|
| ((sourceValue: U) => T)
|
|
24
36
|
| ((sourceValue: U, abort: AbortSignal) => Promise<T>)
|
|
25
37
|
|
|
38
|
+
type Collection<T extends {}> = {
|
|
39
|
+
readonly [Symbol.toStringTag]: 'Collection'
|
|
40
|
+
readonly [Symbol.isConcatSpreadable]: true
|
|
41
|
+
[Symbol.iterator](): IterableIterator<Signal<T>>
|
|
42
|
+
keys(): IterableIterator<string>
|
|
43
|
+
get: () => T[]
|
|
44
|
+
at: (index: number) => Signal<T> | undefined
|
|
45
|
+
byKey: (key: string) => Signal<T> | undefined
|
|
46
|
+
keyAt: (index: number) => string | undefined
|
|
47
|
+
indexOfKey: (key: string) => number | undefined
|
|
48
|
+
on: <K extends Hook>(type: K, callback: HookCallback) => Cleanup
|
|
49
|
+
deriveCollection: <R extends {}>(
|
|
50
|
+
callback: CollectionCallback<R, T>,
|
|
51
|
+
) => DerivedCollection<R, T>
|
|
52
|
+
readonly length: number
|
|
53
|
+
}
|
|
54
|
+
|
|
26
55
|
/* === Constants === */
|
|
27
56
|
|
|
28
57
|
const TYPE_COLLECTION = 'Collection' as const
|
|
29
58
|
|
|
30
59
|
/* === Class === */
|
|
31
60
|
|
|
32
|
-
class
|
|
61
|
+
class DerivedCollection<T extends {}, U extends {}> implements Collection<T> {
|
|
33
62
|
#watchers = new Set<Watcher>()
|
|
34
63
|
#source: CollectionSource<U>
|
|
35
64
|
#callback: CollectionCallback<T, U>
|
|
36
65
|
#signals = new Map<string, Computed<T>>()
|
|
37
66
|
#ownWatchers = new Map<string, Watcher>()
|
|
38
|
-
#
|
|
39
|
-
add: new Set<Listener<'add'>>(),
|
|
40
|
-
change: new Set<Listener<'change'>>(),
|
|
41
|
-
remove: new Set<Listener<'remove'>>(),
|
|
42
|
-
sort: new Set<Listener<'sort'>>(),
|
|
43
|
-
}
|
|
67
|
+
#hookCallbacks: HookCallbacks = {}
|
|
44
68
|
#order: string[] = []
|
|
45
69
|
|
|
46
70
|
constructor(
|
|
47
71
|
source: CollectionSource<U> | (() => CollectionSource<U>),
|
|
48
72
|
callback: CollectionCallback<T, U>,
|
|
49
73
|
) {
|
|
50
|
-
validateCallback(
|
|
74
|
+
validateCallback(TYPE_COLLECTION, callback)
|
|
51
75
|
|
|
52
76
|
if (isFunction(source)) source = source()
|
|
53
77
|
if (!isCollectionSource(source))
|
|
54
|
-
throw new
|
|
78
|
+
throw new InvalidCollectionSourceError(TYPE_COLLECTION, source)
|
|
55
79
|
this.#source = source
|
|
56
80
|
|
|
57
81
|
this.#callback = callback
|
|
@@ -63,7 +87,8 @@ class Collection<T extends {}, U extends {}> {
|
|
|
63
87
|
this.#add(key)
|
|
64
88
|
}
|
|
65
89
|
|
|
66
|
-
this.#source.on(
|
|
90
|
+
this.#source.on(HOOK_ADD, additions => {
|
|
91
|
+
if (!additions) return
|
|
67
92
|
for (const key of additions) {
|
|
68
93
|
if (!this.#signals.has(key)) {
|
|
69
94
|
this.#add(key)
|
|
@@ -74,51 +99,45 @@ class Collection<T extends {}, U extends {}> {
|
|
|
74
99
|
}
|
|
75
100
|
}
|
|
76
101
|
notifyWatchers(this.#watchers)
|
|
77
|
-
|
|
102
|
+
triggerHook(this.#hookCallbacks.add, additions)
|
|
78
103
|
})
|
|
79
104
|
|
|
80
|
-
this.#source.on(
|
|
105
|
+
this.#source.on(HOOK_REMOVE, removals => {
|
|
106
|
+
if (!removals) return
|
|
81
107
|
for (const key of removals) {
|
|
82
108
|
if (!this.#signals.has(key)) continue
|
|
83
109
|
|
|
84
110
|
this.#signals.delete(key)
|
|
85
111
|
const index = this.#order.indexOf(key)
|
|
86
112
|
if (index >= 0) this.#order.splice(index, 1)
|
|
87
|
-
|
|
113
|
+
|
|
114
|
+
const watcher = this.#ownWatchers.get(key)
|
|
115
|
+
if (watcher) {
|
|
116
|
+
watcher.stop()
|
|
117
|
+
this.#ownWatchers.delete(key)
|
|
118
|
+
}
|
|
88
119
|
}
|
|
89
120
|
this.#order = this.#order.filter(() => true) // Compact array
|
|
90
121
|
notifyWatchers(this.#watchers)
|
|
91
|
-
|
|
122
|
+
triggerHook(this.#hookCallbacks.remove, removals)
|
|
92
123
|
})
|
|
93
124
|
|
|
94
|
-
this.#source.on(
|
|
95
|
-
this.#order = [...newOrder]
|
|
125
|
+
this.#source.on(HOOK_SORT, newOrder => {
|
|
126
|
+
if (newOrder) this.#order = [...newOrder]
|
|
96
127
|
notifyWatchers(this.#watchers)
|
|
97
|
-
|
|
128
|
+
triggerHook(this.#hookCallbacks.sort, newOrder)
|
|
98
129
|
})
|
|
99
130
|
}
|
|
100
131
|
|
|
101
|
-
get #value(): T[] {
|
|
102
|
-
return this.#order
|
|
103
|
-
.map(key => this.#signals.get(key)?.get())
|
|
104
|
-
.filter(v => v != null && v !== UNSET) as T[]
|
|
105
|
-
}
|
|
106
|
-
|
|
107
132
|
#add(key: string): boolean {
|
|
108
133
|
const computedCallback = isAsyncCollectionCallback<T>(this.#callback)
|
|
109
134
|
? async (_: T, abort: AbortSignal) => {
|
|
110
|
-
const
|
|
111
|
-
if (!sourceSignal) return UNSET
|
|
112
|
-
|
|
113
|
-
const sourceValue = sourceSignal.get() as U
|
|
135
|
+
const sourceValue = this.#source.byKey(key)?.get() as U
|
|
114
136
|
if (sourceValue === UNSET) return UNSET
|
|
115
137
|
return this.#callback(sourceValue, abort)
|
|
116
138
|
}
|
|
117
139
|
: () => {
|
|
118
|
-
const
|
|
119
|
-
if (!sourceSignal) return UNSET
|
|
120
|
-
|
|
121
|
-
const sourceValue = sourceSignal.get() as U
|
|
140
|
+
const sourceValue = this.#source.byKey(key)?.get() as U
|
|
122
141
|
if (sourceValue === UNSET) return UNSET
|
|
123
142
|
return (this.#callback as (sourceValue: U) => T)(
|
|
124
143
|
sourceValue,
|
|
@@ -129,7 +148,7 @@ class Collection<T extends {}, U extends {}> {
|
|
|
129
148
|
|
|
130
149
|
this.#signals.set(key, signal)
|
|
131
150
|
if (!this.#order.includes(key)) this.#order.push(key)
|
|
132
|
-
if (this.#
|
|
151
|
+
if (this.#hookCallbacks.change?.size) this.#addWatcher(key)
|
|
133
152
|
return true
|
|
134
153
|
}
|
|
135
154
|
|
|
@@ -143,19 +162,11 @@ class Collection<T extends {}, U extends {}> {
|
|
|
143
162
|
watcher()
|
|
144
163
|
}
|
|
145
164
|
|
|
146
|
-
#removeWatcher(key: string): void {
|
|
147
|
-
const watcher = this.#ownWatchers.get(key)
|
|
148
|
-
if (watcher) {
|
|
149
|
-
watcher.stop()
|
|
150
|
-
this.#ownWatchers.delete(key)
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
165
|
get [Symbol.toStringTag](): 'Collection' {
|
|
155
166
|
return TYPE_COLLECTION
|
|
156
167
|
}
|
|
157
168
|
|
|
158
|
-
get [Symbol.isConcatSpreadable]():
|
|
169
|
+
get [Symbol.isConcatSpreadable](): true {
|
|
159
170
|
return true
|
|
160
171
|
}
|
|
161
172
|
|
|
@@ -166,24 +177,21 @@ class Collection<T extends {}, U extends {}> {
|
|
|
166
177
|
}
|
|
167
178
|
}
|
|
168
179
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
return this.#order.length
|
|
180
|
+
keys(): IterableIterator<string> {
|
|
181
|
+
return this.#order.values()
|
|
172
182
|
}
|
|
173
183
|
|
|
174
184
|
get(): T[] {
|
|
175
|
-
subscribeActiveWatcher(this.#watchers)
|
|
176
|
-
return this.#
|
|
185
|
+
subscribeActiveWatcher(this.#watchers, this.#hookCallbacks[HOOK_WATCH])
|
|
186
|
+
return this.#order
|
|
187
|
+
.map(key => this.#signals.get(key)?.get())
|
|
188
|
+
.filter(v => v != null && v !== UNSET) as T[]
|
|
177
189
|
}
|
|
178
190
|
|
|
179
191
|
at(index: number): Computed<T> | undefined {
|
|
180
192
|
return this.#signals.get(this.#order[index])
|
|
181
193
|
}
|
|
182
194
|
|
|
183
|
-
keys(): IterableIterator<string> {
|
|
184
|
-
return this.#order.values()
|
|
185
|
-
}
|
|
186
|
-
|
|
187
195
|
byKey(key: string): Computed<T> | undefined {
|
|
188
196
|
return this.#signals.get(key)
|
|
189
197
|
}
|
|
@@ -196,34 +204,51 @@ class Collection<T extends {}, U extends {}> {
|
|
|
196
204
|
return this.#order.indexOf(key)
|
|
197
205
|
}
|
|
198
206
|
|
|
199
|
-
on
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
207
|
+
on(type: Hook, callback: HookCallback): Cleanup {
|
|
208
|
+
if (
|
|
209
|
+
isHandledHook(type, [
|
|
210
|
+
HOOK_ADD,
|
|
211
|
+
HOOK_CHANGE,
|
|
212
|
+
HOOK_REMOVE,
|
|
213
|
+
HOOK_SORT,
|
|
214
|
+
HOOK_WATCH,
|
|
215
|
+
])
|
|
216
|
+
) {
|
|
217
|
+
this.#hookCallbacks[type] ||= new Set()
|
|
218
|
+
this.#hookCallbacks[type].add(callback)
|
|
219
|
+
if (type === HOOK_CHANGE && !this.#ownWatchers.size) {
|
|
220
|
+
for (const key of this.#signals.keys()) this.#addWatcher(key)
|
|
221
|
+
}
|
|
204
222
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
223
|
+
return () => {
|
|
224
|
+
this.#hookCallbacks[type]?.delete(callback)
|
|
225
|
+
if (type === HOOK_CHANGE && !this.#hookCallbacks.change?.size) {
|
|
226
|
+
if (this.#ownWatchers.size) {
|
|
227
|
+
for (const watcher of this.#ownWatchers.values())
|
|
228
|
+
watcher.stop()
|
|
229
|
+
this.#ownWatchers.clear()
|
|
230
|
+
}
|
|
212
231
|
}
|
|
213
232
|
}
|
|
214
233
|
}
|
|
234
|
+
throw new InvalidHookError(TYPE_COLLECTION, type)
|
|
215
235
|
}
|
|
216
236
|
|
|
217
237
|
deriveCollection<R extends {}>(
|
|
218
238
|
callback: (sourceValue: T) => R,
|
|
219
|
-
):
|
|
239
|
+
): DerivedCollection<R, T>
|
|
220
240
|
deriveCollection<R extends {}>(
|
|
221
241
|
callback: (sourceValue: T, abort: AbortSignal) => Promise<R>,
|
|
222
|
-
):
|
|
242
|
+
): DerivedCollection<R, T>
|
|
223
243
|
deriveCollection<R extends {}>(
|
|
224
244
|
callback: CollectionCallback<R, T>,
|
|
225
|
-
):
|
|
226
|
-
return new
|
|
245
|
+
): DerivedCollection<R, T> {
|
|
246
|
+
return new DerivedCollection(this, callback)
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
get length(): number {
|
|
250
|
+
subscribeActiveWatcher(this.#watchers, this.#hookCallbacks[HOOK_WATCH])
|
|
251
|
+
return this.#order.length
|
|
227
252
|
}
|
|
228
253
|
}
|
|
229
254
|
|
|
@@ -232,13 +257,13 @@ class Collection<T extends {}, U extends {}> {
|
|
|
232
257
|
/**
|
|
233
258
|
* Check if a value is a collection signal
|
|
234
259
|
*
|
|
235
|
-
* @since 0.17.
|
|
260
|
+
* @since 0.17.2
|
|
236
261
|
* @param {unknown} value - Value to check
|
|
237
262
|
* @returns {boolean} - True if value is a collection signal, false otherwise
|
|
238
263
|
*/
|
|
239
|
-
const isCollection = /*#__PURE__*/ <T extends {}
|
|
264
|
+
const isCollection = /*#__PURE__*/ <T extends {}>(
|
|
240
265
|
value: unknown,
|
|
241
|
-
): value is Collection<T
|
|
266
|
+
): value is Collection<T> => isObjectOfType(value, TYPE_COLLECTION)
|
|
242
267
|
|
|
243
268
|
/**
|
|
244
269
|
* Check if a value is a collection source
|
|
@@ -264,9 +289,10 @@ const isAsyncCollectionCallback = <T extends {}>(
|
|
|
264
289
|
isAsyncFunction(callback)
|
|
265
290
|
|
|
266
291
|
export {
|
|
267
|
-
Collection,
|
|
292
|
+
type Collection,
|
|
268
293
|
type CollectionSource,
|
|
269
294
|
type CollectionCallback,
|
|
295
|
+
DerivedCollection,
|
|
270
296
|
isCollection,
|
|
271
297
|
TYPE_COLLECTION,
|
|
272
298
|
}
|
package/src/classes/composite.ts
CHANGED
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
import type { DiffResult, UnknownRecord } from '../diff'
|
|
2
|
-
import { guardMutableSignal } from '../errors'
|
|
2
|
+
import { guardMutableSignal, InvalidHookError } from '../errors'
|
|
3
3
|
import type { Signal } from '../signal'
|
|
4
4
|
import {
|
|
5
5
|
batchSignalWrites,
|
|
6
6
|
type Cleanup,
|
|
7
7
|
createWatcher,
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
HOOK_ADD,
|
|
9
|
+
HOOK_CHANGE,
|
|
10
|
+
HOOK_REMOVE,
|
|
11
|
+
type HookCallback,
|
|
12
|
+
type HookCallbacks,
|
|
13
|
+
isHandledHook,
|
|
11
14
|
trackSignalReads,
|
|
15
|
+
triggerHook,
|
|
12
16
|
type Watcher,
|
|
13
17
|
} from '../system'
|
|
14
18
|
|
|
15
19
|
/* === Types === */
|
|
16
20
|
|
|
17
|
-
type
|
|
21
|
+
type CompositeHook = 'add' | 'change' | 'remove'
|
|
18
22
|
|
|
19
23
|
/* === Class Definitions === */
|
|
20
24
|
|
|
@@ -26,11 +30,7 @@ class Composite<T extends UnknownRecord, S extends Signal<T[keyof T] & {}>> {
|
|
|
26
30
|
) => value is T[K] & {}
|
|
27
31
|
#create: <V extends T[keyof T] & {}>(value: V) => S
|
|
28
32
|
#watchers = new Map<string, Watcher>()
|
|
29
|
-
#
|
|
30
|
-
add: new Set<Listener<'add'>>(),
|
|
31
|
-
change: new Set<Listener<'change'>>(),
|
|
32
|
-
remove: new Set<Listener<'remove'>>(),
|
|
33
|
-
}
|
|
33
|
+
#hookCallbacks: HookCallbacks = {}
|
|
34
34
|
#batching = false
|
|
35
35
|
|
|
36
36
|
constructor(
|
|
@@ -59,7 +59,7 @@ class Composite<T extends UnknownRecord, S extends Signal<T[keyof T] & {}>> {
|
|
|
59
59
|
trackSignalReads(watcher, () => {
|
|
60
60
|
this.signals.get(key)?.get() // Subscribe to the signal
|
|
61
61
|
if (!this.#batching)
|
|
62
|
-
|
|
62
|
+
triggerHook(this.#hookCallbacks.change, [key])
|
|
63
63
|
})
|
|
64
64
|
})
|
|
65
65
|
this.#watchers.set(key, watcher)
|
|
@@ -70,9 +70,9 @@ class Composite<T extends UnknownRecord, S extends Signal<T[keyof T] & {}>> {
|
|
|
70
70
|
if (!this.#validate(key, value)) return false
|
|
71
71
|
|
|
72
72
|
this.signals.set(key, this.#create(value))
|
|
73
|
-
if (this.#
|
|
73
|
+
if (this.#hookCallbacks.change?.size) this.#addWatcher(key)
|
|
74
74
|
|
|
75
|
-
if (!this.#batching)
|
|
75
|
+
if (!this.#batching) triggerHook(this.#hookCallbacks.add, [key])
|
|
76
76
|
return true
|
|
77
77
|
}
|
|
78
78
|
|
|
@@ -86,7 +86,7 @@ class Composite<T extends UnknownRecord, S extends Signal<T[keyof T] & {}>> {
|
|
|
86
86
|
this.#watchers.delete(key)
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
if (!this.#batching)
|
|
89
|
+
if (!this.#batching) triggerHook(this.#hookCallbacks.remove, [key])
|
|
90
90
|
return true
|
|
91
91
|
}
|
|
92
92
|
|
|
@@ -103,7 +103,7 @@ class Composite<T extends UnknownRecord, S extends Signal<T[keyof T] & {}>> {
|
|
|
103
103
|
|
|
104
104
|
// Queue initial additions event to allow listeners to be added first
|
|
105
105
|
const notify = () =>
|
|
106
|
-
|
|
106
|
+
triggerHook(this.#hookCallbacks.add, Object.keys(changes.add))
|
|
107
107
|
if (initialRun) setTimeout(notify, 0)
|
|
108
108
|
else notify()
|
|
109
109
|
}
|
|
@@ -121,20 +121,14 @@ class Composite<T extends UnknownRecord, S extends Signal<T[keyof T] & {}>> {
|
|
|
121
121
|
signal.set(value)
|
|
122
122
|
}
|
|
123
123
|
})
|
|
124
|
-
|
|
125
|
-
this.#listeners.change,
|
|
126
|
-
Object.keys(changes.change),
|
|
127
|
-
)
|
|
124
|
+
triggerHook(this.#hookCallbacks.change, Object.keys(changes.change))
|
|
128
125
|
}
|
|
129
126
|
|
|
130
127
|
// Removals
|
|
131
128
|
if (Object.keys(changes.remove).length) {
|
|
132
129
|
for (const key in changes.remove)
|
|
133
130
|
this.remove(key as keyof T & string)
|
|
134
|
-
|
|
135
|
-
this.#listeners.remove,
|
|
136
|
-
Object.keys(changes.remove),
|
|
137
|
-
)
|
|
131
|
+
triggerHook(this.#hookCallbacks.remove, Object.keys(changes.remove))
|
|
138
132
|
}
|
|
139
133
|
|
|
140
134
|
this.#batching = false
|
|
@@ -145,24 +139,25 @@ class Composite<T extends UnknownRecord, S extends Signal<T[keyof T] & {}>> {
|
|
|
145
139
|
const keys = Array.from(this.signals.keys())
|
|
146
140
|
this.signals.clear()
|
|
147
141
|
this.#watchers.clear()
|
|
148
|
-
|
|
142
|
+
triggerHook(this.#hookCallbacks.remove, keys)
|
|
149
143
|
return true
|
|
150
144
|
}
|
|
151
145
|
|
|
152
|
-
on
|
|
153
|
-
type
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
this.#
|
|
157
|
-
|
|
146
|
+
on(type: CompositeHook, callback: HookCallback): Cleanup {
|
|
147
|
+
if (!isHandledHook(type, [HOOK_ADD, HOOK_CHANGE, HOOK_REMOVE]))
|
|
148
|
+
throw new InvalidHookError('Composite', type)
|
|
149
|
+
|
|
150
|
+
this.#hookCallbacks[type] ||= new Set()
|
|
151
|
+
this.#hookCallbacks[type].add(callback)
|
|
152
|
+
if (type === HOOK_CHANGE && !this.#watchers.size) {
|
|
158
153
|
this.#batching = true
|
|
159
154
|
for (const key of this.signals.keys()) this.#addWatcher(key)
|
|
160
155
|
this.#batching = false
|
|
161
156
|
}
|
|
162
157
|
|
|
163
158
|
return () => {
|
|
164
|
-
this.#
|
|
165
|
-
if (type ===
|
|
159
|
+
this.#hookCallbacks[type]?.delete(callback)
|
|
160
|
+
if (type === HOOK_CHANGE && !this.#hookCallbacks.change?.size) {
|
|
166
161
|
if (this.#watchers.size) {
|
|
167
162
|
for (const watcher of this.#watchers.values())
|
|
168
163
|
watcher.stop()
|
|
@@ -173,4 +168,4 @@ class Composite<T extends UnknownRecord, S extends Signal<T[keyof T] & {}>> {
|
|
|
173
168
|
}
|
|
174
169
|
}
|
|
175
170
|
|
|
176
|
-
export { Composite, type CompositeListeners }
|
|
171
|
+
export { Composite, type CompositeHook as CompositeListeners }
|