bansa 0.0.12 → 0.0.13

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;V;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,p:{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.p)}catch(n){f(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;A=!1;constructor(t,a){super(),this.d=t,this.m=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.m)||(this.r=a,m(this))}};i.prototype.y=!0;i.prototype.s=!0;i.prototype.u=!1;var A=class extends d{s=!1;u=!1;n=!1;A=!1;f=0;t;i;c;constructor(t,a){super(),this.d=t,this.m=a?.equals,this.b=!!a?.persist;let n=this;this.p={get signal(){return(n.t||=q()).signal}},this.state={promise:g,error:void 0,value:void 0}}};A.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 p=(e,t)=>e instanceof Function?new A(e,t):new i(e,t),z=e=>p((t,a)=>{let n,r,o=e(y=>{let l=t(y,!1);if(l.error)r=l.error;else if(l.promise)(n||=[]).push(l.promise);else return l.value;return c},a);if(r)throw r;if(n)throw Promise.all(n);return o},{equals:T}),C=(e,t)=>{let a=new WeakMap;if(t)for(let[r,o]of t)a.set(r,o instanceof d?o:p(o));let n=(r=>{let o=a.get(r);return o||a.set(r,o=r.d instanceof Function?p((y,l)=>r.d((D,E)=>y(n(D),E),l)):e?.(r)||p(r.d)),o});return n},T=(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,m(e))},m=e=>{e.n||(e.n=!0,h.push(e),b||(b=!0,queueMicrotask(K)))},K=()=>{b=!1;{let t=h;h=[];for(let a of t)a.state.promise=void 0,a.state.error=a.V,a.state.value=a.r,O(a)}let e=v;v=[];for(let t=e.length;t--;){let a=e[t];a.A=!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){f(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.p)}catch(a){f(a)}}if(e.a)for(let t of e.a)t.u=!0}},O=e=>{if(!e.A){if(e.A=!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.p);j(a)?(e.state.promise=a,a.then(n=>{t===e.f&&(V(e),x(n,e.state.value,e.m)?e.state.promise=void 0:(e.r=n,e.V=void 0),m(e))},n=>{t===e.f&&(V(e),n instanceof s?n=n.e:f(n),e.V=n,m(e))})):(V(e),e.state.error=void 0,x(a,e.state.value,e.m)?e.n=!1:e.state.value=e.r=a)}catch(a){V(e),a===P?e.n=!1:(a instanceof s?a=a.e:f(a),e.state.error=a)}},V=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(L,0)))},L=()=>{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.V=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),j=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}},f=e=>{queueMicrotask(()=>{throw e})};export{p as $,z as $$,C as createScope,g as inactive};
Binary file
package/dist/index.d.ts CHANGED
@@ -71,7 +71,7 @@ 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
77
  export type AtomValuePair<Value> = [Atom<Value>, Value | Atom<Value>];
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
+ n;
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
+ o: {
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.o);
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
+ p = false;
65
+ constructor(init, options) {
66
+ super();
67
+ this.l = init;
68
+ this.q = 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.q)) {
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
+ p = false;
92
+ m = 0;
93
+ a;
94
+ j;
95
+ k;
96
+ constructor(init, options) {
97
+ super();
98
+ this.l = init;
99
+ this.q = options?.equals;
100
+ this.s = !!options?.persist;
101
+ const self = this;
102
+ this.o = {
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,18 @@ 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) scopeMap.set(
156
+ baseAtom,
157
+ scopedAtom = baseAtom.l instanceof Function ? $((get, options) => baseAtom.l(
158
+ (atom, unwrap) => get(scope(atom), unwrap),
159
+ options
160
+ )) : parentScope?.(baseAtom) || $(baseAtom.l)
161
+ );
153
162
  return scopedAtom;
154
163
  });
155
164
  return scope;
@@ -173,17 +182,18 @@ const shallowEquals = (a, b) => {
173
182
  return true;
174
183
  };
175
184
  let pendingUpdateAtoms = false;
185
+ let updateQueue = [];
176
186
  let stack = [];
