bansa 0.0.12 → 0.0.14

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.
@@ -1 +1 @@
1
- var i=function(){};i.prototype.get=function(){if(this.o||(I(this),V(this)),this.state.promise)throw this.state.promise;if(this.state.error)throw this.state.error;return this.state.value};i.prototype.watch=function(e){return this.o||x(this),(this.i??=new Set).add(e),()=>{this.i.delete(e),this.i.size||V(this)}};i.prototype.subscribe=function(e){let t={y:e,c:{get signal(){return(t.t??=_()).signal}}};if(!this.o)x(this);else if(!this.state.promise&&!this.state.error)try{e(this.state.value,t.c)}catch(o){y(o)}return(this.s??=new Set).add(t),()=>{this.s.delete(t),t.t&&(t.t.abort(),t.t=void 0),this.s.size||V(this)}};i.prototype[Symbol.toPrimitive]=function(){return this.state.value};var c=function(e,t){this.u=e,this.f=t?.equals,this.state={promise:void 0,error:void 0,value:e},this.state.value=this.a=e};c.prototype.set=function(e){let t=e instanceof Function?e(this.a):e;S(t,this.state.value,this.f)||(this.a=t,d(this))};c.prototype.m=!0;c.prototype.o=!0;c.prototype.n=!1;Object.setPrototypeOf(c.prototype,i.prototype);var f=function(e,t){this.u=e,this.f=t?.equals,this.h=t?.persist,this.state={promise:P,error:void 0,value:void 0};let o=this;this.c={get signal(){return(o.t??=_()).signal}}};f.prototype.m=!1;f.prototype.o=!1;f.prototype.n=!1;f.prototype.l=0;Object.setPrototypeOf(f.prototype,i.prototype);var A=()=>A,D=()=>{};Object.setPrototypeOf(A,new Proxy(A,{get:(e,t)=>t===Symbol.toPrimitive?D:A}));var P=Promise.resolve(),m=(e,t)=>e instanceof Function?new f(e,t):new c(e,t),C=e=>m((t,o)=>{let r,n,a=e((s,h)=>{try{return t(s,h)}catch(l){if(!l)throw l;w(l)?(r??=[]).push(l):n=l}return A},o);if(n)throw n;if(r)throw Promise.all(r);return a},{equals:q}),L=(e,t)=>{let o=new WeakMap;if(t)for(let[n,a]of t)o.set(n,a instanceof i?a:m(a));let r=((n,a=!0)=>{let s=o.get(n);return a&&!(s||e&&(s=e(n,!1)))&&o.set(n,s=n.u instanceof Function?m((h,l)=>n.u((O,G)=>h(r(O),G),l)):m(n.u)),s});return r},q=(e,t)=>{if(typeof e!="object"||typeof t!="object"||!e||!t)return!1;let o=e.constructor;if(o!==t.constructor)return!1;if(o===Array){let n=e.length;if(n!==t.length)return!1;for(;(n=n-1|0)>=0;)if(!Object.is(e[n],t[n]))return!1;return!0}let r=0;for(let n in e){if(!(n in t&&Object.is(e[n],t[n])))return!1;r=r+1|0}for(let n in t)if((r=r-1|0)<0)return!1;return!0},b=!1,u=[],x=e=>{e.p||(e.p=!0,d(e))},d=e=>{e.n||(e.n=!0,u.push(e),b||(b=!0,queueMicrotask(T)))},T=()=>{b=!1;{let t=u;u=[];for(let o of t)o.state.promise=void 0,o.state.error=o.A,o.state.value=o.a,k(o)}let e=u;u=[];for(let t=e.length;t--;){let o=e[t];o.d=!1,o.p&&(o.n=!0,I(o)),o.n&&g(o)}},g=e=>{if(e.n=!1,e.r)for(let t of e.r)t.p=!0;if(e.i)for(let t of e.i)t();if(e.s&&!e.state.promise&&!e.state.error)for(let t of e.s){t.t&&(t.t.abort(),t.t=void 0);try{t.y(e.state.value,t.c)}catch(o){y(o)}}},k=e=>{if(!e.d){if(e.d=!0,e.r)for(let t of e.r)k(t);u.push(e)}},p=class{e;constructor(t){this.e=t}},I=e=>{let t=++e.l;e.o=!0,e.p=!1,e.state.promise=void 0,e.t&&(e.t.abort(),e.t=void 0);let o=e.V;o&&(e.V=new Set);try{let r=e.u((n,a=!0)=>{if(t!==e.l)throw void 0;if(e!==n&&(n.o||(I(n),n.n&&(n.n=!1,g(n))),o?.delete(n),(e.V??=new Set).add(n),(n.r??=new Set).add(e)),!a)return n.state;if(n.state.promise)throw new p(n.state.promise);if(n.state.error)throw new p(n.state.error);return n.state.value},e.c);w(r)?(e.state.promise=r,r.then(n=>{t===e.l&&(S(n,e.state.value,e.f)?e.state.promise=void 0:(e.a=n,e.A=void 0,d(e)))},n=>{t===e.l&&(n instanceof Promise?e.state.promise=void 0:(n instanceof p?n=n.e:y(n),e.A=n,d(e)))})):(++e.l,e.state.error=void 0,S(r,e.state.value,e.f)?e.n=!1:e.state.value=e.a=r)}catch(r){++e.l,r?(r instanceof p?r=r.e:y(r),w(r)?e.state.promise=r:e.state.error=r):e.n=!1}if(o)for(let r of o)r.r.delete(e),V(r)},v=!1,V=e=>{if(!e.m&&!e.h&&!e.r?.size&&!e.i?.size&&!e.s?.size){if(!v){setTimeout(()=>{v=!0,V(e),v=!1},0);return}if(e.state.promise=P,e.a=e.A=e.state.error=e.state.value=void 0,e.n=e.p=e.o=!1,e.t&&(e.t.abort(),e.t=void 0),e.V){for(let t of e.V)t.r.delete(e),V(t);e.V.clear()}}},S=(e,t,o)=>Object.is(e,t)||o!==void 0&&t!==void 0&&o(e,t),w=e=>typeof e?.then=="function",_=()=>{let e=new AbortController,t=e.signal,o=new Promise(r=>{t.then=n=>o.then(n),t.addEventListener("abort",r,{once:!0,passive:!0})});return{abort:()=>e.abort(),signal:t}},y=e=>{queueMicrotask(()=>{throw e})};export{m as $,C as $$,L as createScope,P as inactive};
1
+ var d=class{r;p;a;o;l;get(){if(this.s||(I(this),u(this)),this.state.error)throw this.state.error;if(this.state.promise)throw this.state.promise;return this.state.value}watch(t){return this.s||k(this),(this.o||=new Set).add(t),()=>{this.o.delete(t),this.o.size||u(this)}}subscribe(t){let a={h:t,A:{get signal(){return(a.t||=q()).signal}}};if(!this.s)k(this);else if(!this.state.error&&!this.state.promise)try{t(this.state.value,a.A)}catch(n){V(n)}return(this.l||=new Set).add(a),()=>{this.l.delete(a),a.t&&(a.t.abort(),a.t=void 0),this.l.size||u(this)}}[Symbol.toPrimitive](){return this.state.value}},i=class extends d{n=!1;m=!1;constructor(t,a){super(),this.d=t,this.V=a?.equals,this.r=t,this.state={promise:void 0,error:void 0,value:t}}set(t){let a=t instanceof Function?t(this.r):t;x(a,this.state.value,this.V)||(this.r=a,y(this))}};i.prototype.y=!0;i.prototype.s=!0;i.prototype.u=!1;var m=class extends d{s=!1;u=!1;n=!1;m=!1;f=0;t;i;c;constructor(t,a){super(),this.d=t,this.V=a?.equals,this.b=!!a?.persist;let n=this;this.A={get signal(){return(n.t||=q()).signal}},this.state={promise:g,error:void 0,value:void 0}}};m.prototype.y=!1;var c=()=>c,_=()=>{};Object.setPrototypeOf(c,new Proxy(c,{get:(e,t)=>t===Symbol.toPrimitive?_:c}));var g=Promise.reject();g.catch(_);var A=(e,t)=>e instanceof Function?new m(e,t):new i(e,t),M=e=>A((t,a)=>{let n,r,l=e(f=>{let o=t(f,!1);if(o.error)r=o.error;else if(o.promise)(n||=[]).push(o.promise);else return o.value;return c},a);if(r)throw r;if(n)throw Promise.all(n);return l},{equals:L}),W=(e,t)=>{let a=new WeakMap;if(t)for(let[r,l]of t)a.set(r,l instanceof d?l:A(l));let n=(r=>{let l=a.get(r);if(!l){let f=e?.(r),o=f||r;a.set(r,l=o.d instanceof Function?A((D,T)=>o.d((E,K)=>D(n(E),K),T),{equals:o.V,persist:o.b}):f||A(o.d))}return l});return n},L=(e,t)=>{if(typeof e!="object"||typeof t!="object"||!e||!t)return!1;let a=e.constructor;if(a!==t.constructor)return!1;if(a===Array){let r=e.length;if(r!==t.length)return!1;for(;(r=r-1|0)>=0;)if(!Object.is(e[r],t[r]))return!1;return!0}let n=0;for(let r in e){if(!(r in t&&Object.is(e[r],t[r])))return!1;n=n+1|0}for(let r in t)if((n=n-1|0)<0)return!1;return!0},b=!1,h=[],v=[],k=e=>{e.u||(e.u=!0,y(e))},y=e=>{e.n||(e.n=!0,h.push(e),b||(b=!0,queueMicrotask(j)))},j=()=>{b=!1;{let t=h;h=[];for(let a of t)a.state.promise=void 0,a.state.error=a.p,a.state.value=a.r,O(a)}let e=v;v=[];for(let t=e.length;t--;){let a=e[t];a.m=!1,a.u&&(a.n=!0,I(a)),a.n&&G(a)}},G=e=>{if(e.n=!1,e.o)for(let t of e.o)try{t()}catch(a){V(a)}if(!e.state.error&&!e.state.promise){if(e.l)for(let t of e.l){t.t&&(t.t.abort(),t.t=void 0);try{t.h(e.state.value,t.A)}catch(a){V(a)}}if(e.a)for(let t of e.a)t.u=!0}},O=e=>{if(!e.m){if(e.m=!0,e.a)for(let t of e.a)O(t);v.push(e)}},s=class{e;constructor(t){this.e=t}},P=Symbol(),I=e=>{let t=++e.f;e.s=!0,e.u=!1,e.state.promise=void 0,e.t&&(e.t.abort(),e.t=void 0);try{let a=e.d((n,r=!0)=>{if(t!==e.f)throw P;if(e!==n&&(n.s||(I(n),n.n&&G(n)),(e.c||=new Set).add(n),(n.a||=new Set).add(e)),!r)return n.state;if(n.state.error)throw new s(n.state.error);if(n.state.promise)throw new s(n.state.promise);return n.state.value},e.A);C(a)?(e.state.promise=a,a.then(n=>{t===e.f&&(p(e),x(n,e.state.value,e.V)?e.state.promise=void 0:(e.r=n,e.p=void 0),y(e))},n=>{t===e.f&&(p(e),n instanceof s?n=n.e:V(n),e.p=n,y(e))})):(p(e),e.state.error=void 0,x(a,e.state.value,e.V)?e.n=!1:e.state.value=e.r=a)}catch(a){p(e),a===P?e.n=!1:(a instanceof s?a=a.e:V(a),e.state.error=a)}},p=e=>{++e.f;let t=e.i;if(e.i=e.c,t){for(let a of t)e.i?.has(a)||(a.a.delete(e),u(a));t.clear()}e.c=t},S=!1,w=new Set,u=e=>{!e.y&&!e.b&&!e.a?.size&&!e.o?.size&&!e.l?.size&&(w.add(e),S||(S=!0,setTimeout(z,0)))},z=()=>{for(let e of w)if(!e.y&&!e.b&&!e.a?.size&&!e.o?.size&&!e.l?.size&&(e.state.promise=g,e.r=e.p=e.state.error=e.state.value=void 0,e.n=e.u=e.s=!1,e.t&&(e.t.abort(),e.t=void 0),e.i)){for(let t of e.i)t.a.delete(e),u(t);if(e.i.clear(),e.c){for(let t of e.c)t.a.delete(e),u(t);e.c.clear()}}w.clear(),S=!1},x=(e,t,a)=>Object.is(e,t)||a!==void 0&&t!==void 0&&a(e,t),C=e=>typeof e?.then=="function",q=()=>{let e=new AbortController,t=e.signal,a=new Promise(n=>{t.then=r=>a.then(r),t.addEventListener("abort",n,{once:!0,passive:!0})});return{abort:()=>e.abort(),signal:t}},V=e=>{queueMicrotask(()=>{throw e})};export{A as $,M as $$,W as createScope,g as inactive};
Binary file
package/dist/index.d.ts CHANGED
@@ -71,9 +71,9 @@ export type AtomScope = {
71
71
  };
