bansa 0.0.11 → 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 p=function(){};p.prototype.get=function(){if(this.o||(I(this),u(this)),this.state.promise)throw this.state.promise;if(this.state.error)throw this.state.error;return this.state.value};p.prototype.watch=function(e){return this.o||g(this),(this.s??=new Set).add(e),()=>{this.s.delete(e),this.s.size||u(this)}};p.prototype.subscribe=function(e){let t={y:e,c:{get signal(){return(t.t??=_()).signal}}};if(!this.o)g(this);else if(!this.state.promise&&!this.state.error)try{e(this.state.value,t.c)}catch(o){y(o)}return(this.u??=new Set).add(t),()=>{this.u.delete(t),t.t&&(t.t.abort(),t.t=void 0),this.u.size||u(this)}};p.prototype[Symbol.toPrimitive]=function(){return this.state.value};var V=function(e,t){this.a=e,this.f=t?.equals,this.state={promise:void 0,error:void 0,value:e},this.state.value=this.l=e};V.prototype.set=function(e){let t=e instanceof Function?e(this.l):e;S(t,this.state.value,this.f)||(this.l=t,d(this))};V.prototype.m=!0;V.prototype.o=!0;V.prototype.n=!1;Object.setPrototypeOf(V.prototype,p.prototype);var c=function(e,t){this.a=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}}};c.prototype.m=!1;c.prototype.o=!1;c.prototype.n=!1;c.prototype.i=0;Object.setPrototypeOf(c.prototype,p.prototype);var m=()=>m,O=()=>{};Object.setPrototypeOf(m,new Proxy(m,{get:(e,t)=>t===Symbol.toPrimitive?O:m}));var P=Promise.resolve(),A=(e,t)=>e instanceof Function?new c(e,t):new V(e,t),T=e=>A((t,o)=>{let r,n,f=e((l,h)=>{try{return t(l,h)}catch(a){if(!a)throw a;w(a)?(r??=[]).push(a):n=a}return m},o);if(n)throw n;if(r)throw Promise.all(r);return f},{equals:G}),q=(e,t)=>{let o=new WeakMap;if(t)for(let[r,n]of t)o.set(r,A(n));return(r=>{{let n=o.get(r);if(n)return n}return r.a instanceof Function?A((n,f)=>r.a((l,h)=>{let a=o.get(l);return a||(e?a=e(l):e!==null?a=l:o.set(l,a=A(l.a))),n(a,h)},f)):A(r.a)})},G=(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,i=[],g=e=>{e.p||(e.p=!0,d(e))},d=e=>{e.n||(e.n=!0,i.push(e),b||(b=!0,queueMicrotask(D)))},D=()=>{b=!1;{let t=i;i=[];for(let o of t)o.state.promise=void 0,o.state.error=o.A,o.state.value=o.l,k(o)}let e=i;i=[];for(let t=e.length;t--;){let o=e[t];o.d=!1,o.p&&(o.n=!0,I(o)),o.n&&x(o)}},x=e=>{if(e.n=!1,e.r)for(let t of e.r)t.p=!0;if(e.s)for(let t of e.s)t();if(e.u&&!e.state.promise&&!e.state.error)for(let t of e.u){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);i.push(e)}},s=class{e;constructor(t){this.e=t}},I=e=>{let t=++e.i;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.a((n,f=!0)=>{if(t!==e.i)throw void 0;if(e!==n&&(n.o||(I(n),n.n&&(n.n=!1,x(n))),o?.delete(n),(e.V??=new Set).add(n),(n.r??=new Set).add(e)),!f)return n.state;if(n.state.promise)throw new s(n.state.promise);if(n.state.error)throw new s(n.state.error);return n.state.value},e.c);w(r)?(e.state.promise=r,r.then(n=>{t===e.i&&(S(n,e.state.value,e.f)?e.state.promise=void 0:(e.l=n,e.A=void 0,d(e)))},n=>{t===e.i&&(n instanceof Promise?e.state.promise=void 0:(n instanceof s?n=n.e:y(n),e.A=n,d(e)))})):(++e.i,e.state.error=void 0,S(r,e.state.value,e.f)?e.n=!1:e.state.value=e.l=r)}catch(r){++e.i,r?(r instanceof s?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),u(r)},v=!1,u=e=>{if(!e.m&&!e.h&&!e.r?.size&&!e.s?.size&&!e.u?.size){if(!v){setTimeout(()=>{v=!0,u(e),v=!1},0);return}if(e.state.promise=P,e.l=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),u(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{A as $,T as $$,q 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
@@ -65,18 +65,15 @@ export type AtomScope = {
65
65
  <Value>(baseAtom: PrimitiveAtom<Value>): PrimitiveAtom<Value>;
66
66
  <Value>(baseAtom: DerivedAtom<Value>): DerivedAtom<Value>;
67
67
  <Value>(baseAtom: Atom<Value>): Atom<Value>;
68
- } & {
69
- get: {
70
- <Value>(baseAtom: PrimitiveAtom<Value>): PrimitiveAtom<Value>;
71
- <Value>(baseAtom: DerivedAtom<Value>): DerivedAtom<Value>;
72
- <Value>(baseAtom: Atom<Value>): Atom<Value>;
73
- };
68
+ <Value>(baseAtom: PrimitiveAtom<Value>, create: false): PrimitiveAtom<Value> | undefined;
69
+ <Value>(baseAtom: DerivedAtom<Value>, create: false): DerivedAtom<Value> | undefined;
70
+ <Value>(baseAtom: Atom<Value>, create: false): Atom<Value> | undefined;
74
71
  };
75
72
  export type SetLike<Key> = Key[] | Set<Key> | (Key extends object ? WeakSet<Key> : never);
76
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);
77
- export declare const inactive: Promise<void>;
74
+ export declare const inactive: Promise<never>;
78
75
  export declare const $: CreateAtom;
79
76
  export declare const $$: <Value>(init: AtomGetter<Value>) => DerivedAtom<Value>;
80
- export type AtomValuePair<Value> = [Atom<Value>, Value];
77
+ export type AtomValuePair<Value> = [Atom<Value>, Value | Atom<Value>];
81
78
  export declare const createScope: (parentScope?: AtomScope | null, atomValuePairs?: AtomValuePair<unknown>[]) => AtomScope;
82
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.i ??= /* @__PURE__ */ new Set()).add(watcher);
17
- return () => {
18
- this.i.delete(watcher);
19
- if (!this.i.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.j ??= /* @__PURE__ */ new Set()).add(atomSubscriber);
43
- return () => {
44
- this.j.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.j.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.f = 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.g = init;
66
- };
67
- PrimitiveAtomPrototype.prototype.set = function(value) {
68
- const nextValue = value instanceof Function ? value(this.g) : value;
69
- if (!equals(nextValue, this.state.value, this.n)) {
70
- this.g = 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.f = 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.h = 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,27 +147,21 @@ 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));
150
+ scopeMap.set(atom, value instanceof CommonAtomInternal ? value : $(value));
145
151
  }
146
152
  }
147
- return ((baseAtom) => {
148
- {
149
- const scopedAtom = scopeMap.get(baseAtom);
150
- if (scopedAtom) return scopedAtom;
151
- }
152
- if (baseAtom.f instanceof Function) return $(
153
- (get, options) => baseAtom.f((atom, unwrap) => {
154
- let scopedAtom = scopeMap.get(atom);
155
- if (!scopedAtom) {
156
- if (parentScope) scopedAtom = parentScope(atom);
157
- else if (parentScope !== null) scopedAtom = atom;
158
- else scopeMap.set(atom, scopedAtom = $(atom.f));
159
- }
160
- return get(scopedAtom, unwrap);
161
- }, options)
153
+ const scope = ((baseAtom) => {
154
+ let scopedAtom = scopeMap.get(baseAtom);
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)
162
161
  );
163
- return $(baseAtom.f);
162
+ return scopedAtom;
164
163
  });
164
+ return scope;
165
165
  };
166
166
  const shallowEquals = (a, b) => {
167
167
  if (typeof a !== "object" || typeof b !== "object" || !a || !b) return false;
@@ -182,17 +182,18 @@ const shallowEquals = (a, b) => {
182
182
  return true;
183
183
  };
184
184
  let pendingUpdateAtoms = false;
185
+ let updateQueue = [];
185
186
  let stack = [];
186
187
  const requestActivate = (atom) => {
187
- if (!atom.k) {
188
- atom.k = true;
188
+ if (!atom.i) {
189
+ atom.i = true;
189
190
  requestPropagate(atom);
190
191
  }
191
192
  };
192
193
  const requestPropagate = (atom) => {
193
- if (!atom.b) {
194
- atom.b = true;
195
- stack.push(atom);
194
+ if (!atom.c) {
195
+ atom.c = true;
196
+ updateQueue.push(atom);
196
197
  if (!pendingUpdateAtoms) {
197
198
  pendingUpdateAtoms = true;
198
199
  queueMicrotask(updateAtoms);
@@ -202,12 +203,12 @@ const requestPropagate = (atom) => {
202
203
  const updateAtoms = () => {
203
204
  pendingUpdateAtoms = false;
204
205
  {
205
- const updatedAtoms = stack;
206
- stack = [];
206
+ const updatedAtoms = updateQueue;
207
+ updateQueue = [];
207
208
  for (const atom of updatedAtoms) {
208
209
  atom.state.promise = void 0;
209
- atom.state.error = atom.o;
210
- atom.state.value = atom.g;
210
+ atom.state.error = atom.n;
211
+ atom.state.value = atom.d;
211
212
  mark(atom);
212
213
  }
213
214
  }
@@ -215,47 +216,53 @@ const updateAtoms = () => {
215
216
  stack = [];
216
217
  for (let i = markedAtoms.length; i--; ) {
217
218
  const atom = markedAtoms[i];
218
- atom.q = false;
219
- if (atom.k) {
220
- atom.b = true;
219
+ atom.p = false;
220
+ if (atom.i) {
221
+ atom.c = true;
221
222
  execute(atom);
222
223
  }
223
- if (atom.b) {
224
+ if (atom.c) {
224
225
  propagate(atom);
225
226
  }
226
227
  }
227
228
  };
228
229
  const propagate = (atom) => {
229
- atom.b = false;
230
- if (atom.d) {
231
- for (const child of atom.d) {
232
- child.k = true;
233
- }
234
- }
235
- if (atom.i) {
236
- for (const watcher of atom.i) {
237
- watcher();
238
- }
239
- }
240
- if (atom.j && !atom.state.promise && !atom.state.error) {
241
- for (const subscriber of atom.j) {
242
- if (subscriber.a) {
243
- subscriber.a.abort();
244
- subscriber.a = void 0;
245
- }
230
+ atom.c = false;
231
+ if (atom.f) {
232
+ for (const watcher of atom.f) {
246
233
  try {
247
- subscriber.r(atom.state.value, subscriber.m);
234
+ watcher();
248
235
  } catch (e) {
249
236
  logError(e);
250
237
  }
251
238
  }
252
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
+ }
253
260
  };
254
261
  const mark = (atom) => {
255
- if (!atom.q) {
256
- atom.q = true;
257
- if (atom.d) {
258
- 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) {
259
266
  mark(child);
260
267
  }
261
268
  }
@@ -268,133 +275,144 @@ class Wrapped {
268
275
  this.e = e;
269
276
  }
270
277
  }
278
+ const expired = Symbol();
271
279
  const execute = (atom) => {
272
- const counter = ++atom.h;
273
- atom.c = true;
274
- atom.k = false;
280
+ const counter = ++atom.m;
281
+ atom.h = true;
282
+ atom.i = false;
275
283
  atom.state.promise = void 0;
276
284
  if (atom.a) {
277
285
  atom.a.abort();
278
286
  atom.a = void 0;
279
287
  }
280
- const oldDependencies = atom.l;
281
- if (oldDependencies) {
282
- atom.l = /* @__PURE__ */ new Set();
283
- }
284
288
  try {
285
- const value = atom.f(
289
+ const value = atom.l(
286
290
  (anotherAtom, unwrap = true) => {
287
- if (counter !== atom.h) throw void 0;
291
+ if (counter !== atom.m) throw expired;
288
292
  if (atom !== anotherAtom) {
289
- if (!anotherAtom.c) {
293
+ if (!anotherAtom.h) {
290
294
  execute(anotherAtom);
291
- if (anotherAtom.b) {
292
- anotherAtom.b = false;
295
+ if (anotherAtom.c) {
293
296
  propagate(anotherAtom);
294
297
  }
295
298
  }
296
- oldDependencies?.delete(anotherAtom);
297
- (atom.l ??= /* @__PURE__ */ new Set()).add(anotherAtom);
298
- (anotherAtom.d ??= /* @__PURE__ */ new Set()).add(atom);
299
+ (atom.k ||= /* @__PURE__ */ new Set()).add(anotherAtom);
300
+ (anotherAtom.b ||= /* @__PURE__ */ new Set()).add(atom);
299
301
  }
300
302
  if (!unwrap) return anotherAtom.state;
301
- if (anotherAtom.state.promise)
302
- throw new Wrapped(anotherAtom.state.promise);
303
303
  if (anotherAtom.state.error)
304
304
  throw new Wrapped(anotherAtom.state.error);
305
+ if (anotherAtom.state.promise)
306
+ throw new Wrapped(anotherAtom.state.promise);
305
307
  return anotherAtom.state.value;
306
308
  },
307
- atom.m
309
+ atom.o
308
310
  );
309
311
  if (isPromiseLike(value)) {
310
312
  atom.state.promise = value;
311
313
  value.then(
312
314
  (value2) => {
313
- if (counter === atom.h) {
314
- 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)) {
315
318
  atom.state.promise = void 0;
316
319
  } else {
317
- atom.g = value2;
318
- atom.o = void 0;
319
- requestPropagate(atom);
320
+ atom.d = value2;
321
+ atom.n = void 0;
320
322
  }
323
+ requestPropagate(atom);
321
324
  }
322
325
  },
323
326
  (e) => {
324
- if (counter === atom.h) {
325
- if (e instanceof Promise) {
326
- atom.state.promise = void 0;
327
+ if (counter === atom.m) {
328
+ finalizeExecution(atom);
329
+ if (e instanceof Wrapped) {
330
+ e = e.e;
327
331
  } else {
328
- if (e instanceof Wrapped) {
329
- e = e.e;
330
- } else {
331
- logError(e);
332
- }
333
- atom.o = e;
334
- requestPropagate(atom);
332
+ logError(e);
335
333
  }
334
+ atom.n = e;
335
+ requestPropagate(atom);
336
336
  }
337
337
  }
338
338
  );
339
339
  } else {
340
- ++atom.h;
340
+ finalizeExecution(atom);
341
341
  atom.state.error = void 0;
342
- if (equals(value, atom.state.value, atom.n)) {
343
- atom.b = false;
342
+ if (equals(value, atom.state.value, atom.q)) {
343
+ atom.c = false;
344
344
  } else {
345
- atom.state.value = atom.g = value;
345
+ atom.state.value = atom.d = value;
346
346
  }
347
347
  }
348
348
  } catch (e) {
349
- ++atom.h;
350
- if (!e) {
351
- atom.b = false;
349
+ finalizeExecution(atom);
350
+ if (e === expired) {
351
+ atom.c = false;
352
352
  } else {
353
353
  if (e instanceof Wrapped) {
354
354
  e = e.e;
355
355
  } else {
356
356
  logError(e);
357
357
  }
358
- if (isPromiseLike(e)) {
359
- atom.state.promise = e;
360
- } else {
361
- atom.state.error = e;
362
- }
358
+ atom.state.error = e;
363
359
  }
364
360
  }
361
+ };
362
+ const finalizeExecution = (atom) => {
363
+ ++atom.m;
364
+ const oldDependencies = atom.j;
365
+ atom.j = atom.k;
365
366
  if (oldDependencies) {
366
367
  for (const dep of oldDependencies) {
367
- dep.d.delete(atom);
368
- disableAtom(dep);
368
+ if (!atom.j?.has(dep)) {
369
+ dep.b.delete(atom);
370
+ disableAtom(dep);
371
+ }
369
372
  }
373
+ oldDependencies.clear();
370
374
  }
375
+ atom.k = oldDependencies;
371
376
  };
372
- let disabling = false;
377
+ let runningGc = false;
378
+ let gcCandidates = /* @__PURE__ */ new Set();
373
379
  const disableAtom = (atom) => {
374
- if (!atom.p && !atom.s && !atom.d?.size && !atom.i?.size && !atom.j?.size) {
375
- if (!disabling) {
376
- setTimeout(() => {
377
- disabling = true;
378
- disableAtom(atom);
379
- disabling = false;
380
- }, 0);
381
- return;
382
- }
383
- atom.state.promise = inactive;
384
- atom.g = atom.o = atom.state.error = atom.state.value = void 0;
385
- atom.b = atom.k = atom.c = false;
386
- if (atom.a) {
387
- atom.a.abort();
388
- 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);
389
385
  }
390
- if (atom.l) {
391
- for (const dep of atom.l) {
392
- dep.d.delete(atom);
393
- 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
+ }
394
411
  }
395
- atom.l.clear();
396
412
  }
397
413
  }
414
+ gcCandidates.clear();
415
+ runningGc = false;
398
416
  };
399
417
  const equals = (value, prevValue, equalsFn) => Object.is(value, prevValue) || equalsFn !== void 0 && prevValue !== void 0 && equalsFn(value, prevValue);
400
418
  const isPromiseLike = (x) => typeof x?.then === "function";
package/dist/react.js CHANGED
@@ -1,12 +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
- const ScopeContext = createContext(
5
- ((x) => x)
6
- );
4
+ const ScopeContext = createContext((x) => x);
7
5
  const ScopeProvider = ({ value, children }) => {
8
6
  const parentScope = useContext(ScopeContext);
9
- const scope = useState(() => createScope(parentScope, value))[0];
7
+ const scope = useMemo(() => createScope(parentScope, value), [parentScope]);
10
8
  return /* @__PURE__ */ jsx(ScopeContext.Provider, { value: scope, children });
11
9
  };
12
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.11",
3
+ "version": "0.0.13",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -17,12 +17,12 @@
17
17
  }
18
18
  },
19
19
  "devDependencies": {
20
- "@biomejs/biome": "^2.2.4",
21
- "@types/react": "^19.1.15",
22
- "@types/react-dom": "^19.1.9",
23
- "esbuild": "^0.25.10",
24
- "typescript": "^5.9.2",
25
- "vitest": "^3.2.4"
20
+ "@biomejs/biome": "^2.3.8",
21
+ "@types/react": "^19.2.7",
22
+ "@types/react-dom": "^19.2.3",
23
+ "esbuild": "^0.27.0",
24
+ "typescript": "^5.9.3",
25
+ "vitest": "^4.0.14"
26
26
  },
27
27
  "peerDependencies": {
28
28
  "@types/react": ">=17.0.0",
@@ -1,5 +1,5 @@
1
1
  import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
- import { $, 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);
@@ -476,7 +562,7 @@ describe('Atom Library - Advanced Tests', () => {
476
562
  await flushMicrotasks(); // Additional wait for promise resolution
477
563
 
478
564
  expect(errorAtom.state.error).toBe(error);
479
- expect(() => errorAtom.get()).toThrow(error);
565
+ expect(() => errorAtom.get()).toThrowError(error);
480
566
  });
481
567
 
482
568
  it('multiple subscribers receive updates', async () => {
@@ -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
 
@@ -951,6 +1041,120 @@ describe('Bansa Documentation Examples as Tests', () => {
951
1041
  });
952
1042
  });
953
1043
 
1044
+ // --- 스코프 테스트 ---
1045
+ describe('Scope', () => {
1046
+ it('scope with initial values', async () => {
1047
+ const $x = $(0);
1048
+ const $y = $(1);
1049
+ const $x2 = $(100);
1050
+ const scope = createScope(null, [
1051
+ [$x, $x2],
1052
+ [$y, 101],
1053
+ ]);
1054
+
1055
+ const $y2 = scope($y);
1056
+ expect(scope($x)).toBe($x2);
1057
+ expect($y2).not.toBe($y);
1058
+ expect($y2).toBe(scope($y));
1059
+
1060
+ expect($x.get()).toBe(0);
1061
+ expect($y.get()).toBe(1);
1062
+ expect($x2.get()).toBe(100);
1063
+ expect($y2.get()).toBe(101);
1064
+ });
1065
+
1066
+ it('scope with updates (1)', async () => {
1067
+ const $x = $(0);
1068
+ const $y = $((get) => get($x) + 1);
1069
+ const scope = createScope();
1070
+ const $x2 = scope($x);
1071
+ const $y2 = scope($y);
1072
+
1073
+ expect($x.get()).toBe(0);
1074
+ expect($y.get()).toBe(1);
1075
+ expect($x2.get()).toBe(0);
1076
+ expect($y2.get()).toBe(1);
1077
+
1078
+ $x.set(10);
1079
+ await flushMicrotasks();
1080
+
1081
+ expect($x.get()).toBe(10);
1082
+ expect($y.get()).toBe(11);
1083
+ expect($x2.get()).toBe(0);
1084
+ expect($y2.get()).toBe(1);
1085
+
1086
+ $x2.set(100);
1087
+ await flushMicrotasks();
1088
+
1089
+ expect($x.get()).toBe(10);
1090
+ expect($y.get()).toBe(11);
1091
+ expect($x2.get()).toBe(100);
1092
+ expect($y2.get()).toBe(101);
1093
+ });
1094
+
1095
+ it('scope with updates (2)', async () => {
1096
+ const $x = $(0);
1097
+ const $y = $((get) => get($x) + 1);
1098
+ const scope = createScope(null, [
1099
+ [$x, 100],
1100
+ ]);
1101
+ const $x2 = scope($x);
1102
+ const $y2 = scope($y);
1103
+
1104
+ expect($x.get()).toBe(0);
1105
+ expect($y.get()).toBe(1);
1106
+ expect($x2.get()).toBe(100);
1107
+ expect($y2.get()).toBe(101);
1108
+
1109
+ $x.set(10);
1110
+ await flushMicrotasks();
1111
+
1112
+ expect($x.get()).toBe(10);
1113
+ expect($y.get()).toBe(11);
1114
+ expect($x2.get()).toBe(100);
1115
+ expect($y2.get()).toBe(101);
1116
+
1117
+ $x2.set(1000);
1118
+ await flushMicrotasks();
1119
+
1120
+ expect($x.get()).toBe(10);
1121
+ expect($y.get()).toBe(11);
1122
+ expect($x2.get()).toBe(1000);
1123
+ expect($y2.get()).toBe(1001);
1124
+ });
1125
+
1126
+ it('scope with updates (3)', async () => {
1127
+ const $x = $(0);
1128
+ const $y = $((get) => get($x) + 1);
1129
+ const $x2 = $(100);
1130
+ const scope = createScope(null, [
1131
+ [$x, $x2],
1132
+ ]);
1133
+ const $y2 = scope($y);
1134
+
1135
+ expect($x.get()).toBe(0);
1136
+ expect($y.get()).toBe(1);
1137
+ expect($x2.get()).toBe(100);
1138
+ expect($y2.get()).toBe(101);
1139
+
1140
+ $x.set(10);
1141
+ await flushMicrotasks();
1142
+
1143
+ expect($x.get()).toBe(10);
1144
+ expect($y.get()).toBe(11);
1145
+ expect($x2.get()).toBe(100);
1146
+ expect($y2.get()).toBe(101);
1147
+
1148
+ $x2.set(1000);
1149
+ await flushMicrotasks();
1150
+
1151
+ expect($x.get()).toBe(10);
1152
+ expect($y.get()).toBe(11);
1153
+ expect($x2.get()).toBe(1000);
1154
+ expect($y2.get()).toBe(1001);
1155
+ });
1156
+ });
1157
+
954
1158
  // --- "스크롤 방향 감지" 예제 테스트 ---
955
1159
  /*
956
1160
  describe('Scroll Direction Detection Example', () => {