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.
- package/dist/index.browser.js +1 -1
- package/dist/index.browser.js.br +0 -0
- package/dist/index.d.ts +5 -8
- package/dist/index.js +248 -230
- package/dist/react.js +3 -5
- package/package.json +7 -7
- package/tests/bansa.test.ts +212 -8
package/dist/index.browser.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
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
|
-
|
|
70
|
-
|
|
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<
|
|
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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
-
|
|
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
|
-
(
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
|
|
50
|
-
|
|
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
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
)
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
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.
|
|
123
|
+
const inactive = Promise.reject();
|
|
124
|
+
inactive.catch(toUndefined);
|
|
111
125
|
const $ = (init, options) => {
|
|
112
126
|
if (init instanceof Function)
|
|
113
|
-
return new
|
|
114
|
-
return new
|
|
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
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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
|
|
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.
|
|
188
|
-
atom.
|
|
188
|
+
if (!atom.i) {
|
|
189
|
+
atom.i = true;
|
|
189
190
|
requestPropagate(atom);
|
|
190
191
|
}
|
|
191
192
|
};
|
|
192
193
|
const requestPropagate = (atom) => {
|
|
193
|
-
if (!atom.
|
|
194
|
-
atom.
|
|
195
|
-
|
|
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 =
|
|
206
|
-
|
|
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.
|
|
210
|
-
atom.state.value = atom.
|
|
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.
|
|
219
|
-
if (atom.
|
|
220
|
-
atom.
|
|
219
|
+
atom.p = false;
|
|
220
|
+
if (atom.i) {
|
|
221
|
+
atom.c = true;
|
|
221
222
|
execute(atom);
|
|
222
223
|
}
|
|
223
|
-
if (atom.
|
|
224
|
+
if (atom.c) {
|
|
224
225
|
propagate(atom);
|
|
225
226
|
}
|
|
226
227
|
}
|
|
227
228
|
};
|
|
228
229
|
const propagate = (atom) => {
|
|
229
|
-
atom.
|
|
230
|
-
if (atom.
|
|
231
|
-
for (const
|
|
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
|
-
|
|
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.
|
|
256
|
-
atom.
|
|
257
|
-
if (atom.
|
|
258
|
-
for (const child of atom.
|
|
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.
|
|
273
|
-
atom.
|
|
274
|
-
atom.
|
|
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.
|
|
289
|
+
const value = atom.l(
|
|
286
290
|
(anotherAtom, unwrap = true) => {
|
|
287
|
-
if (counter !== atom.
|
|
291
|
+
if (counter !== atom.m) throw expired;
|
|
288
292
|
if (atom !== anotherAtom) {
|
|
289
|
-
if (!anotherAtom.
|
|
293
|
+
if (!anotherAtom.h) {
|
|
290
294
|
execute(anotherAtom);
|
|
291
|
-
if (anotherAtom.
|
|
292
|
-
anotherAtom.b = false;
|
|
295
|
+
if (anotherAtom.c) {
|
|
293
296
|
propagate(anotherAtom);
|
|
294
297
|
}
|
|
295
298
|
}
|
|
296
|
-
|
|
297
|
-
(
|
|
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.
|
|
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.
|
|
314
|
-
|
|
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.
|
|
318
|
-
atom.
|
|
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.
|
|
325
|
-
|
|
326
|
-
|
|
327
|
+
if (counter === atom.m) {
|
|
328
|
+
finalizeExecution(atom);
|
|
329
|
+
if (e instanceof Wrapped) {
|
|
330
|
+
e = e.e;
|
|
327
331
|
} else {
|
|
328
|
-
|
|
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
|
-
|
|
340
|
+
finalizeExecution(atom);
|
|
341
341
|
atom.state.error = void 0;
|
|
342
|
-
if (equals(value, atom.state.value, atom.
|
|
343
|
-
atom.
|
|
342
|
+
if (equals(value, atom.state.value, atom.q)) {
|
|
343
|
+
atom.c = false;
|
|
344
344
|
} else {
|
|
345
|
-
atom.state.value = atom.
|
|
345
|
+
atom.state.value = atom.d = value;
|
|
346
346
|
}
|
|
347
347
|
}
|
|
348
348
|
} catch (e) {
|
|
349
|
-
|
|
350
|
-
if (
|
|
351
|
-
atom.
|
|
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
|
-
|
|
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
|
-
|
|
368
|
-
|
|
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
|
|
377
|
+
let runningGc = false;
|
|
378
|
+
let gcCandidates = /* @__PURE__ */ new Set();
|
|
373
379
|
const disableAtom = (atom) => {
|
|
374
|
-
if (!atom.
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
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
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
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 =
|
|
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.
|
|
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.
|
|
21
|
-
"@types/react": "^19.
|
|
22
|
-
"@types/react-dom": "^19.
|
|
23
|
-
"esbuild": "^0.
|
|
24
|
-
"typescript": "^5.9.
|
|
25
|
-
"vitest": "^
|
|
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",
|
package/tests/bansa.test.ts
CHANGED
|
@@ -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()).
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
654
|
+
expect(async3Atom.state.value).toBe(2);
|
|
655
|
+
expect(mockFn).toHaveBeenCalledTimes(3);
|
|
567
656
|
|
|
568
|
-
countAtom.set((c) => c +
|
|
657
|
+
countAtom.set((c) => c + 3);
|
|
569
658
|
await flushMicrotasks();
|
|
570
659
|
resolve();
|
|
571
660
|
await flushMicrotasks();
|
|
572
|
-
|
|
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', () => {
|