UNPKG

16.1 kBJavaScriptView Raw
1System.register([], (function (exports) {
2 'use strict';
3 return {
4 execute: (function () {
5
6 exports('atom', atom);
7
8 let keyCount = 0;
9 function atom(read, write) {
10 const key = `atom${++keyCount}`;
11 const config = {
12 toString: () => key
13 };
14 if (typeof read === "function") {
15 config.read = read;
16 } else {
17 config.init = read;
18 config.read = (get) => get(config);
19 config.write = (get, set, arg) => set(
20 config,
21 typeof arg === "function" ? arg(get(config)) : arg
22 );
23 }
24 if (write) {
25 config.write = write;
26 }
27 return config;
28 }
29
30 const hasInitialValue = (atom) => "init" in atom;
31 const isActuallyWritableAtom = (atom) => !!atom.write;
32 const cancelPromiseMap = /* @__PURE__ */ new WeakMap();
33 const registerCancelPromise = (promise, cancel) => {
34 cancelPromiseMap.set(promise, cancel);
35 promise.catch(() => {
36 }).finally(() => cancelPromiseMap.delete(promise));
37 };
38 const cancelPromise = (promise, next) => {
39 const cancel = cancelPromiseMap.get(promise);
40 if (cancel) {
41 cancelPromiseMap.delete(promise);
42 cancel(next);
43 }
44 };
45 const resolvePromise = (promise, value) => {
46 promise.status = "fulfilled";
47 promise.value = value;
48 };
49 const rejectPromise = (promise, e) => {
50 promise.status = "rejected";
51 promise.reason = e;
52 };
53 const isEqualAtomValue = (a, b) => "v" in a && "v" in b && Object.is(a.v, b.v);
54 const isEqualAtomError = (a, b) => "e" in a && "e" in b && Object.is(a.e, b.e);
55 const hasPromiseAtomValue = (a) => "v" in a && a.v instanceof Promise;
56 const returnAtomValue = (atomState) => {
57 if ("e" in atomState) {
58 throw atomState.e;
59 }
60 return atomState.v;
61 };
62 const createStore = exports('createStore', () => {
63 const atomStateMap = /* @__PURE__ */ new WeakMap();
64 const mountedMap = /* @__PURE__ */ new WeakMap();
65 const pendingMap = /* @__PURE__ */ new Map();
66 let stateListeners;
67 let mountedAtoms;
68 {
69 stateListeners = /* @__PURE__ */ new Set();
70 mountedAtoms = /* @__PURE__ */ new Set();
71 }
72 const getAtomState = (atom) => atomStateMap.get(atom);
73 const setAtomState = (atom, atomState) => {
74 {
75 Object.freeze(atomState);
76 }
77 const prevAtomState = atomStateMap.get(atom);
78 atomStateMap.set(atom, atomState);
79 if (!pendingMap.has(atom)) {
80 pendingMap.set(atom, prevAtomState);
81 }
82 if (prevAtomState && hasPromiseAtomValue(prevAtomState)) {
83 const next = "v" in atomState ? atomState.v instanceof Promise ? atomState.v : Promise.resolve(atomState.v) : Promise.reject(atomState.e);
84 cancelPromise(prevAtomState.v, next);
85 }
86 };
87 const updateDependencies = (atom, nextAtomState, depSet) => {
88 const dependencies = /* @__PURE__ */ new Map();
89 let changed = false;
90 depSet.forEach((a) => {
91 const aState = a === atom ? nextAtomState : getAtomState(a);
92 if (aState) {
93 dependencies.set(a, aState);
94 if (nextAtomState.d.get(a) !== aState) {
95 changed = true;
96 }
97 } else {
98 console.warn("[Bug] atom state not found");
99 }
100 });
101 if (changed || nextAtomState.d.size !== dependencies.size) {
102 nextAtomState.d = dependencies;
103 }
104 };
105 const setAtomValue = (atom, value, depSet) => {
106 const prevAtomState = getAtomState(atom);
107 const nextAtomState = {
108 d: (prevAtomState == null ? void 0 : prevAtomState.d) || /* @__PURE__ */ new Map(),
109 v: value
110 };
111 if (depSet) {
112 updateDependencies(atom, nextAtomState, depSet);
113 }
114 if (prevAtomState && isEqualAtomValue(prevAtomState, nextAtomState) && prevAtomState.d === nextAtomState.d) {
115 return prevAtomState;
116 }
117 setAtomState(atom, nextAtomState);
118 return nextAtomState;
119 };
120 const setAtomError = (atom, error, depSet) => {
121 const prevAtomState = getAtomState(atom);
122 const nextAtomState = {
123 d: (prevAtomState == null ? void 0 : prevAtomState.d) || /* @__PURE__ */ new Map(),
124 e: error
125 };
126 if (depSet) {
127 updateDependencies(atom, nextAtomState, depSet);
128 }
129 if (prevAtomState && isEqualAtomError(prevAtomState, nextAtomState) && prevAtomState.d === nextAtomState.d) {
130 return prevAtomState;
131 }
132 setAtomState(atom, nextAtomState);
133 return nextAtomState;
134 };
135 const readAtomState = (atom) => {
136 const atomState = getAtomState(atom);
137 if (atomState) {
138 atomState.d.forEach((_, a) => {
139 if (a !== atom && !mountedMap.has(a)) {
140 readAtomState(a);
141 }
142 });
143 if (Array.from(atomState.d).every(
144 ([a, s]) => a === atom || getAtomState(a) === s
145 )) {
146 return atomState;
147 }
148 }
149 const depSet = /* @__PURE__ */ new Set();
150 let isSync = true;
151 const getter = (a) => {
152 depSet.add(a);
153 if (a === atom) {
154 const aState2 = getAtomState(a);
155 if (aState2) {
156 return returnAtomValue(aState2);
157 }
158 if (hasInitialValue(a)) {
159 return a.init;
160 }
161 throw new Error("no atom init");
162 }
163 const aState = readAtomState(a);
164 return returnAtomValue(aState);
165 };
166 let controller;
167 let setSelf;
168 const options = {
169 get signal() {
170 if (!controller) {
171 controller = new AbortController();
172 }
173 return controller.signal;
174 },
175 get setSelf() {
176 if (!isActuallyWritableAtom(atom)) {
177 console.warn("setSelf function cannot be used with read-only atom");
178 }
179 if (!setSelf && isActuallyWritableAtom(atom)) {
180 setSelf = (...args) => {
181 if (isSync) {
182 console.warn("setSelf function cannot be called in sync");
183 }
184 if (!isSync) {
185 return writeAtom(atom, ...args);
186 }
187 };
188 }
189 return setSelf;
190 }
191 };
192 try {
193 const value = atom.read(getter, options);
194 if (value instanceof Promise) {
195 let continuePromise;
196 const promise = new Promise((resolve, reject) => {
197 let settled = false;
198 value.then(
199 (v) => {
200 if (!settled) {
201 resolvePromise(promise, v);
202 resolve(v);
203 }
204 },
205 (e) => {
206 if (!settled) {
207 rejectPromise(promise, e);
208 reject(e);
209 }
210 }
211 ).finally(() => {
212 if (!settled) {
213 settled = true;
214 setAtomValue(atom, promise, depSet);
215 }
216 });
217 continuePromise = (next) => {
218 if (!settled) {
219 settled = true;
220 next.then(
221 (v) => resolvePromise(promise, v),
222 (e) => rejectPromise(promise, e)
223 );
224 resolve(next);
225 }
226 };
227 });
228 promise.status = "pending";
229 registerCancelPromise(promise, (next) => {
230 if (next) {
231 continuePromise(next);
232 }
233 controller == null ? void 0 : controller.abort();
234 });
235 return setAtomValue(atom, promise, depSet);
236 }
237 return setAtomValue(atom, value, depSet);
238 } catch (error) {
239 return setAtomError(atom, error, depSet);
240 } finally {
241 isSync = false;
242 }
243 };
244 const readAtom = (atom) => returnAtomValue(readAtomState(atom));
245 const addAtom = (atom) => {
246 let mounted = mountedMap.get(atom);
247 if (!mounted) {
248 mounted = mountAtom(atom);
249 }
250 return mounted;
251 };
252 const canUnmountAtom = (atom, mounted) => !mounted.l.size && (!mounted.t.size || mounted.t.size === 1 && mounted.t.has(atom));
253 const delAtom = (atom) => {
254 const mounted = mountedMap.get(atom);
255 if (mounted && canUnmountAtom(atom, mounted)) {
256 unmountAtom(atom);
257 }
258 };
259 const recomputeDependents = (atom) => {
260 const mounted = mountedMap.get(atom);
261 mounted == null ? void 0 : mounted.t.forEach((dependent) => {
262 if (dependent !== atom) {
263 const prevAtomState = getAtomState(dependent);
264 const nextAtomState = readAtomState(dependent);
265 if (!prevAtomState || !isEqualAtomValue(prevAtomState, nextAtomState)) {
266 recomputeDependents(dependent);
267 }
268 }
269 });
270 };
271 const writeAtomState = (atom, ...args) => {
272 let isSync = true;
273 const getter = (a) => returnAtomValue(readAtomState(a));
274 const setter = (a, ...args2) => {
275 let r;
276 if (a === atom) {
277 if (!hasInitialValue(a)) {
278 throw new Error("atom not writable");
279 }
280 const prevAtomState = getAtomState(a);
281 const nextAtomState = setAtomValue(a, args2[0]);
282 if (!prevAtomState || !isEqualAtomValue(prevAtomState, nextAtomState)) {
283 recomputeDependents(a);
284 }
285 } else {
286 r = writeAtomState(a, ...args2);
287 }
288 if (!isSync) {
289 flushPending();
290 }
291 return r;
292 };
293 const result = atom.write(getter, setter, ...args);
294 isSync = false;
295 return result;
296 };
297 const writeAtom = (atom, ...args) => {
298 const result = writeAtomState(atom, ...args);
299 flushPending();
300 return result;
301 };
302 const mountAtom = (atom, initialDependent) => {
303 const mounted = {
304 t: new Set(initialDependent && [initialDependent]),
305 l: /* @__PURE__ */ new Set()
306 };
307 mountedMap.set(atom, mounted);
308 {
309 mountedAtoms.add(atom);
310 }
311 readAtomState(atom).d.forEach((_, a) => {
312 const aMounted = mountedMap.get(a);
313 if (aMounted) {
314 aMounted.t.add(atom);
315 } else {
316 if (a !== atom) {
317 mountAtom(a, atom);
318 }
319 }
320 });
321 readAtomState(atom);
322 if (isActuallyWritableAtom(atom) && atom.onMount) {
323 const onUnmount = atom.onMount((...args) => writeAtom(atom, ...args));
324 if (onUnmount) {
325 mounted.u = onUnmount;
326 }
327 }
328 return mounted;
329 };
330 const unmountAtom = (atom) => {
331 var _a;
332 const onUnmount = (_a = mountedMap.get(atom)) == null ? void 0 : _a.u;
333 if (onUnmount) {
334 onUnmount();
335 }
336 mountedMap.delete(atom);
337 {
338 mountedAtoms.delete(atom);
339 }
340 const atomState = getAtomState(atom);
341 if (atomState) {
342 if (hasPromiseAtomValue(atomState)) {
343 cancelPromise(atomState.v);
344 }
345 atomState.d.forEach((_, a) => {
346 if (a !== atom) {
347 const mounted = mountedMap.get(a);
348 if (mounted) {
349 mounted.t.delete(atom);
350 if (canUnmountAtom(a, mounted)) {
351 unmountAtom(a);
352 }
353 }
354 }
355 });
356 } else {
357 console.warn("[Bug] could not find atom state to unmount", atom);
358 }
359 };
360 const mountDependencies = (atom, atomState, prevDependencies) => {
361 const depSet = new Set(atomState.d.keys());
362 prevDependencies == null ? void 0 : prevDependencies.forEach((_, a) => {
363 if (depSet.has(a)) {
364 depSet.delete(a);
365 return;
366 }
367 const mounted = mountedMap.get(a);
368 if (mounted) {
369 mounted.t.delete(atom);
370 if (canUnmountAtom(a, mounted)) {
371 unmountAtom(a);
372 }
373 }
374 });
375 depSet.forEach((a) => {
376 const mounted = mountedMap.get(a);
377 if (mounted) {
378 mounted.t.add(atom);
379 } else if (mountedMap.has(atom)) {
380 mountAtom(a, atom);
381 }
382 });
383 };
384 const flushPending = () => {
385 while (pendingMap.size) {
386 const pending = Array.from(pendingMap);
387 pendingMap.clear();
388 pending.forEach(([atom, prevAtomState]) => {
389 const atomState = getAtomState(atom);
390 if (atomState) {
391 if (atomState.d !== (prevAtomState == null ? void 0 : prevAtomState.d)) {
392 mountDependencies(atom, atomState, prevAtomState == null ? void 0 : prevAtomState.d);
393 }
394 const mounted = mountedMap.get(atom);
395 if (mounted && !// TODO This seems pretty hacky. Hope to fix it.
396 // Maybe we could `mountDependencies` in `setAtomState`?
397 (prevAtomState && !hasPromiseAtomValue(prevAtomState) && (isEqualAtomValue(prevAtomState, atomState) || isEqualAtomError(prevAtomState, atomState)))) {
398 mounted.l.forEach((listener) => listener());
399 }
400 } else {
401 console.warn("[Bug] no atom state to flush");
402 }
403 });
404 }
405 {
406 stateListeners.forEach((l) => l());
407 }
408 };
409 const subscribeAtom = (atom, listener) => {
410 const mounted = addAtom(atom);
411 flushPending();
412 const listeners = mounted.l;
413 listeners.add(listener);
414 return () => {
415 listeners.delete(listener);
416 delAtom(atom);
417 };
418 };
419 {
420 return {
421 get: readAtom,
422 set: writeAtom,
423 sub: subscribeAtom,
424 // store dev methods (these are tentative and subject to change)
425 dev_subscribe_state: (l) => {
426 stateListeners.add(l);
427 return () => {
428 stateListeners.delete(l);
429 };
430 },
431 dev_get_mounted_atoms: () => mountedAtoms.values(),
432 dev_get_atom_state: (a) => atomStateMap.get(a),
433 dev_get_mounted: (a) => mountedMap.get(a),
434 dev_restore_atoms: (values) => {
435 for (const [atom, value] of values) {
436 if (hasInitialValue(atom)) {
437 setAtomValue(atom, value);
438 recomputeDependents(atom);
439 }
440 }
441 flushPending();
442 }
443 };
444 }
445 });
446 let defaultStore;
447 const getDefaultStore = exports('getDefaultStore', () => {
448 if (!defaultStore) {
449 defaultStore = createStore();
450 }
451 return defaultStore;
452 });
453
454 })
455 };
456}));