muya 2.0.5 → 2.0.7

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/cjs/index.js CHANGED
@@ -1 +1 @@
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:()=>U,select:()=>h,shallow:()=>q,useValue:()=>x});module.exports=j(Y);var k=e=>e;function f(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 p(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 A(e){return e instanceof Error}function d(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=p){if(!d(e.current)){if(!d(e.previous)&&t(e.current,e.previous))return!1;e.previous=e.current}return!0}function m(e,t,r){if(!f(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 G(){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(d(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),f(n)||A(n))throw n;return n}function D(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=D(t),i.destroy=r,i.listen=function(s){return this.emitter.subscribe(()=>{let a=t();f(a)||s(t())})},i.withName=function(s){return this.stateName=s,this},i.select=function(s,a=p){return h([i],s,a)},i.get=t,i.set=n,i}var S=G();function U(e,t=p){let r={};function n(){try{if(d(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&&f(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 q(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}
1
+ "use strict";var I=Object.defineProperty;var M=Object.getOwnPropertyDescriptor;var j=Object.getOwnPropertyNames;var N=Object.prototype.hasOwnProperty;var _=(e,t)=>{for(var r in t)I(e,r,{get:t[r],enumerable:!0})},K=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of j(t))!N.call(e,o)&&o!==r&&I(e,o,{get:()=>t[o],enumerable:!(n=M(t,o))||n.enumerable});return e};var Y=e=>K(I({},"__esModule",{value:!0}),e);var Z={};_(Z,{EMPTY_SELECTOR:()=>D,create:()=>R,isAbortError:()=>v,isArray:()=>k,isEqualBase:()=>T,isError:()=>G,isFunction:()=>b,isMap:()=>E,isPromise:()=>l,isSet:()=>g,isSetValueFunction:()=>A,isState:()=>Q,isUndefined:()=>m,select:()=>C,shallow:()=>L,useValue:()=>O});module.exports=Y(Z);var d=class extends Error{static Error="AbortError"};function J(e,t){t&&t.abort();let r=new AbortController,{signal:n}=r;return{promise:new Promise((s,i)=>{n.addEventListener("abort",()=>{i(new d)}),e.then(s).catch(i)}),controller:r}}function x(e,t=T){if(!m(e.current)){if(!m(e.previous)&&t(e.current,e.previous))return!1;e.previous=e.current}return!0}function p(e,t,r){if(!l(r))return r;e.abortController&&e.abortController.abort();let{promise:n,controller:o}=J(r,e.abortController);return e.abortController=o,n.then(s=>{e.current=s,t()}).catch(s=>{v(s)||(e.current=s,t())})}function l(e){return e instanceof Promise}function b(e){return typeof e=="function"}function E(e){return e instanceof Map}function g(e){return e instanceof Set}function k(e){return Array.isArray(e)}function T(e,t){return e===t?!0:!!Object.is(e,t)}function A(e){return typeof e=="function"}function v(e){return e instanceof d}function G(e){return e instanceof Error}function m(e){return e===void 0}function Q(e){return b(e)&&"get"in e&&"set"in e&&"isSet"in e&&e.isSet===!0}var D=e=>e;function q(){let e=new Map,t=new Set,r=performance.now(),n=!1;function o(){let i=performance.now(),a=i-r,{size:u}=t;if(a<.2&&u>0&&u<10){r=i,s();return}n||(n=!0,Promise.resolve().then(()=>{n=!1,r=performance.now(),s()}))}function s(){if(t.size===0)return;let i=new Set;for(let a of t){if(e.has(a.id)){i.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 i)e.get(a)?.onFinish()}return{add(i,a){return e.set(i,a),()=>{e.delete(i)}},schedule(i,a){t.add({value:a,id:i}),o()}}}function C(e,t,r){let n={};function o(){let c=[],f=!1;for(let S of e){let y=S.get();l(y)&&(f=!0),c.push(y)}return f?new Promise((S,y)=>{Promise.all(c).then(U=>{if(U.some(H=>m(H)))return y(new d);let z=t(...U);S(z)})}):t(...c)}function s(){if(m(n.current)){let c=o();n.current=p(n,a.emitter.emit,c)}return n.current}let i=[];for(let c of e){let f=c.emitter.subscribe(()=>{h.schedule(a.id,null)});i.push(f)}let a=P({destroy(){for(let c of i)c();u(),a.emitter.clear(),n.current=void 0},get:s}),u=h.add(a.id,{onFinish(){let c=o();n.current=p(n,a.emitter.emit,c),x(n,r)&&a.emitter.emit()}});return a}var V=require("react");function O(e,t=D){let{emitter:r}=e,n=(0,V.useSyncExternalStore)(e.emitter.subscribe,()=>t(r.getSnapshot()),()=>t(r.getInitialSnapshot?r.getInitialSnapshot():r.getSnapshot()));if((0,V.useDebugValue)(n),l(n)||G(n))throw n;return n}function F(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 s of r)s(...o)},contains:o=>r.has(o),getSnapshot:e,getInitialSnapshot:t,getSize:()=>r.size,subscribeToOtherEmitter(o){let s=o.subscribe(()=>{this.emit()});n.push(s)}}}var W=0;function X(){return W++}function P(e){let{get:t,destroy:r,set:n}=e,o=!!n,s=function(i){return O(s,i)};return s.isSet=o,s.id=X(),s.emitter=F(t),s.destroy=r,s.listen=function(i){return this.emitter.subscribe(()=>{let a=t();l(a)||i(t())})},s.withName=function(i){return this.stateName=i,this},s.select=function(i,a=T){return C([s],i,a)},s.get=t,s.set=n,s}var h=q();function R(e,t=T){let r={};function n(){try{if(m(r.current)){let u=b(e)?e():e,c=p(r,i.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 f=c(r.current),w=p(r,i.emitter.emit,f);r.current=w}function s(u){let c=n(),f=A(u);if(f&&l(c)){o(c,u);return}r.abortController&&r.abortController.abort();let w=f?u(c):u,S=p(r,i.emitter.emit,w);r.current=S}let i=P({get:n,destroy(){n(),a(),i.emitter.clear(),r.current=void 0},set(u){h.schedule(i.id,u)}}),a=h.add(i.id,{onFinish(){r.current=n(),x(r,t)&&i.emitter.emit()},onResolveItem:s});return b(e)||n(),i}function L(e,t){if(e==t)return!0;if(typeof e!="object"||e==null||typeof t!="object"||t==null)return!1;if(E(e)&&E(t)){if(e.size!==t.size)return!1;for(let[o,s]of e)if(!Object.is(s,t.get(o)))return!1;return!0}if(g(e)&&g(t)){if(e.size!==t.size)return!1;for(let o of e)if(!t.has(o))return!1;return!0}if(k(e)&&k(t)){if(e.length!==t.length)return!1;for(let[o,s]of e.entries())if(!Object.is(s,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}
@@ -1 +1 @@
1
- import{select as u}from"./select";import{useValue as l}from"./use-value";import{createEmitter as S}from"./utils/create-emitter";import{isEqualBase as c,isPromise as m}from"./utils/is";let d=0;function f(){return d++}function g(i){const{get:r,destroy:n,set:a}=i,o=!!a,t=function(e){return l(t,e)};return t.isSet=o,t.id=f(),t.emitter=S(r),t.destroy=n,t.listen=function(e){return this.emitter.subscribe(()=>{const s=r();m(s)||e(r())})},t.withName=function(e){return this.stateName=e,this},t.select=function(e,s=c){return u([t],e,s)},t.get=r,t.set=a,t}export{g as createState};
1
+ import{select as u}from"./select";import{useValue as l}from"./use-value";import{createEmitter as S}from"./utils/create-emitter";import{isEqualBase as c,isPromise as m}from"./utils/is";let d=0;function f(){return d++}function G(i){const{get:r,destroy:n,set:a}=i,o=!!a,t=function(e){return l(t,e)};return t.isSet=o,t.id=f(),t.emitter=S(r),t.destroy=n,t.listen=function(e){return this.emitter.subscribe(()=>{const s=r();m(s)||e(r())})},t.withName=function(e){return this.stateName=e,this},t.select=function(e,s=c){return u([t],e,s)},t.get=r,t.set=a,t}export{G as createState};
package/esm/index.js CHANGED
@@ -1 +1 @@
1
- export*from"./types";import{create as t}from"./create";import{select as m}from"./select";import{useValue as x}from"./use-value";import{shallow as a}from"./utils/shallow";export{t as create,m as select,a as shallow,x as useValue};
1
+ export*from"./utils/is";export*from"./types";import{create as f}from"./create";import{select as p}from"./select";import{useValue as l}from"./use-value";import{shallow as s}from"./utils/shallow";export{f as create,p as select,s as shallow,l as useValue};
package/esm/select.js CHANGED
@@ -1 +1 @@
1
- import{stateScheduler as u}from"./create";import{createState as p}from"./create-state";import{subscribeToDevelopmentTools as f}from"./debug/development-tools";import{canUpdate as S,handleAsyncUpdate as s}from"./utils/common";import{isUndefined as T}from"./utils/is";function v(o,i,d){const t={};function c(){const e=o.map(r=>r.get());return i(...e)}function m(){if(T(t.current)){const e=c();t.current=s(t,n.emitter.emit,e)}return t.current}const a=[];for(const e of o){const r=e.emitter.subscribe(()=>{u.schedule(n.id,null)});a.push(r)}const n=p({destroy(){for(const e of a)e();l(),n.emitter.clear(),t.current=void 0},get:m}),l=u.add(n.id,{onFinish(){const e=c();t.current=s(t,n.emitter.emit,e),S(t,d)&&n.emitter.emit()}});return f(n),n}export{v as select};
1
+ import{stateScheduler as m}from"./create";import{createState as w}from"./create-state";import{subscribeToDevelopmentTools as b}from"./debug/development-tools";import{AbortError as k,canUpdate as v,handleAsyncUpdate as f}from"./utils/common";import{isPromise as A,isUndefined as d}from"./utils/is";function U(c,u,p){const t={};function a(){const e=[];let r=!1;for(const s of c){const o=s.get();A(o)&&(r=!0),e.push(o)}return r?new Promise((s,o)=>{Promise.all(e).then(l=>{if(l.some(y=>d(y)))return o(new k);const h=u(...l);s(h)})}):u(...e)}function S(){if(d(t.current)){const e=a();t.current=f(t,n.emitter.emit,e)}return t.current}const i=[];for(const e of c){const r=e.emitter.subscribe(()=>{m.schedule(n.id,null)});i.push(r)}const n=w({destroy(){for(const e of i)e();T(),n.emitter.clear(),t.current=void 0},get:S}),T=m.add(n.id,{onFinish(){const e=a();t.current=f(t,n.emitter.emit,e),v(t,p)&&n.emitter.emit()}});return b(n),n}export{U as select};
@@ -1 +1 @@
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};
1
+ import{isAbortError as a,isEqualBase as b,isPromise as u,isUndefined as i}from"./is";class p extends Error{static Error="AbortError"}function T(r,o){o&&o.abort();const t=new AbortController,{signal:n}=t;return{promise:new Promise((e,s)=>{n.addEventListener("abort",()=>{s(new p)}),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}=T(t,r.abortController);return r.abortController=l,n.then(e=>{r.current=e,o()}).catch(e=>{a(e)||(r.current=e,o())})}export{p as AbortError,f as canUpdate,T as cancelablePromise,m as handleAsyncUpdate};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "muya",
3
- "version": "2.0.5",
3
+ "version": "2.0.7",
4
4
  "author": "samuel.gjabel@gmail.com",
5
5
  "repository": "https://github.com/samuelgjabel/muya",
6
6
  "main": "cjs/index.js",
@@ -1,7 +1,8 @@
1
1
  import { create } from '../create'
2
2
  import { select } from '../select'
3
- import { waitFor } from '@testing-library/react'
3
+ import { renderHook, waitFor } from '@testing-library/react'
4
4
  import { longPromise } from './test-utils'
5
+ import { Suspense } from 'react'
5
6
 
6
7
  describe('select', () => {
7
8
  it('should derive state from a single dependency', async () => {
@@ -95,6 +96,33 @@ describe('select', () => {
95
96
  expect(listener).toHaveBeenCalledWith(1)
96
97
  })
97
98
  })
99
+ it('should handle async updates with nested selects', async () => {
100
+ const state = create(longPromise(100))
101
+ const selectedState = select([state], async (value) => {
102
+ await longPromise(100)
103
+ return (await value) + 1
104
+ })
105
+ const selectedState2 = selectedState.select(async (value) => value + 1)
106
+ const listener = jest.fn()
107
+ selectedState2.listen(listener)
108
+ await waitFor(() => {
109
+ expect(selectedState2.get()).toBe(2)
110
+ expect(listener).toHaveBeenCalledWith(2)
111
+ })
112
+ })
113
+ it('should handle async updates with async state', async () => {
114
+ const state = create(longPromise(100))
115
+ const selectedState = select([state], async (value) => {
116
+ // await longPromise(100)
117
+ return (await value) + 1
118
+ })
119
+ const listener = jest.fn()
120
+ selectedState.listen(listener)
121
+ await waitFor(() => {
122
+ expect(selectedState.get()).toBe(1)
123
+ expect(listener).toHaveBeenCalledWith(1)
124
+ })
125
+ })
98
126
  it('should handle sync state updates when one of par is changed', async () => {
99
127
  const state1Atom = create(0)
100
128
  const state2Atom = create(0)
@@ -124,4 +152,57 @@ describe('select', () => {
124
152
  expect(listener).toHaveBeenCalledWith(3)
125
153
  })
126
154
  })
155
+ it('should select state from async initial state', async () => {
156
+ const state = create(longPromise(100))
157
+ const selectedState = state.select(async (value) => {
158
+ return value + 2
159
+ })
160
+ await waitFor(() => {
161
+ expect(selectedState.get()).toBe(2)
162
+ })
163
+ })
164
+ it('should select state from sync initial state', async () => {
165
+ const state = create(0)
166
+ const selectedState = state.select((value) => {
167
+ return value + 2
168
+ })
169
+ await waitFor(() => {
170
+ expect(selectedState.get()).toBe(2)
171
+ })
172
+ })
173
+
174
+ it('should select state from async state and do not change second time as it just boolean value', async () => {
175
+ const state = create(longPromise(100))
176
+ const selectedState = state.select((value) => {
177
+ const result = value > 0
178
+ expect(value).not.toBeUndefined()
179
+ return result
180
+ })
181
+ const render = jest.fn()
182
+
183
+ const { result } = renderHook(
184
+ () => {
185
+ render()
186
+ const value = selectedState()
187
+ return value
188
+ },
189
+ { wrapper: ({ children }) => <Suspense fallback="loading">{children}</Suspense> },
190
+ )
191
+
192
+ await waitFor(() => {
193
+ expect(result.current).toBe(false)
194
+ expect(selectedState.get()).toBe(false)
195
+ // re-render twice, as it hit suspense, because value is not resolved yet
196
+ expect(render).toHaveBeenCalledTimes(2)
197
+ })
198
+
199
+ state.set(1)
200
+
201
+ await waitFor(() => {
202
+ expect(result.current).toBe(true)
203
+ expect(selectedState.get()).toBe(true)
204
+ // next time it re-render only once, as value is already resolved
205
+ expect(render).toHaveBeenCalledTimes(3)
206
+ })
207
+ })
127
208
  })
@@ -2,6 +2,7 @@ import { renderHook, act } from '@testing-library/react-hooks'
2
2
  import { create } from '../create'
3
3
  import { useValue } from '../use-value'
4
4
  import { waitFor } from '@testing-library/react'
5
+ import { longPromise } from './test-utils'
5
6
 
6
7
  describe('useValue', () => {
7
8
  it('should get the initial state value', () => {
@@ -75,4 +76,26 @@ describe('useValue', () => {
75
76
  await waitFor(() => {})
76
77
  expect(renders).toHaveBeenCalledTimes(2)
77
78
  })
79
+
80
+ it('should check how many times the hook re-render when the state is promise', async () => {
81
+ const state = create(longPromise(100))
82
+
83
+ const render = jest.fn()
84
+ const renderAfter = jest.fn()
85
+
86
+ const { result } = renderHook(() => {
87
+ render()
88
+ const stateResult = state()
89
+ renderAfter()
90
+ return stateResult
91
+ })
92
+
93
+ await waitFor(() => {
94
+ expect(result.current).toBe(0)
95
+ // when it render, it will return a promise - hit the suspense, so it should be called twice
96
+ expect(render).toHaveBeenCalledTimes(2)
97
+ // after the promise resolved, it will re-render again, this part should be called once
98
+ expect(renderAfter).toHaveBeenCalledTimes(1)
99
+ })
100
+ })
78
101
  })
@@ -45,7 +45,7 @@ export function createState<T>(options: GetStateOptions<T>): FullState<T> {
45
45
  return this
46
46
  }
47
47
  state.select = function (selector, isSelectorEqual = isEqualBase) {
48
- return select([state], selector, isSelectorEqual)
48
+ return select([state as never], selector, isSelectorEqual)
49
49
  }
50
50
  state.get = get
51
51
  state.set = set as State<T>['set']
package/src/index.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export * from './utils/is'
1
2
  export * from './types'
2
3
  export { create } from './create'
3
4
  export { select } from './select'
package/src/select.ts CHANGED
@@ -2,8 +2,8 @@ import { stateScheduler } from './create'
2
2
  import { createState } from './create-state'
3
3
  import { subscribeToDevelopmentTools } from './debug/development-tools'
4
4
  import type { Cache, GetState, IsEqual } from './types'
5
- import { canUpdate, handleAsyncUpdate } from './utils/common'
6
- import { isUndefined } from './utils/is'
5
+ import { AbortError, canUpdate, handleAsyncUpdate } from './utils/common'
6
+ import { isPromise, isUndefined } from './utils/is'
7
7
 
8
8
  type StateDependencies<T extends Array<unknown>> = {
9
9
  [K in keyof T]: GetState<T[K]>
@@ -21,8 +21,32 @@ export function select<T = unknown, S extends Array<unknown> = []>(
21
21
  const cache: Cache<T> = {}
22
22
 
23
23
  function computedValue(): T {
24
- const values = states.map((state) => state.get()) as S
25
- return selector(...values)
24
+ // const values = states.map((state) => state.get()) as S
25
+
26
+ const values: unknown[] = []
27
+ let hasPromise = false
28
+ for (const state of states) {
29
+ const value = state.get()
30
+ if (isPromise(value)) {
31
+ hasPromise = true
32
+ }
33
+ values.push(value)
34
+ }
35
+ if (hasPromise) {
36
+ return new Promise((resolve, reject) => {
37
+ Promise.all(values).then((resolvedValues) => {
38
+ // check if some of value is undefined
39
+ // eslint-disable-next-line sonarjs/no-nested-functions
40
+ if (resolvedValues.some((element) => isUndefined(element))) {
41
+ return reject(new AbortError())
42
+ }
43
+ const resolved = selector(...(resolvedValues as S))
44
+ resolve(resolved)
45
+ })
46
+ }) as T
47
+ }
48
+ const result = selector(...(values as S))
49
+ return result
26
50
  }
27
51
 
28
52
  function getValue(): T {
package/src/types.ts CHANGED
@@ -48,7 +48,7 @@ export interface GetState<T> {
48
48
  * Select particular slice of the state.
49
49
  * It will create "another" state in read-only mode (without set).
50
50
  */
51
- select: <S>(selector: (state: T) => S, isEqual?: IsEqual<S>) => GetState<S>
51
+ select: <S>(selector: (state: Awaited<T>) => S, isEqual?: IsEqual<S>) => GetState<S>
52
52
  }
53
53
 
54
54
  export interface State<T> extends GetState<T> {
@@ -12,7 +12,7 @@ export class AbortError extends Error {
12
12
  /**
13
13
  * Cancelable promise function, return promise and controller
14
14
  */
15
- function cancelablePromise<T>(promise: Promise<T>, previousController?: AbortController): CancelablePromise<T> {
15
+ export function cancelablePromise<T>(promise: Promise<T>, previousController?: AbortController): CancelablePromise<T> {
16
16
  if (previousController) {
17
17
  previousController.abort()
18
18
  }
package/types/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export * from './utils/is';
1
2
  export * from './types';
2
3
  export { create } from './create';
3
4
  export { select } from './select';
package/types/types.d.ts CHANGED
@@ -45,7 +45,7 @@ export interface GetState<T> {
45
45
  * Select particular slice of the state.
46
46
  * It will create "another" state in read-only mode (without set).
47
47
  */
48
- select: <S>(selector: (state: T) => S, isEqual?: IsEqual<S>) => GetState<S>;
48
+ select: <S>(selector: (state: Awaited<T>) => S, isEqual?: IsEqual<S>) => GetState<S>;
49
49
  }
50
50
  export interface State<T> extends GetState<T> {
51
51
  /**
@@ -6,6 +6,10 @@ export interface CancelablePromise<T> {
6
6
  export declare class AbortError extends Error {
7
7
  static readonly Error = "AbortError";
8
8
  }
9
+ /**
10
+ * Cancelable promise function, return promise and controller
11
+ */
12
+ export declare function cancelablePromise<T>(promise: Promise<T>, previousController?: AbortController): CancelablePromise<T>;
9
13
  /**
10
14
  * Check if the cache value is different from the previous value.
11
15
  */