72
72
  export type SetLike<Key> = Key[] | Set<Key> | (Key extends object ? WeakSet<Key> : never);
73
73
  export type MapLike<Key, Value> = Map<Key, Value> | (Key extends object ? WeakMap<Key, Value> : never) | (Key extends string | number | symbol ? Record<Key, Value> : never);
74
- export declare const inactive: Promise<void>;
74
+ export declare const inactive: Promise<never>;
75
75
  export declare const $: CreateAtom;
76
76
  export declare const $$: <Value>(init: AtomGetter<Value>) => DerivedAtom<Value>;
77
- export type AtomValuePair<Value> = [Atom<Value>, Value | Atom<Value>];
78
- export declare const createScope: (parentScope?: AtomScope | null, atomValuePairs?: AtomValuePair<unknown>[]) => AtomScope;
77
+ export type AtomValuePair<Value> = [Atom<Value>, Value | PrimitiveAtom<Value>] | [DerivedAtom<Value>, Value | Atom<Value>];
78
+ export declare const createScope: <T extends AtomValuePair<unknown>[]>(parentScope?: AtomScope | null, atomValuePairs?: T) => AtomScope;
79
79
  export {};
package/dist/index.js CHANGED
@@ -1,104 +1,117 @@
1
- const AtomPrototype = function() {
2
- };
3
- AtomPrototype.prototype.get = function() {
4
- if (!this.c) {
5
- execute(this);
6
- disableAtom(this);
7
- }
8
- if (this.state.promise) throw this.state.promise;
9
- if (this.state.error) throw this.state.error;
10
- return this.state.value;
11
- };
12
- AtomPrototype.prototype.watch = function(watcher) {
13
- if (!this.c) {
14
- requestActivate(this);
15
- }
16
- (this.h ??= /* @__PURE__ */ new Set()).add(watcher);
17
- return () => {
18
- this.h.delete(watcher);
19
- if (!this.h.size) {
1
+ class CommonAtomInternal {
2
+ d;
3
+ o;
4
+ b;
5
+ f;
6
+ g;
7
+ get() {
8
+ if (!this.h) {
9
+ execute(this);
20
10
  disableAtom(this);
21
11
  }
22
- };
23
- };
24
- AtomPrototype.prototype.subscribe = function(subscriber) {
25
- const atomSubscriber = {
26
- r: subscriber,
27
- m: {
28
- get signal() {
29
- return (atomSubscriber.a ??= createThenableSignal()).signal;
30
- }
31
- }
32
- };
33
- if (!this.c) {
34
- requestActivate(this);
35
- } else if (!this.state.promise && !this.state.error) {
36
- try {
37
- subscriber(this.state.value, atomSubscriber.m);
38
- } catch (e) {
39
- logError(e);
40
- }
12
+ if (this.state.error) throw this.state.error;
13
+ if (this.state.promise) throw this.state.promise;
14
+ return this.state.value;
41
15
  }
42
- (this.i ??= /* @__PURE__ */ new Set()).add(atomSubscriber);
43
- return () => {
44
- this.i.delete(atomSubscriber);
45
- if (atomSubscriber.a) {
46
- atomSubscriber.a.abort();
47
- atomSubscriber.a = void 0;
16
+ watch(watcher) {
17
+ if (!this.h) {
18
+ requestActivate(this);
48
19
  }
49
- if (!this.i.size) {
50
- disableAtom(this);
20
+ (this.f ||= /* @__PURE__ */ new Set()).add(watcher);
21
+ return () => {
22
+ this.f.delete(watcher);
23
+ if (!this.f.size) {
24
+ disableAtom(this);
25
+ }
26
+ };
27
+ }
28
+ subscribe(subscriber) {
29
+ const atomSubscriber = {
30
+ t: subscriber,
31
+ p: {
32
+ get signal() {
33
+ return (atomSubscriber.a ||= createThenableSignal()).signal;
34
+ }
35
+ }
36
+ };
37
+ if (!this.h) {
38
+ requestActivate(this);
39
+ } else if (!this.state.error && !this.state.promise) {
40
+ try {
41
+ subscriber(this.state.value, atomSubscriber.p);
42
+ } catch (e) {
43
+ logError(e);
44
+ }
51
45
  }
52
- };
53
- };
54
- AtomPrototype.prototype[Symbol.toPrimitive] = function() {
55
- return this.state.value;
56
- };
57
- const PrimitiveAtomPrototype = function(init, options) {
58
- this.j = init;
59
- this.n = options?.equals;
60
- this.state = {
61
- promise: void 0,
62
- error: void 0,
63
- value: init
64
- };
65
- this.state.value = this.f = init;
66
- };
67
- PrimitiveAtomPrototype.prototype.set = function(value) {
68
- const nextValue = value instanceof Function ? value(this.f) : value;
69
- if (!equals(nextValue, this.state.value, this.n)) {
70
- this.f = nextValue;
71
- requestPropagate(this);
46
+ (this.g ||= /* @__PURE__ */ new Set()).add(atomSubscriber);
47
+ return () => {
48
+ this.g.delete(atomSubscriber);
49
+ if (atomSubscriber.a) {
50
+ atomSubscriber.a.abort();
51
+ atomSubscriber.a = void 0;
52
+ }
53
+ if (!this.g.size) {
54
+ disableAtom(this);
55
+ }
56
+ };
72
57
  }
73
- };
74
- PrimitiveAtomPrototype.prototype.p = true;
75
- PrimitiveAtomPrototype.prototype.c = true;
76
- PrimitiveAtomPrototype.prototype.b = false;
77
- Object.setPrototypeOf(
78
- PrimitiveAtomPrototype.prototype,
79
- AtomPrototype.prototype
80
- );
81
- const DerivedAtomPrototype = function(init, options) {
82
- this.j = init;
83
- this.n = options?.equals;
84
- this.s = options?.persist;
85
- this.state = {
86
- promise: inactive,
87
- error: void 0,
88
- value: void 0
89
- };
90
- const self = this;
91
- this.m = {
92
- get signal() {
93
- return (self.a ??= createThenableSignal()).signal;
58
+ [Symbol.toPrimitive]() {
59
+ return this.state.value;
60
+ }
61
+ }
62
+ class PrimitiveAtomInternal extends CommonAtomInternal {
63
+ c = false;
64
+ q = false;
65
+ constructor(init, options) {
66
+ super();
67
+ this.l = init;
68
+ this.m = options?.equals;
69
+ this.d = init;
70
+ this.state = {
71
+ promise: void 0,
72
+ error: void 0,
73
+ value: init
74
+ };
75
+ }
76
+ set(value) {
77
+ const nextValue = value instanceof Function ? value(this.d) : value;
78
+ if (!equals(nextValue, this.state.value, this.m)) {
79
+ this.d = nextValue;
80
+ requestPropagate(this);
94
81
  }
95
- };
96
- };
97
- DerivedAtomPrototype.prototype.p = false;
98
- DerivedAtomPrototype.prototype.c = false;
99
- DerivedAtomPrototype.prototype.b = false;
100
- DerivedAtomPrototype.prototype.g = 0;
101
- Object.setPrototypeOf(DerivedAtomPrototype.prototype, AtomPrototype.prototype);
82
+ }
83
+ }
84
+ PrimitiveAtomInternal.prototype.r = true;
85
+ PrimitiveAtomInternal.prototype.h = true;
86
+ PrimitiveAtomInternal.prototype.i = false;
87
+ class DerivedAtomInternal extends CommonAtomInternal {
88
+ h = false;
89
+ i = false;
90
+ c = false;
91
+ q = false;
92
+ n = 0;
93
+ a;
94
+ j;
95
+ k;
96
+ constructor(init, options) {
97
+ super();
98
+ this.l = init;
99
+ this.m = options?.equals;
100
+ this.s = !!options?.persist;
101
+ const self = this;
102
+ this.p = {
103
+ get signal() {
104
+ return (self.a ||= createThenableSignal()).signal;
105
+ }
106
+ };
107
+ this.state = {
108
+ promise: inactive,
109
+ error: void 0,
110
+ value: void 0
111
+ };
112
+ }
113
+ }
114
+ DerivedAtomInternal.prototype.r = false;
102
115
  const ouroboros = () => ouroboros;
103
116
  const toUndefined = () => void 0;
104
117
  Object.setPrototypeOf(
@@ -107,28 +120,21 @@ Object.setPrototypeOf(
107
120
  get: (_, k) => k === Symbol.toPrimitive ? toUndefined : ouroboros
108
121
  })
109
122
  );
110
- const inactive = Promise.resolve();
123
+ const inactive = Promise.reject();
124
+ inactive.catch(toUndefined);
111
125
  const $ = (init, options) => {
112
126
  if (init instanceof Function)
113
- return new DerivedAtomPrototype(init, options);
114
- return new PrimitiveAtomPrototype(init, options);
127
+ return new DerivedAtomInternal(init, options);
128
+ return new PrimitiveAtomInternal(init, options);
115
129
  };
116
130
  const $$ = (init) => $((get, options) => {
117
131
  let promises;
118
132
  let error;
119
- const result = init((atom, unwrap) => {
120
- try {
121
- return get(atom, unwrap);
122
- } catch (e) {
123
- if (!e) {
124
- throw e;
125
- }
126
- if (isPromiseLike(e)) {
127
- (promises ??= []).push(e);
128
- } else {
129
- error = e;
130
- }
131
- }
133
+ const result = init((atom) => {
134
+ const state = get(atom, false);
135
+ if (state.error) error = state.error;
136
+ else if (state.promise) (promises ||= []).push(state.promise);
137
+ else return state.value;
132
138
  return ouroboros;
133
139
  }, options);
134
140
  if (error) throw error;
@@ -141,15 +147,25 @@ const createScope = (parentScope, atomValuePairs) => {
141
147
  const scopeMap = /* @__PURE__ */ new WeakMap();
142
148
  if (atomValuePairs) {
143
149
  for (const [atom, value] of atomValuePairs) {
144
- scopeMap.set(atom, value instanceof AtomPrototype ? value : $(value));
150
+ scopeMap.set(atom, value instanceof CommonAtomInternal ? value : $(value));
145
151
  }
146
152
  }
147
- const scope = ((baseAtom, create = true) => {
153
+ const scope = ((baseAtom) => {
148
154
  let scopedAtom = scopeMap.get(baseAtom);
149
- if (create && !(scopedAtom || parentScope && (scopedAtom = parentScope(baseAtom, false)))) scopeMap.set(baseAtom, scopedAtom = baseAtom.j instanceof Function ? $((get, options) => baseAtom.j(
150
- (atom, unwrap) => get(scope(atom), unwrap),
151
- options
152
- )) : $(baseAtom.j));
155
+ if (!scopedAtom) {
156
+ const parentAtom = parentScope?.(baseAtom);
157
+ const realBaseAtom = parentAtom || baseAtom;
158
+ scopeMap.set(
159
+ baseAtom,
160
+ scopedAtom = realBaseAtom.l instanceof Function ? $((get, options) => realBaseAtom.l(
161
+ (atom, unwrap) => get(scope(atom), unwrap),
162
+ options
163
+ ), {
164
+ equals: realBaseAtom.m,
165
+ persist: realBaseAtom.s
166
+ }) : parentAtom || $(realBaseAtom.l)
167
+ );
168
+ }
153
169
  return scopedAtom;
154
170
  });
155
171
  return scope;
@@ -173,17 +189,18 @@ const shallowEquals = (a, b) => {
173
189
  return true;
174
190
  };
175
191
  let pendingUpdateAtoms = false;
192
+ let updateQueue = [];
176
193
  let stack = [];
177
194
  const requestActivate = (atom) => {
178
- if (!atom.k) {
179
- atom.k = true;
195
+ if (!atom.i) {
196
+ atom.i = true;
180
197
  requestPropagate(atom);
181
198
  }
182
199
  };
183
200
  const requestPropagate = (atom) => {
184
- if (!atom.b) {
185
- atom.b = true;
186
- stack.push(atom);
201
+ if (!atom.c) {
202
+ atom.c = true;
203
+ updateQueue.push(atom);
187
204
  if (!pendingUpdateAtoms) {
188
205
  pendingUpdateAtoms = true;
189
206
  queueMicrotask(updateAtoms);
@@ -193,12 +210,12 @@ const requestPropagate = (atom) => {
193
210
  const updateAtoms = () => {
194
211
  pendingUpdateAtoms = false;
195
212
  {
196
- const updatedAtoms = stack;
197
- stack = [];
213
+ const updatedAtoms = updateQueue;
214
+ updateQueue = [];
198
215
  for (const atom of updatedAtoms) {
199
216
  atom.state.promise = void 0;
200
217
  atom.state.error = atom.o;
201
- atom.state.value = atom.f;
218
+ atom.state.value = atom.d;
202
219
  mark(atom);
203
220
  }
204
221
  }
@@ -207,46 +224,52 @@ const updateAtoms = () => {
207
224
  for (let i = markedAtoms.length; i--; ) {
208
225
  const atom = markedAtoms[i];
209
226
  atom.q = false;
210
- if (atom.k) {
211
- atom.b = true;
227
+ if (atom.i) {
228
+ atom.c = true;
212
229
  execute(atom);
213
230
  }
214
- if (atom.b) {
231
+ if (atom.c) {
215
232
  propagate(atom);
216
233
  }
217
234
  }
218
235
  };
219
236
  const propagate = (atom) => {
220
- atom.b = false;
221
- if (atom.d) {
222
- for (const child of atom.d) {
223
- child.k = true;
224
- }
225
- }
226
- if (atom.h) {
227
- for (const watcher of atom.h) {
228
- watcher();
229
- }
230
- }
231
- if (atom.i && !atom.state.promise && !atom.state.error) {
232
- for (const subscriber of atom.i) {
233
- if (subscriber.a) {
234
- subscriber.a.abort();
235
- subscriber.a = void 0;
236
- }
237
+ atom.c = false;
238
+ if (atom.f) {
239
+ for (const watcher of atom.f) {
237
240
  try {
238
- subscriber.r(atom.state.value, subscriber.m);
241
+ watcher();
239
242
  } catch (e) {
240
243
  logError(e);
241
244
  }
242
245
  }
243
246
  }
247
+ if (!atom.state.error && !atom.state.promise) {
248
+ if (atom.g) {
249
+ for (const subscriber of atom.g) {
250
+ if (subscriber.a) {
251
+ subscriber.a.abort();
252
+ subscriber.a = void 0;
253
+ }
254
+ try {
255
+ subscriber.t(atom.state.value, subscriber.p);
256
+ } catch (e) {
257
+ logError(e);
258
+ }
259
+ }
260
+ }
261
+ if (atom.b) {
262
+ for (const child of atom.b) {
263
+ child.i = true;
264
+ }
265
+ }
266
+ }
244
267
  };
245
268
  const mark = (atom) => {
246
269
  if (!atom.q) {
247
270
  atom.q = true;
248
- if (atom.d) {
249
- for (const child of atom.d) {
271
+ if (atom.b) {
272
+ for (const child of atom.b) {
250
273
  mark(child);
251
274
  }
252
275
  }
@@ -259,133 +282,144 @@ class Wrapped {
259
282
  this.e = e;
260
283
  }
261
284
  }
285
+ const expired = Symbol();
262
286
  const execute = (atom) => {
263
- const counter = ++atom.g;
264
- atom.c = true;
265
- atom.k = false;
287
+ const counter = ++atom.n;
288
+ atom.h = true;
289
+ atom.i = false;
266
290
  atom.state.promise = void 0;
267
291
  if (atom.a) {
268
292
  atom.a.abort();
269
293
  atom.a = void 0;
270
294
  }
271
- const oldDependencies = atom.l;
272
- if (oldDependencies) {
273
- atom.l = /* @__PURE__ */ new Set();
274
- }
275
295
  try {
276
- const value = atom.j(
296
+ const value = atom.l(
277
297
  (anotherAtom, unwrap = true) => {
278
- if (counter !== atom.g) throw void 0;
298
+ if (counter !== atom.n) throw expired;
279
299
  if (atom !== anotherAtom) {
280
- if (!anotherAtom.c) {
300
+ if (!anotherAtom.h) {
281
301
  execute(anotherAtom);
282
- if (anotherAtom.b) {
283
- anotherAtom.b = false;
302
+ if (anotherAtom.c) {
284
303
  propagate(anotherAtom);
285
304
  }
286
305
  }
287
- oldDependencies?.delete(anotherAtom);
288
- (atom.l ??= /* @__PURE__ */ new Set()).add(anotherAtom);
289
- (anotherAtom.d ??= /* @__PURE__ */ new Set()).add(atom);
306
+ (atom.k ||= /* @__PURE__ */ new Set()).add(anotherAtom);
307
+ (anotherAtom.b ||= /* @__PURE__ */ new Set()).add(atom);
290
308
  }
291
309
  if (!unwrap) return anotherAtom.state;
292
- if (anotherAtom.state.promise)
293
- throw new Wrapped(anotherAtom.state.promise);
294
310
  if (anotherAtom.state.error)
295
311
  throw new Wrapped(anotherAtom.state.error);
312
+ if (anotherAtom.state.promise)
313
+ throw new Wrapped(anotherAtom.state.promise);
296
314
  return anotherAtom.state.value;
297
315
  },
298
- atom.m
316
+ atom.p
299
317
  );
300
318
  if (isPromiseLike(value)) {
301
319
  atom.state.promise = value;
302
320
  value.then(
303
321
  (value2) => {
304
- if (counter === atom.g) {
305
- if (equals(value2, atom.state.value, atom.n)) {
322
+ if (counter === atom.n) {
323
+ finalizeExecution(atom);
324
+ if (equals(value2, atom.state.value, atom.m)) {
306
325
  atom.state.promise = void 0;
307
326
  } else {
308
- atom.f = value2;
327
+ atom.d = value2;
309
328
  atom.o = void 0;
310
- requestPropagate(atom);
311
329
  }
330
+ requestPropagate(atom);
312
331
  }
313
332
  },
314
333
  (e) => {
315
- if (counter === atom.g) {
316
- if (e instanceof Promise) {
317
- atom.state.promise = void 0;
334
+ if (counter === atom.n) {
335
+ finalizeExecution(atom);
336
+ if (e instanceof Wrapped) {
337
+ e = e.e;
318
338
  } else {
319
- if (e instanceof Wrapped) {
320
- e = e.e;
321
- } else {
322
- logError(e);
323
- }
324
- atom.o = e;
325
- requestPropagate(atom);
339
+ logError(e);
326
340
  }
341
+ atom.o = e;
342
+ requestPropagate(atom);
327
343
  }
328
344
  }
329
345
  );
330
346
  } else {
331
- ++atom.g;
347
+ finalizeExecution(atom);
332
348
  atom.state.error = void 0;
333
- if (equals(value, atom.state.value, atom.n)) {
334
- atom.b = false;
349
+ if (equals(value, atom.state.value, atom.m)) {
350
+ atom.c = false;
335
351
  } else {
336
- atom.state.value = atom.f = value;
352
+ atom.state.value = atom.d = value;
337
353
  }
338
354
  }
339
355
  } catch (e) {
340
- ++atom.g;
341
- if (!e) {
342
- atom.b = false;
356
+ finalizeExecution(atom);
357
+ if (e === expired) {
358
+ atom.c = false;
343
359
  } else {
344
360
  if (e instanceof Wrapped) {
345
361
  e = e.e;
346
362
  } else {
347
363
  logError(e);
348
364
  }
349
- if (isPromiseLike(e)) {
350
- atom.state.promise = e;
351
- } else {
352
- atom.state.error = e;
353
- }
365
+ atom.state.error = e;
354
366
  }
355
367
  }
368
+ };
369
+ const finalizeExecution = (atom) => {
370
+ ++atom.n;
371
+ const oldDependencies = atom.j;
372
+ atom.j = atom.k;
356
373
  if (oldDependencies) {
357
374
  for (const dep of oldDependencies) {
358
- dep.d.delete(atom);
359
- disableAtom(dep);
375
+ if (!atom.j?.has(dep)) {
376
+ dep.b.delete(atom);
377
+ disableAtom(dep);
378
+ }
360
379
  }
380
+ oldDependencies.clear();
361
381
  }
382
+ atom.k = oldDependencies;
362
383
  };
363
- let disabling = false;
384
+ let runningGc = false;
385
+ let gcCandidates = /* @__PURE__ */ new Set();
364
386
  const disableAtom = (atom) => {
365
- if (!atom.p && !atom.s && !atom.d?.size && !atom.h?.size && !atom.i?.size) {
366
- if (!disabling) {
367
- setTimeout(() => {
368
- disabling = true;
369
- disableAtom(atom);
370
- disabling = false;
371
- }, 0);
372
- return;
373
- }
374
- atom.state.promise = inactive;
375
- atom.f = atom.o = atom.state.error = atom.state.value = void 0;
376
- atom.b = atom.k = atom.c = false;
377
- if (atom.a) {
378
- atom.a.abort();
379
- atom.a = void 0;
387
+ if (!atom.r && !atom.s && !atom.b?.size && !atom.f?.size && !atom.g?.size) {
388
+ gcCandidates.add(atom);
389
+ if (!runningGc) {
390
+ runningGc = true;
391
+ setTimeout(gc, 0);
380
392
  }
381
- if (atom.l) {
382
- for (const dep of atom.l) {
383
- dep.d.delete(atom);
384
- disableAtom(dep);
393
+ }
394
+ };
395
+ const gc = () => {
396
+ for (const atom of gcCandidates) {
397
+ if (!atom.r && !atom.s && !atom.b?.size && !atom.f?.size && !atom.g?.size) {
398
+ atom.state.promise = inactive;
399
+ atom.d = atom.o = atom.state.error = atom.state.value = void 0;
400
+ atom.c = atom.i = atom.h = false;
401
+ if (atom.a) {
402
+ atom.a.abort();
403
+ atom.a = void 0;
404
+ }
405
+ if (atom.j) {
406
+ for (const dep of atom.j) {
407
+ dep.b.delete(atom);
408
+ disableAtom(dep);
409
+ }
410
+ atom.j.clear();
411
+ if (atom.k) {
412
+ for (const dep of atom.k) {
413
+ dep.b.delete(atom);
414
+ disableAtom(dep);
415
+ }
416
+ atom.k.clear();
417
+ }
385
418
  }
386
- atom.l.clear();
387
419
  }
388
420
  }
421
+ gcCandidates.clear();
422
+ runningGc = false;
389
423
  };
390
424
  const equals = (value, prevValue, equalsFn) => Object.is(value, prevValue) || equalsFn !== void 0 && prevValue !== void 0 && equalsFn(value, prevValue);
391
425
  const isPromiseLike = (x) => typeof x?.then === "function";
package/dist/react.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
- import { createContext, use, useContext, useState, useSyncExternalStore } from "react";
2
+ import { createContext, use, useContext, useMemo, useState, useSyncExternalStore } from "react";
3
3
  import { $, createScope } from ".";
4
4
  const ScopeContext = createContext((x) => x);
5
5
  const ScopeProvider = ({ value, children }) => {
6
6
  const parentScope = useContext(ScopeContext);
7
- const scope = useState(() => createScope(parentScope, value))[0];
7
+ const scope = useMemo(() => createScope(parentScope, value), [parentScope]);
8
8
  return /* @__PURE__ */ jsx(ScopeContext.Provider, { value: scope, children });
9
9
  };
10
10
  const useAtomValue = (atom) => (atom = useContext(ScopeContext)(atom), useSyncExternalStore(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bansa",
3
- "version": "0.0.12",
3
+ "version": "0.0.14",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,5 +1,5 @@
1
1
  import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
- import { $, createScope, type ThenableSignal } from '../src/index';
2
+ import { $, createScope, DerivedAtom, type ThenableSignal } from '../src/index';
3
3
 
4
4
  const flushMicrotasks = () =>
5
5
  new Promise((resolve) => {
@@ -445,6 +445,92 @@ describe('Atom Library - Advanced Tests', () => {
445
445
  expect(derivedAtom3.state.value).toEqual(undefined);
446
446
  });
447
447
 
448
+ it('gc test', async () => {
449
+ const atom1 = $(10);
450
+
451
+ const metrics1 = { mounted: 0, unmounted: 0 };
452
+ const derivedAtom1 = $((get, { signal }) => {
453
+ metrics1.mounted++;
454
+ signal.then(() => {
455
+ metrics1.unmounted++;
456
+ });
457
+ return get(atom1);
458
+ });
459
+
460
+ const unsub = derivedAtom1.subscribe(nop);
461
+ await flushMicrotasks();
462
+ expect(metrics1).toEqual({ mounted: 1, unmounted: 0 });
463
+ expect(derivedAtom1.state.value).toEqual(10);
464
+
465
+ unsub();
466
+ await flushMicrotasks();
467
+ expect(metrics1).toEqual({ mounted: 1, unmounted: 0 });
468
+ expect(derivedAtom1.state.value).toEqual(10);
469
+
470
+ const unsub2 = derivedAtom1.subscribe(nop);
471
+ await flushMicrotasks();
472
+ expect(metrics1).toEqual({ mounted: 1, unmounted: 0 });
473
+ expect(derivedAtom1.state.value).toEqual(10);
474
+
475
+ atom1.set(20);
476
+ await flushMicrotasks();
477
+ expect(metrics1).toEqual({ mounted: 2, unmounted: 1 });
478
+ expect(derivedAtom1.state.value).toEqual(20);
479
+
480
+ unsub2();
481
+ await new Promise((r) => setTimeout(r, 10));
482
+ expect(metrics1).toEqual({ mounted: 2, unmounted: 2 });
483
+ expect(derivedAtom1.state.value).toEqual(undefined);
484
+
485
+ atom1.set(30);
486
+ await flushMicrotasks();
487
+ expect(metrics1).toEqual({ mounted: 2, unmounted: 2 });
488
+ expect(derivedAtom1.state.value).toEqual(undefined);
489
+ });
490
+
491
+ it('deep scope', async () => {
492
+ const $x1 = $(1);
493
+ const $x2 = $((get) => get($x1) + 1);
494
+ const $x3 = $((get) => get($x2) + 1);
495
+ const $x4 = $((get) => get($x3) + 1);
496
+ const $x5 = $((get) => get($x4) + 1);
497
+ const identity = (x: any) => x;
498
+ const scope0 = createScope(identity);
499
+ const scope1 = createScope(identity, [
500
+ [$x1, 11],
501
+ ]);
502
+ const scope2 = createScope(identity, [
503
+ [$x2, 22],
504
+ ]);
505
+
506
+ $x5.subscribe(nop);
507
+ await flushMicrotasks();
508
+
509
+ const $y0 = scope0($x5);
510
+ const $y1 = scope1($x5);
511
+ const $y2 = scope2($x5);
512
+
513
+ expect($x5.get()).toBe(5);
514
+ expect($y0.get()).toBe(5);
515
+ expect($y1.get()).toBe(15);
516
+ expect($y2.get()).toBe(25);
517
+
518
+ $x1.set(101);
519
+ await flushMicrotasks();
520
+ expect($x5.get()).toBe(105);
521
+ expect($y0.get()).toBe(105);
522
+ expect($y1.get()).toBe(15);
523
+ expect($y2.get()).toBe(25);
524
+
525
+ scope1($x1).set(201);
526
+ scope2($x1).set(201);
527
+ await flushMicrotasks();
528
+ expect($x5.get()).toBe(205);
529
+ expect($y0.get()).toBe(205);
530
+ expect($y1.get()).toBe(205);
531
+ expect($y2.get()).toBe(25);
532
+ });
533
+
448
534
  it('should not provide stale values to conditional dependents', async () => {
449
535
  const dataAtom = $([100]);
450
536
  const hasFilterAtom = $(false);
@@ -550,26 +636,30 @@ describe('Atom Library - Advanced Tests', () => {
550
636
  await new Promise<void>((r) => (resolve = r));
551
637
  return count;
552
638
  });
553
- const async2Atom = $((get) => get(asyncAtom));
554
- const async3Atom = $((get) => get(async2Atom));
639
+ const async2Atom = $((get) => get(asyncAtom) % 3);
640
+ const mockFn = vi.fn((get: (atom: DerivedAtom<number>) => any) => get(async2Atom));
641
+ const async3Atom = $(mockFn);
555
642
 
556
643
  async3Atom.subscribe(nop);
557
644
  await flushMicrotasks();
558
645
  resolve();
559
646
  await flushMicrotasks();
560
- await expect(async3Atom.state.value).toBe(1);
647
+ expect(async3Atom.state.value).toBe(1);
648
+ expect(mockFn).toHaveBeenCalledTimes(2);
561
649
 
562
650
  countAtom.set((c) => c + 1);
563
651
  await flushMicrotasks();
564
652
  resolve();
565
653
  await flushMicrotasks();
566
- await expect(async3Atom.state.value).toBe(2);
654
+ expect(async3Atom.state.value).toBe(2);
655
+ expect(mockFn).toHaveBeenCalledTimes(3);
567
656
 
568
- countAtom.set((c) => c + 1);
657
+ countAtom.set((c) => c + 3);
569
658
  await flushMicrotasks();
570
659
  resolve();
571
660
  await flushMicrotasks();
572
- await expect(async3Atom.state.value).toBe(3);
661
+ expect(async3Atom.state.value).toBe(2);
662
+ expect(mockFn).toHaveBeenCalledTimes(3);
573
663
  });
574
664
  });
575
665