muya 2.0.1 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -217,6 +217,40 @@ const asyncState = state.select(async (s) => {
217
217
  ```
218
218
  ---
219
219
 
220
+ ### Lazy resolution
221
+ `Muya` can be used in `immediate` mode or in `lazy` mode. When create a state with just plain data, it will be in immediate mode, but if you create a state with a function, it will be in lazy mode. This is useful when you want to create a state that is executed only when it is accessed for the first time.
222
+
223
+
224
+ ```typescript
225
+ // immediate mode, so no matter what, this value is already stored in memory
226
+ const state = create(0)
227
+
228
+ // lazy mode, value is not stored in memory until it is accessed for the first time via get or component render
229
+ const state = create(() => 0)
230
+ ```
231
+
232
+ And in async:
233
+ ```typescript
234
+ // we can create some initial functions like this
235
+ async function initialLoad() {
236
+ return 0
237
+ }
238
+ // immediate mode, so no matter what, this value is already stored in memory
239
+ const state = create(initialLoad)
240
+ // or
241
+ const state = create(Promise.resolve(0))
242
+
243
+ // lazy mode, value is not stored in memory until it is accessed for the first time via get or component render
244
+ const state = create(() => Promise.resolve(0))
245
+ ```
246
+
247
+ And when setting state when initial value is promise, set is always sync.
248
+ But as in react there are two methods how to set a state. Directly `.set(2)` or with a function `.set((prev) => prev + 1)`.
249
+
250
+ So how `set` state will behave with async initial value?
251
+ 1. Directly call `.set(2)` will be sync, and will set the value to 2 (it will cancel the initial promise)
252
+ 2. Call `.set((prev) => prev + 1)` will wait until previous promise is resolved, so previous value in set callback is always resolved.
253
+
220
254
  ### Debugging
221
255
  `Muya` in dev mode automatically connects to the `redux` devtools extension if it is installed in the browser. For now devtool api is simple - state updates.
222
256
 
package/cjs/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";var x=Object.defineProperty;var q=Object.getOwnPropertyDescriptor;var R=Object.getOwnPropertyNames;var F=Object.prototype.hasOwnProperty;var L=(e,t)=>{for(var r in t)x(e,r,{get:t[r],enumerable:!0})},M=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of R(t))!F.call(e,i)&&i!==r&&x(e,i,{get:()=>t[i],enumerable:!(o=q(t,i))||o.enumerable});return e};var z=e=>M(x({},"__esModule",{value:!0}),e);var N={};L(N,{EMPTY_SELECTOR:()=>w,create:()=>G,select:()=>b,shallow:()=>U,useValue:()=>E});module.exports=z(N);var w=e=>e;function T(e){return e instanceof Promise}function O(e){return typeof e=="function"}function g(e){return e instanceof Map}function k(e){return e instanceof Set}function C(e){return Array.isArray(e)}function f(e,t){return e===t?!0:!!Object.is(e,t)}function V(e){return typeof e=="function"}function P(e){return e instanceof DOMException&&e.name==="StateAbortError"}function I(e){return e instanceof Error}function l(e){return e===void 0}function A(e,t){t&&t.abort();let r=new AbortController,{signal:o}=r;return{promise:new Promise((n,a)=>{o.addEventListener("abort",()=>{a(new DOMException("Promise was aborted","StateAbortError"))}),e.then(n).catch(a)}),controller:r}}function S(e,t=f){if(!l(e.current)){if(!l(e.previous)&&t(e.current,e.previous))return!1;e.previous=e.current}return!0}function p(e,t,r){if(!T(r))return r;e.abortController&&e.abortController.abort();let{promise:o,controller:i}=A(r,e.abortController);return e.abortController=i,o.then(n=>{e.current=n,t()}).catch(n=>{P(n)||(e.current=n,t())})}function D(){let e=new Map,t=new Set,r=performance.now(),o=!1;function i(){let a=performance.now(),s=a-r,{size:u}=t;if(s<.2&&u>0&&u<10){r=a,n();return}o||(o=!0,Promise.resolve().then(()=>{o=!1,r=performance.now(),n()}))}function n(){if(t.size===0)return;let a=new Set;for(let s of t){if(e.has(s.id)){a.add(s.id);let{onResolveItem:u}=e.get(s.id);u&&u(s.value)}t.delete(s)}if(t.size>0){i();return}for(let s of a)e.get(s)?.onFinish()}return{add(a,s){return e.set(a,s),()=>{e.delete(a)}},schedule(a,s){t.add({value:s,id:a}),i()}}}function b(e,t,r){let o={};function i(){let c=e.map(m=>m.get());return t(...c)}function n(){if(l(o.current)){let c=i();o.current=p(o,s.emitter.emit,c)}return o.current}let a=[];for(let c of e){let m=c.emitter.subscribe(()=>{d.schedule(s.id,null)});a.push(m)}let s=h({destroy(){for(let c of a)c();u(),s.emitter.clear(),o.current=void 0},get:n}),u=d.add(s.id,{onFinish(){let c=i();o.current=p(o,s.emitter.emit,c),S(o,r)&&s.emitter.emit()}});return s}var y=require("react");function E(e,t=w){let{emitter:r}=e,o=(0,y.useSyncExternalStore)(e.emitter.subscribe,()=>t(r.getSnapshot()),()=>t(r.getInitialSnapshot?r.getInitialSnapshot():r.getSnapshot()));if((0,y.useDebugValue)(o),T(o)||I(o))throw o;return o}function v(e,t){let r=new Set,o=[];return{clear:()=>{for(let i of o)i();r.clear()},subscribe:i=>(r.add(i),()=>{r.delete(i)}),emit:(...i)=>{for(let n of r)n(...i)},contains:i=>r.has(i),getSnapshot:e,getInitialSnapshot:t,getSize:()=>r.size,subscribeToOtherEmitter(i){let n=i.subscribe(()=>{this.emit()});o.push(n)}}}var H=0;function j(){return H++}function h(e){let{get:t,destroy:r,set:o}=e,i=!!o,n=function(a){return E(n,a)};return n.isSet=i,n.id=j(),n.emitter=v(t),n.destroy=r,n.listen=function(a){return this.emitter.subscribe(()=>{a(t())})},n.withName=function(a){return this.stateName=a,this},n.select=function(a,s=f){return b([n],a,s)},n.get=t,n.set=o,n}var d=D();function G(e,t=f){let r={};function o(){try{if(l(r.current)){let s=O(e)?e():e,u=p(r,n.emitter.emit,s);r.current=u}return r.current}catch(s){r.current=s}return r.current}function i(s){r.abortController&&r.abortController.abort();let u=o(),c=V(s)?s(u):s,m=p(r,n.emitter.emit,c);r.current=m}let n=h({get:o,destroy(){o(),a(),n.emitter.clear(),r.current=void 0},set(s){d.schedule(n.id,s)}}),a=d.add(n.id,{onFinish(){r.current=o(),S(r,t)&&n.emitter.emit()},onResolveItem:i});return n}function U(e,t){if(e==t)return!0;if(typeof e!="object"||e==null||typeof t!="object"||t==null)return!1;if(g(e)&&g(t)){if(e.size!==t.size)return!1;for(let[i,n]of e)if(!Object.is(n,t.get(i)))return!1;return!0}if(k(e)&&k(t)){if(e.size!==t.size)return!1;for(let i of e)if(!t.has(i))return!1;return!0}if(C(e)&&C(t)){if(e.length!==t.length)return!1;for(let[i,n]of e.entries())if(!Object.is(n,t[i]))return!1;return!0}let r=Object.keys(e),o=Object.keys(t);if(r.length!==o.length)return!1;for(let i of r)if(!Object.prototype.hasOwnProperty.call(t,i)||!Object.is(e[i],t[i]))return!1;return!0}
1
+ "use strict";var g=Object.defineProperty;var R=Object.getOwnPropertyDescriptor;var L=Object.getOwnPropertyNames;var z=Object.prototype.hasOwnProperty;var H=(e,t)=>{for(var r in t)g(e,r,{get:t[r],enumerable:!0})},M=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of L(t))!z.call(e,o)&&o!==r&&g(e,o,{get:()=>t[o],enumerable:!(n=R(t,o))||n.enumerable});return e};var j=e=>M(g({},"__esModule",{value:!0}),e);var Y={};H(Y,{EMPTY_SELECTOR:()=>k,create:()=>q,select:()=>h,shallow:()=>A,useValue:()=>x});module.exports=j(Y);var k=e=>e;function p(e){return e instanceof Promise}function C(e){return typeof e=="function"}function V(e){return e instanceof Map}function P(e){return e instanceof Set}function O(e){return Array.isArray(e)}function d(e,t){return e===t?!0:!!Object.is(e,t)}function I(e){return typeof e=="function"}function v(e){return e instanceof T}function G(e){return e instanceof Error}function f(e){return e===void 0}var T=class extends Error{static Error="AbortError"};function N(e,t){t&&t.abort();let r=new AbortController,{signal:n}=r;return{promise:new Promise((i,s)=>{n.addEventListener("abort",()=>{s(new T)}),e.then(i).catch(s)}),controller:r}}function b(e,t=d){if(!f(e.current)){if(!f(e.previous)&&t(e.current,e.previous))return!1;e.previous=e.current}return!0}function m(e,t,r){if(!p(r))return r;e.abortController&&e.abortController.abort();let{promise:n,controller:o}=N(r,e.abortController);return e.abortController=o,n.then(i=>{e.current=i,t()}).catch(i=>{v(i)||(e.current=i,t())})}function D(){let e=new Map,t=new Set,r=performance.now(),n=!1;function o(){let s=performance.now(),a=s-r,{size:u}=t;if(a<.2&&u>0&&u<10){r=s,i();return}n||(n=!0,Promise.resolve().then(()=>{n=!1,r=performance.now(),i()}))}function i(){if(t.size===0)return;let s=new Set;for(let a of t){if(e.has(a.id)){s.add(a.id);let{onResolveItem:u}=e.get(a.id);u&&u(a.value)}t.delete(a)}if(t.size>0){o();return}for(let a of s)e.get(a)?.onFinish()}return{add(s,a){return e.set(s,a),()=>{e.delete(s)}},schedule(s,a){t.add({value:a,id:s}),o()}}}function h(e,t,r){let n={};function o(){let c=e.map(l=>l.get());return t(...c)}function i(){if(f(n.current)){let c=o();n.current=m(n,a.emitter.emit,c)}return n.current}let s=[];for(let c of e){let l=c.emitter.subscribe(()=>{S.schedule(a.id,null)});s.push(l)}let a=y({destroy(){for(let c of s)c();u(),a.emitter.clear(),n.current=void 0},get:i}),u=S.add(a.id,{onFinish(){let c=o();n.current=m(n,a.emitter.emit,c),b(n,r)&&a.emitter.emit()}});return a}var w=require("react");function x(e,t=k){let{emitter:r}=e,n=(0,w.useSyncExternalStore)(e.emitter.subscribe,()=>t(r.getSnapshot()),()=>t(r.getInitialSnapshot?r.getInitialSnapshot():r.getSnapshot()));if((0,w.useDebugValue)(n),p(n)||G(n))throw n;return n}function U(e,t){let r=new Set,n=[];return{clear:()=>{for(let o of n)o();r.clear()},subscribe:o=>(r.add(o),()=>{r.delete(o)}),emit:(...o)=>{for(let i of r)i(...o)},contains:o=>r.has(o),getSnapshot:e,getInitialSnapshot:t,getSize:()=>r.size,subscribeToOtherEmitter(o){let i=o.subscribe(()=>{this.emit()});n.push(i)}}}var _=0;function K(){return _++}function y(e){let{get:t,destroy:r,set:n}=e,o=!!n,i=function(s){return x(i,s)};return i.isSet=o,i.id=K(),i.emitter=U(t),i.destroy=r,i.listen=function(s){return this.emitter.subscribe(()=>{s(t())})},i.withName=function(s){return this.stateName=s,this},i.select=function(s,a=d){return h([i],s,a)},i.get=t,i.set=n,i}var S=D();function q(e,t=d){let r={};function n(){try{if(f(r.current)){let u=C(e)?e():e,c=m(r,s.emitter.emit,u);return r.current=c,r.current}return r.current}catch(u){r.current=u}return r.current}async function o(u,c){await u;let l=c(r.current),E=m(r,s.emitter.emit,l);r.current=E}function i(u){let c=n(),l=I(u);if(l&&p(c)){o(c,u);return}r.abortController&&r.abortController.abort();let E=l?u(c):u,F=m(r,s.emitter.emit,E);r.current=F}let s=y({get:n,destroy(){n(),a(),s.emitter.clear(),r.current=void 0},set(u){S.schedule(s.id,u)}}),a=S.add(s.id,{onFinish(){r.current=n(),b(r,t)&&s.emitter.emit()},onResolveItem:i});return C(e)||n(),s}function A(e,t){if(e==t)return!0;if(typeof e!="object"||e==null||typeof t!="object"||t==null)return!1;if(V(e)&&V(t)){if(e.size!==t.size)return!1;for(let[o,i]of e)if(!Object.is(i,t.get(o)))return!1;return!0}if(P(e)&&P(t)){if(e.size!==t.size)return!1;for(let o of e)if(!t.has(o))return!1;return!0}if(O(e)&&O(t)){if(e.length!==t.length)return!1;for(let[o,i]of e.entries())if(!Object.is(i,t[o]))return!1;return!0}let r=Object.keys(e),n=Object.keys(t);if(r.length!==n.length)return!1;for(let o of r)if(!Object.prototype.hasOwnProperty.call(t,o)||!Object.is(e[o],t[o]))return!1;return!0}
package/esm/create.js CHANGED
@@ -1 +1 @@
1
- import{canUpdate as f,handleAsyncUpdate as u}from"./utils/common";import{isEqualBase as p,isFunction as T,isSetValueFunction as h,isUndefined as S}from"./utils/is";import{createScheduler as V}from"./scheduler";import{subscribeToDevelopmentTools as b}from"./debug/development-tools";import{createState as y}from"./create-state";const a=V();function F(n,s=p){const e={};function o(){try{if(S(e.current)){const t=T(n)?n():n,c=u(e,r.emitter.emit,t);e.current=c}return e.current}catch(t){e.current=t}return e.current}function i(t){e.abortController&&e.abortController.abort();const c=o(),m=h(t)?t(c):t,d=u(e,r.emitter.emit,m);e.current=d}const r=y({get:o,destroy(){o(),l(),r.emitter.clear(),e.current=void 0},set(t){a.schedule(r.id,t)}}),l=a.add(r.id,{onFinish(){e.current=o(),f(e,s)&&r.emitter.emit()},onResolveItem:i});return b(r),r}export{F as create,a as stateScheduler};
1
+ import{canUpdate as p,handleAsyncUpdate as u}from"./utils/common";import{isEqualBase as V,isFunction as i,isPromise as h,isSetValueFunction as b,isUndefined as y}from"./utils/is";import{createScheduler as C}from"./scheduler";import{subscribeToDevelopmentTools as w}from"./debug/development-tools";import{createState as v}from"./create-state";const l=C();function I(c,m=V){const e={};function o(){try{if(y(e.current)){const t=i(c)?c():c,n=u(e,r.emitter.emit,t);return e.current=n,e.current}return e.current}catch(t){e.current=t}return e.current}async function d(t,n){await t;const a=n(e.current),s=u(e,r.emitter.emit,a);e.current=s}function f(t){const n=o(),a=b(t);if(a&&h(n)){d(n,t);return}e.abortController&&e.abortController.abort();const s=a?t(n):t,S=u(e,r.emitter.emit,s);e.current=S}const r=v({get:o,destroy(){o(),T(),r.emitter.clear(),e.current=void 0},set(t){l.schedule(r.id,t)}}),T=l.add(r.id,{onFinish(){e.current=o(),p(e,m)&&r.emitter.emit()},onResolveItem:f});return i(c)||o(),w(r),r}export{I as create,l as stateScheduler};
@@ -1 +1 @@
1
- import{isPromise as a,isState as p}from"../utils/is";const o=window?.__REDUX_DEVTOOLS_EXTENSION__?.connect({name:"CustomState",trace:!0});o&&o.init({message:"Initial state"});function s(e){if(!o)return;const{message:t,type:n,value:i,name:r}=e;a(i)||o.send(r,{value:i,type:n,message:t},n)}function m(e,t){return n=>{s({name:e,type:t,value:n,message:"update"})}}function l(e){}export{l as subscribeToDevelopmentTools};
1
+ import{isPromise as r,isState as a}from"../utils/is";const o=window?.__REDUX_DEVTOOLS_EXTENSION__?.connect({name:"CustomState",trace:!0});o&&o.init({message:"Initial state"});function p(e){if(!o)return;const{message:t,type:n,value:s,name:i}=e;r(s)||o.send(i,{value:s,type:n,message:t},n)}function m(e,t){return n=>{p({name:e,type:t,value:n,message:"update"})}}function S(e){}export{S as subscribeToDevelopmentTools};
@@ -1 +1 @@
1
- import{create as r}from"../../create";import{isPromise as o,isFunction as s,isSetValueFunction as u,isMap as i,isSet as n,isArray as a,isEqualBase as f,isUndefined as l,isState as e}from"../is";describe("isPromise",()=>{it("should return true for a Promise",()=>{expect(o(Promise.resolve())).toBe(!0)}),it("should return false for a non-Promise",()=>{expect(o(123)).toBe(!1)})}),describe("isFunction",()=>{it("should return true for a function",()=>{expect(s(()=>{})).toBe(!0)}),it("should return false for a non-function",()=>{expect(s(123)).toBe(!1)})}),describe("isSetValueFunction",()=>{it("should return true for a function",()=>{expect(u(()=>{})).toBe(!0)}),it("should return false for a non-function",()=>{expect(u(123)).toBe(!1)})}),describe("isMap",()=>{it("should return true for a Map",()=>{expect(i(new Map)).toBe(!0)}),it("should return false for a non-Map",()=>{expect(i(123)).toBe(!1)})}),describe("isSet",()=>{it("should return true for a Set",()=>{expect(n(new Set)).toBe(!0)}),it("should return false for a non-Set",()=>{expect(n(123)).toBe(!1)})}),describe("isArray",()=>{it("should return true for an array",()=>{expect(a([])).toBe(!0)}),it("should return false for a non-array",()=>{expect(a(123)).toBe(!1)})}),describe("isEqualBase",()=>{it("should return true for equal values",()=>{expect(f(1,1)).toBe(!0)}),it("should return false for non-equal values",()=>{expect(f(1,2)).toBe(!1)})}),describe("isUndefined",()=>{it("should return true for undefined",()=>{expect(l(void 0)).toBe(!0)}),it("should return false for a non-undefined",()=>{expect(l(123)).toBe(!1)})}),describe("isState",()=>{it("should return true for a State real",()=>{const t=r(1);expect(e(t)).toBe(!0)}),it("should return true for a State with derived",()=>{const d=r(1).select(c=>c);expect(e(d)).toBe(!1)}),it("should return false for a non-State",()=>{expect(e(123)).toBe(!1)})});
1
+ import{create as r}from"../../create";import{AbortError as B}from"../common";import{isPromise as o,isFunction as s,isSetValueFunction as u,isMap as n,isSet as i,isArray as a,isEqualBase as f,isUndefined as l,isState as t,isAbortError as c}from"../is";describe("isPromise",()=>{it("should return true for a Promise",()=>{expect(o(Promise.resolve())).toBe(!0)}),it("should return false for a non-Promise",()=>{expect(o(123)).toBe(!1)})}),describe("isFunction",()=>{it("should return true for a function",()=>{expect(s(()=>{})).toBe(!0)}),it("should return false for a non-function",()=>{expect(s(123)).toBe(!1)})}),describe("isSetValueFunction",()=>{it("should return true for a function",()=>{expect(u(()=>{})).toBe(!0)}),it("should return false for a non-function",()=>{expect(u(123)).toBe(!1)})}),describe("isMap",()=>{it("should return true for a Map",()=>{expect(n(new Map)).toBe(!0)}),it("should return false for a non-Map",()=>{expect(n(123)).toBe(!1)})}),describe("isSet",()=>{it("should return true for a Set",()=>{expect(i(new Set)).toBe(!0)}),it("should return false for a non-Set",()=>{expect(i(123)).toBe(!1)})}),describe("isArray",()=>{it("should return true for an array",()=>{expect(a([])).toBe(!0)}),it("should return false for a non-array",()=>{expect(a(123)).toBe(!1)})}),describe("isEqualBase",()=>{it("should return true for equal values",()=>{expect(f(1,1)).toBe(!0)}),it("should return false for non-equal values",()=>{expect(f(1,2)).toBe(!1)})}),describe("isUndefined",()=>{it("should return true for undefined",()=>{expect(l(void 0)).toBe(!0)}),it("should return false for a non-undefined",()=>{expect(l(123)).toBe(!1)})}),describe("isState",()=>{it("should return true for a State real",()=>{const e=r(1);expect(t(e)).toBe(!0)}),it("should return true for a State with derived",()=>{const d=r(1).select(p=>p);expect(t(d)).toBe(!1)}),it("should return false for a non-State",()=>{expect(t(123)).toBe(!1)})}),describe("isAbortError",()=>{it("should return true for an AbortError",()=>{const e=new B;expect(c(e)).toBe(!0)}),it("should return false for a non-AbortError",()=>{const e=new Error("asd");expect(c(e)).toBe(!1)})});
@@ -1 +1 @@
1
- import{isAbortError as a,isEqualBase as b,isPromise as u,isUndefined as s}from"./is";var p=(o=>(o.Error="StateAbortError",o))(p||{});function T(r,o){o&&o.abort();const e=new AbortController,{signal:n}=e;return{promise:new Promise((t,l)=>{n.addEventListener("abort",()=>{l(new DOMException("Promise was aborted","StateAbortError"))}),r.then(t).catch(l)}),controller:e}}function f(r,o=b){if(!s(r.current)){if(!s(r.previous)&&o(r.current,r.previous))return!1;r.previous=r.current}return!0}function c(r,o,e){if(!u(e))return e;r.abortController&&r.abortController.abort();const{promise:n,controller:i}=T(e,r.abortController);return r.abortController=i,n.then(t=>{r.current=t,o()}).catch(t=>{a(t)||(r.current=t,o())})}export{p as Abort,f as canUpdate,c as handleAsyncUpdate};
1
+ import{isAbortError as a,isEqualBase as b,isPromise as u,isUndefined as i}from"./is";class T extends Error{static Error="AbortError"}function p(r,o){o&&o.abort();const t=new AbortController,{signal:n}=t;return{promise:new Promise((e,s)=>{n.addEventListener("abort",()=>{s(new T)}),r.then(e).catch(s)}),controller:t}}function f(r,o=b){if(!i(r.current)){if(!i(r.previous)&&o(r.current,r.previous))return!1;r.previous=r.current}return!0}function m(r,o,t){if(!u(t))return t;r.abortController&&r.abortController.abort();const{promise:n,controller:l}=p(t,r.abortController);return r.abortController=l,n.then(e=>{r.current=e,o()}).catch(e=>{a(e)||(r.current=e,o())})}export{T as AbortError,f as canUpdate,m as handleAsyncUpdate};
package/esm/utils/is.js CHANGED
@@ -1 +1 @@
1
- import{Abort as e}from"./common";function i(n){return n instanceof Promise}function r(n){return typeof n=="function"}function u(n){return n instanceof Map}function s(n){return n instanceof Set}function a(n){return Array.isArray(n)}function f(n,t){return n===t?!0:!!Object.is(n,t)}function c(n){return typeof n=="function"}function p(n){return n instanceof DOMException&&n.name===e.Error}function k(n){return n instanceof Error}function w(n){return n===void 0}function S(n){return r(n)&&"get"in n&&"set"in n&&"isSet"in n&&n.isSet===!0}export{p as isAbortError,a as isArray,f as isEqualBase,k as isError,r as isFunction,u as isMap,i as isPromise,s as isSet,c as isSetValueFunction,S as isState,w as isUndefined};
1
+ import{AbortError as r}from"./common";function i(n){return n instanceof Promise}function e(n){return typeof n=="function"}function u(n){return n instanceof Map}function s(n){return n instanceof Set}function a(n){return Array.isArray(n)}function f(n,t){return n===t?!0:!!Object.is(n,t)}function c(n){return typeof n=="function"}function p(n){return n instanceof r}function k(n){return n instanceof Error}function w(n){return n===void 0}function S(n){return e(n)&&"get"in n&&"set"in n&&"isSet"in n&&n.isSet===!0}export{p as isAbortError,a as isArray,f as isEqualBase,k as isError,e as isFunction,u as isMap,i as isPromise,s as isSet,c as isSetValueFunction,S as isState,w as isUndefined};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "muya",
3
- "version": "2.0.1",
3
+ "version": "2.0.3",
4
4
  "author": "samuel.gjabel@gmail.com",
5
5
  "repository": "https://github.com/samuelgjabel/muya",
6
6
  "main": "cjs/index.js",
@@ -1,6 +1,7 @@
1
1
  import { create } from '../create'
2
2
  import { waitFor } from '@testing-library/react'
3
3
  import { longPromise } from './test-utils'
4
+ import { isPromise } from '../utils/is'
4
5
 
5
6
  describe('create', () => {
6
7
  it('should get basic value states', async () => {
@@ -56,9 +57,16 @@ describe('create', () => {
56
57
  })
57
58
  })
58
59
 
59
- it('should initialize state with a function', () => {
60
+ it('should initialize state with a lazy value', () => {
60
61
  const initialValue = jest.fn(() => 10)
61
62
  const state = create(initialValue)
63
+ expect(initialValue).not.toHaveBeenCalled()
64
+ expect(state.get()).toBe(10)
65
+ })
66
+
67
+ it('should initialize state with direct lazy value', () => {
68
+ const initialValue = jest.fn(() => 10)
69
+ const state = create(initialValue())
62
70
  expect(initialValue).toHaveBeenCalled()
63
71
  expect(state.get()).toBe(10)
64
72
  })
@@ -156,4 +164,62 @@ describe('create', () => {
156
164
  expect(listener).toHaveBeenCalledWith(2)
157
165
  })
158
166
  })
167
+
168
+ it('should resolve immediately when state is promise', async () => {
169
+ const promiseMock = jest.fn(() => longPromise(100))
170
+ const state1 = create(promiseMock())
171
+ expect(promiseMock).toHaveBeenCalled()
172
+ state1.set((value) => {
173
+ // set with callback will be executed later when promise is resolved
174
+ expect(isPromise(value)).toBe(false)
175
+ return value + 1
176
+ })
177
+
178
+ await waitFor(() => {
179
+ expect(state1.get()).toBe(1)
180
+ })
181
+
182
+ state1.set(2)
183
+ await waitFor(() => {
184
+ expect(state1.get()).toBe(2)
185
+ })
186
+
187
+ state1.set((value) => {
188
+ expect(isPromise(value)).toBe(false)
189
+ return value + 1
190
+ })
191
+
192
+ await waitFor(() => {
193
+ expect(state1.get()).toBe(3)
194
+ })
195
+ })
196
+
197
+ it('should resolve lazy when state is promise', async () => {
198
+ const promiseMock = jest.fn(() => longPromise(100))
199
+ const state1 = create(promiseMock)
200
+ expect(promiseMock).not.toHaveBeenCalled()
201
+ state1.set((value) => {
202
+ // set with callback will be executed later when promise is resolved
203
+ expect(isPromise(value)).toBe(false)
204
+ return value + 1
205
+ })
206
+
207
+ await waitFor(() => {
208
+ expect(state1.get()).toBe(1)
209
+ })
210
+
211
+ state1.set(2)
212
+ await waitFor(() => {
213
+ expect(state1.get()).toBe(2)
214
+ })
215
+
216
+ state1.set((value) => {
217
+ expect(isPromise(value)).toBe(false)
218
+ return value + 1
219
+ })
220
+
221
+ await waitFor(() => {
222
+ expect(state1.get()).toBe(3)
223
+ })
224
+ })
159
225
  })
package/src/create.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { canUpdate, handleAsyncUpdate } from './utils/common'
2
- import { isEqualBase, isFunction, isSetValueFunction, isUndefined } from './utils/is'
3
- import type { Cache, DefaultValue, IsEqual, SetValue, State } from './types'
2
+ import { isEqualBase, isFunction, isPromise, isSetValueFunction, isUndefined } from './utils/is'
3
+ import type { Cache, DefaultValue, IsEqual, SetStateCb, SetValue, State } from './types'
4
4
  import { createScheduler } from './scheduler'
5
5
  import { subscribeToDevelopmentTools } from './debug/development-tools'
6
6
  import { createState } from './create-state'
@@ -19,21 +19,37 @@ export function create<T>(initialValue: DefaultValue<T>, isEqual: IsEqual<T> = i
19
19
  const value = isFunction(initialValue) ? initialValue() : initialValue
20
20
  const resolvedValue = handleAsyncUpdate(cache, state.emitter.emit, value)
21
21
  cache.current = resolvedValue
22
+
23
+ return cache.current
22
24
  }
23
25
  return cache.current
24
26
  } catch (error) {
25
27
  cache.current = error as T
26
28
  }
29
+
27
30
  return cache.current
28
31
  }
29
32
 
33
+ async function handleAsyncSetValue(previousPromise: Promise<T>, value: SetStateCb<T>) {
34
+ await previousPromise
35
+ const newValue = value(cache.current as Awaited<T>)
36
+ const resolvedValue = handleAsyncUpdate(cache, state.emitter.emit, newValue)
37
+ cache.current = resolvedValue
38
+ }
39
+
30
40
  function setValue(value: SetValue<T>) {
41
+ const previous = getValue()
42
+ const isFunctionValue = isSetValueFunction(value)
43
+
44
+ if (isFunctionValue && isPromise(previous)) {
45
+ handleAsyncSetValue(previous as Promise<T>, value)
46
+ return
47
+ }
31
48
  if (cache.abortController) {
32
49
  cache.abortController.abort()
33
50
  }
34
51
 
35
- const previous = getValue()
36
- const newValue = isSetValueFunction(value) ? value(previous) : value
52
+ const newValue = isFunctionValue ? value(previous as Awaited<T>) : value
37
53
  const resolvedValue = handleAsyncUpdate(cache, state.emitter.emit, newValue)
38
54
  cache.current = resolvedValue
39
55
  }
@@ -62,6 +78,10 @@ export function create<T>(initialValue: DefaultValue<T>, isEqual: IsEqual<T> = i
62
78
  onResolveItem: setValue,
63
79
  })
64
80
 
81
+ if (!isFunction(initialValue)) {
82
+ getValue()
83
+ }
84
+
65
85
  subscribeToDevelopmentTools(state)
66
86
  return state
67
87
  }
@@ -47,6 +47,5 @@ export function subscribeToDevelopmentTools<T>(state: State<T> | GetState<T>) {
47
47
  type = 'derived'
48
48
  }
49
49
  const name = state.stateName?.length ? state.stateName : `${type}(${state.id.toString()})`
50
- sendToDevelopmentTools({ name, type, value: state.get(), message: 'initial' })
51
50
  return state.listen(developmentToolsListener(name, type))
52
51
  }
package/src/types.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { Emitter } from './utils/create-emitter'
2
2
 
3
3
  export type IsEqual<T = unknown> = (a: T, b: T) => boolean
4
- export type SetStateCb<T> = (value: T | Awaited<T>) => Awaited<T>
4
+ export type SetStateCb<T> = (value: Awaited<T>) => Awaited<T>
5
5
  export type SetValue<T> = SetStateCb<T> | Awaited<T>
6
6
  export type DefaultValue<T> = T | (() => T)
7
7
  export type Listener<T> = (listener: (value: T) => void) => () => void
@@ -1,5 +1,17 @@
1
1
  import { create } from '../../create'
2
- import { isPromise, isFunction, isSetValueFunction, isMap, isSet, isArray, isEqualBase, isUndefined, isState } from '../is'
2
+ import { AbortError } from '../common'
3
+ import {
4
+ isPromise,
5
+ isFunction,
6
+ isSetValueFunction,
7
+ isMap,
8
+ isSet,
9
+ isArray,
10
+ isEqualBase,
11
+ isUndefined,
12
+ isState,
13
+ isAbortError,
14
+ } from '../is'
3
15
 
4
16
  describe('isPromise', () => {
5
17
  it('should return true for a Promise', () => {
@@ -89,3 +101,14 @@ describe('isState', () => {
89
101
  expect(isState(123)).toBe(false)
90
102
  })
91
103
  })
104
+
105
+ describe('isAbortError', () => {
106
+ it('should return true for an AbortError', () => {
107
+ const error = new AbortError()
108
+ expect(isAbortError(error)).toBe(true)
109
+ })
110
+ it('should return false for a non-AbortError', () => {
111
+ const error = new Error('asd')
112
+ expect(isAbortError(error)).toBe(false)
113
+ })
114
+ })
@@ -1,15 +1,14 @@
1
1
  import type { Cache, IsEqual } from '../types'
2
2
  import { isAbortError, isEqualBase, isPromise, isUndefined } from './is'
3
3
 
4
- // eslint-disable-next-line no-shadow
5
- export enum Abort {
6
- Error = 'StateAbortError',
7
- }
8
-
9
4
  export interface CancelablePromise<T> {
10
5
  promise: Promise<T>
11
6
  controller?: AbortController
12
7
  }
8
+
9
+ export class AbortError extends Error {
10
+ static readonly Error = 'AbortError'
11
+ }
13
12
  /**
14
13
  * Cancelable promise function, return promise and controller
15
14
  */
@@ -23,7 +22,7 @@ function cancelablePromise<T>(promise: Promise<T>, previousController?: AbortCon
23
22
  const cancelable = new Promise<T>((resolve, reject) => {
24
23
  // Listen for the abort event
25
24
  signal.addEventListener('abort', () => {
26
- reject(new DOMException('Promise was aborted', Abort.Error))
25
+ reject(new AbortError())
27
26
  })
28
27
  // When the original promise settles, resolve or reject accordingly
29
28
  promise.then(resolve).catch(reject)
package/src/utils/is.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { SetStateCb, SetValue, State } from '../types'
2
- import { Abort } from './common'
2
+ import { AbortError } from './common'
3
3
 
4
4
  export function isPromise<T>(value: unknown): value is Promise<T> {
5
5
  return value instanceof Promise
@@ -30,8 +30,8 @@ export function isEqualBase<T>(valueA: T, valueB: T): boolean {
30
30
  export function isSetValueFunction<T>(value: SetValue<T>): value is SetStateCb<T> {
31
31
  return typeof value === 'function'
32
32
  }
33
- export function isAbortError(value: unknown): value is DOMException {
34
- return value instanceof DOMException && value.name === Abort.Error
33
+ export function isAbortError(value: unknown): value is AbortError {
34
+ return value instanceof AbortError
35
35
  }
36
36
 
37
37
  export function isError(value: unknown): value is Error {
package/types/types.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { Emitter } from './utils/create-emitter';
2
2
  export type IsEqual<T = unknown> = (a: T, b: T) => boolean;
3
- export type SetStateCb<T> = (value: T | Awaited<T>) => Awaited<T>;
3
+ export type SetStateCb<T> = (value: Awaited<T>) => Awaited<T>;
4
4
  export type SetValue<T> = SetStateCb<T> | Awaited<T>;
5
5
  export type DefaultValue<T> = T | (() => T);
6
6
  export type Listener<T> = (listener: (value: T) => void) => () => void;
@@ -1,11 +1,11 @@
1
1
  import type { Cache, IsEqual } from '../types';
2
- export declare enum Abort {
3
- Error = "StateAbortError"
4
- }
5
2
  export interface CancelablePromise<T> {
6
3
  promise: Promise<T>;
7
4
  controller?: AbortController;
8
5
  }
6
+ export declare class AbortError extends Error {
7
+ static readonly Error = "AbortError";
8
+ }
9
9
  /**
10
10
  * Check if the cache value is different from the previous value.
11
11
  */
@@ -1,4 +1,5 @@
1
1
  import type { SetStateCb, SetValue, State } from '../types';
2
+ import { AbortError } from './common';
2
3
  export declare function isPromise<T>(value: unknown): value is Promise<T>;
3
4
  export declare function isFunction<T extends (...args: unknown[]) => unknown>(value: unknown): value is T;
4
5
  export declare function isMap(value: unknown): value is Map<unknown, unknown>;
@@ -6,7 +7,7 @@ export declare function isSet(value: unknown): value is Set<unknown>;
6
7
  export declare function isArray(value: unknown): value is Array<unknown>;
7
8
  export declare function isEqualBase<T>(valueA: T, valueB: T): boolean;
8
9
  export declare function isSetValueFunction<T>(value: SetValue<T>): value is SetStateCb<T>;
9
- export declare function isAbortError(value: unknown): value is DOMException;
10
+ export declare function isAbortError(value: unknown): value is AbortError;
10
11
  export declare function isError(value: unknown): value is Error;
11
12
  export declare function isUndefined(value: unknown): value is undefined;
12
13
  export declare function isState<T>(value: unknown): value is State<T>;