177
187
  const requestActivate = (atom) => {
178
- if (!atom.k) {
179
- atom.k = true;
188
+ if (!atom.i) {
189
+ atom.i = true;
180
190
  requestPropagate(atom);
181
191
  }
182
192
  };
183
193
  const requestPropagate = (atom) => {
184
- if (!atom.b) {
185
- atom.b = true;
186
- stack.push(atom);
194
+ if (!atom.c) {
195
+ atom.c = true;
196
+ updateQueue.push(atom);
187
197
  if (!pendingUpdateAtoms) {
188
198
  pendingUpdateAtoms = true;
189
199
  queueMicrotask(updateAtoms);
@@ -193,12 +203,12 @@ const requestPropagate = (atom) => {
193
203
  const updateAtoms = () => {
194
204
  pendingUpdateAtoms = false;
195
205
  {
196
- const updatedAtoms = stack;
197
- stack = [];
206
+ const updatedAtoms = updateQueue;
207
+ updateQueue = [];
198
208
  for (const atom of updatedAtoms) {
199
209
  atom.state.promise = void 0;
200
- atom.state.error = atom.o;
201
- atom.state.value = atom.f;
210
+ atom.state.error = atom.n;
211
+ atom.state.value = atom.d;
202
212
  mark(atom);
203
213
  }
204
214
  }
@@ -206,47 +216,53 @@ const updateAtoms = () => {
206
216
  stack = [];
207
217
  for (let i = markedAtoms.length; i--; ) {
208
218
  const atom = markedAtoms[i];
209
- atom.q = false;
210
- if (atom.k) {
211
- atom.b = true;
219
+ atom.p = false;
220
+ if (atom.i) {
221
+ atom.c = true;
212
222
  execute(atom);
213
223
  }
214
- if (atom.b) {
224
+ if (atom.c) {
215
225
  propagate(atom);
216
226
  }
217
227
  }
218
228
  };
219
229
  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
- }
230
+ atom.c = false;
231
+ if (atom.f) {
232
+ for (const watcher of atom.f) {
237
233
  try {
238
- subscriber.r(atom.state.value, subscriber.m);
234
+ watcher();
239
235
  } catch (e) {
240
236
  logError(e);
241
237
  }
242
238
  }
243
239
  }
240
+ if (!atom.state.error && !atom.state.promise) {
241
+ if (atom.g) {
242
+ for (const subscriber of atom.g) {
243
+ if (subscriber.a) {
244
+ subscriber.a.abort();
245
+ subscriber.a = void 0;
246
+ }
247
+ try {
248
+ subscriber.t(atom.state.value, subscriber.o);
249
+ } catch (e) {
250
+ logError(e);
251
+ }
252
+ }
253
+ }
254
+ if (atom.b) {
255
+ for (const child of atom.b) {
256
+ child.i = true;
257
+ }
258
+ }
259
+ }
244
260
  };
245
261
  const mark = (atom) => {
246
- if (!atom.q) {
247
- atom.q = true;
248
- if (atom.d) {
249
- for (const child of atom.d) {
262
+ if (!atom.p) {
263
+ atom.p = true;
264
+ if (atom.b) {
265
+ for (const child of atom.b) {
250
266
  mark(child);
251
267
  }
252
268
  }
@@ -259,133 +275,144 @@ class Wrapped {
259
275
  this.e = e;
260
276
  }
261
277
  }
278
+ const expired = Symbol();
262
279
  const execute = (atom) => {
263
- const counter = ++atom.g;
264
- atom.c = true;
265
- atom.k = false;
280
+ const counter = ++atom.m;
281
+ atom.h = true;
282
+ atom.i = false;
266
283
  atom.state.promise = void 0;
267
284
  if (atom.a) {
268
285
  atom.a.abort();
269
286
  atom.a = void 0;
270
287
  }
271
- const oldDependencies = atom.l;
272
- if (oldDependencies) {
273
- atom.l = /* @__PURE__ */ new Set();
274
- }
275
288
  try {
276
- const value = atom.j(
289
+ const value = atom.l(
277
290
  (anotherAtom, unwrap = true) => {
278
- if (counter !== atom.g) throw void 0;
291
+ if (counter !== atom.m) throw expired;
279
292
  if (atom !== anotherAtom) {
280
- if (!anotherAtom.c) {
293
+ if (!anotherAtom.h) {
281
294
  execute(anotherAtom);
282
- if (anotherAtom.b) {
283
- anotherAtom.b = false;
295
+ if (anotherAtom.c) {
284
296
  propagate(anotherAtom);
285
297
  }
286
298
  }
287
- oldDependencies?.delete(anotherAtom);
288
- (atom.l ??= /* @__PURE__ */ new Set()).add(anotherAtom);
289
- (anotherAtom.d ??= /* @__PURE__ */ new Set()).add(atom);
299
+ (atom.k ||= /* @__PURE__ */ new Set()).add(anotherAtom);
300
+ (anotherAtom.b ||= /* @__PURE__ */ new Set()).add(atom);
290
301
  }
291
302
  if (!unwrap) return anotherAtom.state;
292
- if (anotherAtom.state.promise)
293
- throw new Wrapped(anotherAtom.state.promise);
294
303
  if (anotherAtom.state.error)
295
304
  throw new Wrapped(anotherAtom.state.error);
305
+ if (anotherAtom.state.promise)
306
+ throw new Wrapped(anotherAtom.state.promise);
296
307
  return anotherAtom.state.value;
297
308
  },
298
- atom.m
309
+ atom.o
299
310
  );
300
311
  if (isPromiseLike(value)) {
301
312
  atom.state.promise = value;
302
313
  value.then(
303
314
  (value2) => {
304
- if (counter === atom.g) {
305
- if (equals(value2, atom.state.value, atom.n)) {
315
+ if (counter === atom.m) {
316
+ finalizeExecution(atom);
317
+ if (equals(value2, atom.state.value, atom.q)) {
306
318
  atom.state.promise = void 0;
307
319
  } else {
308
- atom.f = value2;
309
- atom.o = void 0;
310
- requestPropagate(atom);
320
+ atom.d = value2;
321
+ atom.n = void 0;
311
322
  }
323
+ requestPropagate(atom);
312
324
  }
313
325
  },
314
326
  (e) => {
315
- if (counter === atom.g) {
316
- if (e instanceof Promise) {
317
- atom.state.promise = void 0;
327
+ if (counter === atom.m) {
328
+ finalizeExecution(atom);
329
+ if (e instanceof Wrapped) {
330
+ e = e.e;
318
331
  } else {
319
- if (e instanceof Wrapped) {
320
- e = e.e;
321
- } else {
322
- logError(e);
323
- }
324
- atom.o = e;
325
- requestPropagate(atom);
332
+ logError(e);
326
333
  }
334
+ atom.n = e;
335
+ requestPropagate(atom);
327
336
  }
328
337
  }
329
338
  );
330
339
  } else {
331
- ++atom.g;
340
+ finalizeExecution(atom);
332
341
  atom.state.error = void 0;
333
- if (equals(value, atom.state.value, atom.n)) {
334
- atom.b = false;
342
+ if (equals(value, atom.state.value, atom.q)) {
343
+ atom.c = false;
335
344
  } else {
336
- atom.state.value = atom.f = value;
345
+ atom.state.value = atom.d = value;
337
346
  }
338
347
  }
339
348
  } catch (e) {
340
- ++atom.g;
341
- if (!e) {
342
- atom.b = false;
349
+ finalizeExecution(atom);
350
+ if (e === expired) {
351
+ atom.c = false;
343
352
  } else {
344
353
  if (e instanceof Wrapped) {
345
354
  e = e.e;
346
355
  } else {
347
356
  logError(e);
348
357
  }
349
- if (isPromiseLike(e)) {
350
- atom.state.promise = e;
351
- } else {
352
- atom.state.error = e;
353
- }
358
+ atom.state.error = e;
354
359
  }
355
360
  }
361
+ };
362
+ const finalizeExecution = (atom) => {
363
+ ++atom.m;
364
+ const oldDependencies = atom.j;
365
+ atom.j = atom.k;
356
366
  if (oldDependencies) {
357
367
  for (const dep of oldDependencies) {
358
- dep.d.delete(atom);
359
- disableAtom(dep);
368
+ if (!atom.j?.has(dep)) {
369
+ dep.b.delete(atom);
370
+ disableAtom(dep);
371
+ }
360
372
  }
373
+ oldDependencies.clear();
361
374
  }
375
+ atom.k = oldDependencies;
362
376
  };
363
- let disabling = false;
377
+ let runningGc = false;
378
+ let gcCandidates = /* @__PURE__ */ new Set();
364
379
  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;
380
+ if (!atom.r && !atom.s && !atom.b?.size && !atom.f?.size && !atom.g?.size) {
381
+ gcCandidates.add(atom);
382
+ if (!runningGc) {
383
+ runningGc = true;
384
+ setTimeout(gc, 0);
380
385
  }
381
- if (atom.l) {
382
- for (const dep of atom.l) {
383
- dep.d.delete(atom);
384
- disableAtom(dep);
386
+ }
387
+ };
388
+ const gc = () => {
389
+ for (const atom of gcCandidates) {
390
+ if (!atom.r && !atom.s && !atom.b?.size && !atom.f?.size && !atom.g?.size) {
391
+ atom.state.promise = inactive;
392
+ atom.d = atom.n = atom.state.error = atom.state.value = void 0;
393
+ atom.c = atom.i = atom.h = false;
394
+ if (atom.a) {
395
+ atom.a.abort();
396
+ atom.a = void 0;
397
+ }
398
+ if (atom.j) {
399
+ for (const dep of atom.j) {
400
+ dep.b.delete(atom);
401
+ disableAtom(dep);
402
+ }
403
+ atom.j.clear();
404
+ if (atom.k) {
405
+ for (const dep of atom.k) {
406
+ dep.b.delete(atom);
407
+ disableAtom(dep);
408
+ }
409
+ atom.k.clear();
410
+ }
385
411
  }
386
- atom.l.clear();
387
412
  }
388
413
  }
414
+ gcCandidates.clear();
415
+ runningGc = false;
389
416
  };
390
417
  const equals = (value, prevValue, equalsFn) => Object.is(value, prevValue) || equalsFn !== void 0 && prevValue !== void 0 && equalsFn(value, prevValue);
391
418
  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.13",
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