@dhmk/atom
Advanced tools
Comparing version 2.0.1-test.10 to 2.0.1-test.11
@@ -37,3 +37,4 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
}; | ||
import { atom, observe, act } from "./"; | ||
import { atom, observe, runEffects, batch } from "./"; | ||
var nextTick = function () { return new Promise(process.nextTick); }; | ||
describe("atom", function () { | ||
@@ -45,3 +46,3 @@ test("basic", function () { | ||
expect(b()).toEqual(2); | ||
act(function () { return a.set(2); }); | ||
a.set(2); | ||
expect(a()).toEqual(2); | ||
@@ -58,133 +59,202 @@ expect(b()).toEqual(3); | ||
expect(spy).toBeCalledTimes(1); | ||
act(function () { return a.set(3); }); // b = 1 | ||
a.set(3); // b = 1 | ||
c(); | ||
expect(spy).toBeCalledTimes(1); | ||
act(function () { return a.set(5); }); // b = 0 | ||
a.set(5); // b = 0 | ||
c(); | ||
act(function () { return a.set(6); }); // b = 0 | ||
a.set(6); // b = 0 | ||
c(); | ||
expect(spy).toBeCalledTimes(2); | ||
}); | ||
test("diamond", function () { | ||
var computeSpy = jest.fn(); | ||
var observeSpy = jest.fn(); | ||
var a = atom(1); | ||
var b = atom(function () { return a() + 1; }); | ||
var c = atom(function () { return a() * 10; }); | ||
var d = atom(function () { | ||
computeSpy(); | ||
return b() + c(); | ||
test("diamond", function () { return __awaiter(void 0, void 0, void 0, function () { | ||
var computeSpy, observeSpy, a, b, c, d; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
computeSpy = jest.fn(); | ||
observeSpy = jest.fn(); | ||
a = atom(1); | ||
b = atom(function () { return a() + 1; }); | ||
c = atom(function () { return a() * 10; }); | ||
d = atom(function () { | ||
computeSpy(); | ||
return b() + c(); | ||
}); | ||
observe(function () { | ||
d(); | ||
observeSpy(); | ||
}); | ||
expect(d()).toEqual(12); | ||
expect(computeSpy).toBeCalledTimes(1); | ||
expect(observeSpy).toBeCalledTimes(1); | ||
a.set(2); | ||
return [4 /*yield*/, nextTick()]; | ||
case 1: | ||
_a.sent(); | ||
expect(d()).toEqual(23); | ||
expect(computeSpy).toBeCalledTimes(2); | ||
expect(observeSpy).toBeCalledTimes(2); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
observe(function () { | ||
d(); | ||
observeSpy(); | ||
}); }); | ||
test("onBO/onBUO", function () { return __awaiter(void 0, void 0, void 0, function () { | ||
var onBOspy, onBUOspy, a, d, d2; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
onBOspy = jest.fn(); | ||
onBUOspy = jest.fn(); | ||
a = atom(1, { | ||
onBecomeObserved: onBOspy, | ||
onBecomeUnobserved: onBUOspy, | ||
}); | ||
expect(onBOspy).toBeCalledTimes(0); | ||
expect(onBUOspy).toBeCalledTimes(0); | ||
// irrelevant | ||
a.set(2); | ||
return [4 /*yield*/, nextTick()]; | ||
case 1: | ||
_a.sent(); | ||
expect(onBOspy).toBeCalledTimes(0); | ||
expect(onBUOspy).toBeCalledTimes(0); | ||
d = observe(a); | ||
expect(onBOspy).toBeCalledTimes(1); | ||
expect(onBUOspy).toBeCalledTimes(0); | ||
// irrelevant | ||
a.set(3); | ||
return [4 /*yield*/, nextTick()]; | ||
case 2: | ||
_a.sent(); | ||
expect(onBOspy).toBeCalledTimes(1); | ||
expect(onBUOspy).toBeCalledTimes(0); | ||
// BUO | ||
d(); | ||
expect(onBOspy).toBeCalledTimes(1); | ||
expect(onBUOspy).toBeCalledTimes(1); | ||
// irrelevant | ||
d(); | ||
expect(onBOspy).toBeCalledTimes(1); | ||
expect(onBUOspy).toBeCalledTimes(1); | ||
// irrelevant | ||
(function () { return a.set(4); }); | ||
return [4 /*yield*/, nextTick()]; | ||
case 3: | ||
_a.sent(); | ||
expect(onBOspy).toBeCalledTimes(1); | ||
expect(onBUOspy).toBeCalledTimes(1); | ||
d2 = observe(a); | ||
expect(onBOspy).toBeCalledTimes(2); | ||
expect(onBUOspy).toBeCalledTimes(1); | ||
// BUO | ||
d2(); | ||
expect(onBOspy).toBeCalledTimes(2); | ||
expect(onBUOspy).toBeCalledTimes(2); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
expect(d()).toEqual(12); | ||
expect(computeSpy).toBeCalledTimes(1); | ||
expect(observeSpy).toBeCalledTimes(1); | ||
act(function () { return a.set(2); }); | ||
expect(d()).toEqual(23); | ||
expect(computeSpy).toBeCalledTimes(2); | ||
expect(observeSpy).toBeCalledTimes(2); | ||
}); | ||
test("onBO/onBUO", function () { | ||
var onBOspy = jest.fn(); | ||
var onBUOspy = jest.fn(); | ||
var a = atom(1, { | ||
onBecomeObserved: onBOspy, | ||
onBecomeUnobserved: onBUOspy, | ||
}); | ||
expect(onBOspy).toBeCalledTimes(0); | ||
expect(onBUOspy).toBeCalledTimes(0); | ||
// irrelevant | ||
act(function () { return a.set(2); }); | ||
expect(onBOspy).toBeCalledTimes(0); | ||
expect(onBUOspy).toBeCalledTimes(0); | ||
// BO | ||
var d = observe(a); | ||
expect(onBOspy).toBeCalledTimes(1); | ||
expect(onBUOspy).toBeCalledTimes(0); | ||
// irrelevant | ||
act(function () { return a.set(3); }); | ||
expect(onBOspy).toBeCalledTimes(1); | ||
expect(onBUOspy).toBeCalledTimes(0); | ||
// BUO | ||
d(); | ||
expect(onBOspy).toBeCalledTimes(1); | ||
expect(onBUOspy).toBeCalledTimes(1); | ||
// irrelevant | ||
d(); | ||
expect(onBOspy).toBeCalledTimes(1); | ||
expect(onBUOspy).toBeCalledTimes(1); | ||
// irrelevant | ||
act(function () { return a.set(4); }); | ||
expect(onBOspy).toBeCalledTimes(1); | ||
expect(onBUOspy).toBeCalledTimes(1); | ||
// BO | ||
var d2 = observe(a); | ||
expect(onBOspy).toBeCalledTimes(2); | ||
expect(onBUOspy).toBeCalledTimes(1); | ||
// BUO | ||
d2(); | ||
expect(onBOspy).toBeCalledTimes(2); | ||
expect(onBUOspy).toBeCalledTimes(2); | ||
}); | ||
}); }); | ||
}); | ||
describe("observe", function () { | ||
test("basic", function () { | ||
var a = atom(1); | ||
var b = atom(2); | ||
var spy = jest.fn(); | ||
observe(function () { | ||
a() + b(); | ||
spy(); | ||
test("basic", function () { return __awaiter(void 0, void 0, void 0, function () { | ||
var a, b, spy; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
a = atom(1); | ||
b = atom(2); | ||
spy = jest.fn(); | ||
observe(function () { | ||
a() + b(); | ||
spy(); | ||
}); | ||
expect(spy).toBeCalledTimes(1); | ||
a.set(2); | ||
return [4 /*yield*/, nextTick()]; | ||
case 1: | ||
_a.sent(); | ||
b.set(3); | ||
return [4 /*yield*/, nextTick()]; | ||
case 2: | ||
_a.sent(); | ||
expect(spy).toBeCalledTimes(3); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
expect(spy).toBeCalledTimes(1); | ||
act(function () { return a.set(2); }); | ||
act(function () { return b.set(3); }); | ||
expect(spy).toBeCalledTimes(3); | ||
}); | ||
test("re-runs if atoms changed in-flight", function () { | ||
var a = atom(0); | ||
var spy = jest.fn(); | ||
observe(function () { | ||
if (a() === 1) | ||
a.set(2); | ||
spy(); | ||
}); }); | ||
test("re-runs if atoms changed in-flight", function () { return __awaiter(void 0, void 0, void 0, function () { | ||
var a, spy, spy2; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
a = atom(0); | ||
spy = jest.fn(); | ||
observe(function () { | ||
if (a() === 1) | ||
a.set(2); | ||
spy(); | ||
}); | ||
expect(spy).toBeCalledTimes(1); | ||
a.set(1); | ||
return [4 /*yield*/, nextTick()]; | ||
case 1: | ||
_a.sent(); | ||
expect(spy).toBeCalledTimes(3); | ||
spy2 = jest.fn(); | ||
observe(function () { | ||
if (a() === 3) | ||
a.set(4); | ||
// if we read changed atom again, effect won't be recalculated | ||
a(); | ||
spy2(); | ||
}); | ||
expect(spy2).toBeCalledTimes(1); | ||
a.set(3); | ||
return [4 /*yield*/, nextTick()]; | ||
case 2: | ||
_a.sent(); | ||
expect(spy2).toBeCalledTimes(2); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
expect(spy).toBeCalledTimes(1); | ||
act(function () { return a.set(1); }); | ||
expect(spy).toBeCalledTimes(3); | ||
var spy2 = jest.fn(); | ||
observe(function () { | ||
if (a() === 3) | ||
a.set(4); | ||
// if we read changed atom again, effect won't be recalculated | ||
a(); | ||
spy2(); | ||
}); }); | ||
test("dispose", function () { return __awaiter(void 0, void 0, void 0, function () { | ||
var a, spy, d; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
a = atom(1); | ||
spy = jest.fn(); | ||
observe(function (d) { | ||
a(); | ||
d(); | ||
spy(); | ||
}); | ||
a.set(2); | ||
return [4 /*yield*/, nextTick()]; | ||
case 1: | ||
_a.sent(); | ||
a.set(3); | ||
return [4 /*yield*/, nextTick()]; | ||
case 2: | ||
_a.sent(); | ||
expect(spy).toBeCalledTimes(1); | ||
d = observe(function () { | ||
a(); | ||
spy(); | ||
}); | ||
d(); | ||
a.set(4); | ||
return [4 /*yield*/, nextTick()]; | ||
case 3: | ||
_a.sent(); | ||
a.set(5); | ||
return [4 /*yield*/, nextTick()]; | ||
case 4: | ||
_a.sent(); | ||
expect(spy).toBeCalledTimes(2); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
expect(spy2).toBeCalledTimes(1); | ||
act(function () { return a.set(3); }); | ||
expect(spy2).toBeCalledTimes(2); | ||
}); | ||
test("dispose", function () { | ||
var a = atom(1); | ||
var spy = jest.fn(); | ||
observe(function (d) { | ||
a(); | ||
d(); | ||
spy(); | ||
}); | ||
act(function () { return a.set(2); }); | ||
act(function () { return a.set(3); }); | ||
expect(spy).toBeCalledTimes(1); | ||
var d = observe(function () { | ||
a(); | ||
spy(); | ||
}); | ||
d(); | ||
act(function () { return a.set(4); }); | ||
act(function () { return a.set(5); }); | ||
expect(spy).toBeCalledTimes(2); | ||
}); | ||
}); }); | ||
test("custom scheduler", function () { return __awaiter(void 0, void 0, void 0, function () { | ||
@@ -204,4 +274,4 @@ var a, spy; | ||
expect(spy).toBeCalledTimes(0); | ||
act(function () { return a.set(2); }); | ||
return [4 /*yield*/, null]; | ||
a.set(2); | ||
return [4 /*yield*/, nextTick]; | ||
case 1: | ||
@@ -222,3 +292,3 @@ _a.sent(); | ||
expect(spy).toBeCalledTimes(1); | ||
act(function () { | ||
batch(function () { | ||
d.invalidate( /*false*/); | ||
@@ -229,19 +299,28 @@ expect(spy).toBeCalledTimes(1); | ||
}); | ||
runEffects(); | ||
expect(spy).toBeCalledTimes(2); | ||
}); | ||
}); | ||
test("action", function () { | ||
var a = atom(1); | ||
var b = atom(2); | ||
var spy = jest.fn(); | ||
observe(function () { | ||
a() + b(); | ||
spy(); | ||
test("action", function () { return __awaiter(void 0, void 0, void 0, function () { | ||
var a, b, spy; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
a = atom(1); | ||
b = atom(2); | ||
spy = jest.fn(); | ||
observe(function () { | ||
a() + b(); | ||
spy(); | ||
}); | ||
expect(spy).toBeCalledTimes(1); | ||
a.set(2); | ||
b.set(3); | ||
return [4 /*yield*/, nextTick()]; | ||
case 1: | ||
_a.sent(); | ||
expect(spy).toBeCalledTimes(2); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
expect(spy).toBeCalledTimes(1); | ||
act(function () { | ||
a.set(2); | ||
b.set(3); | ||
}); | ||
expect(spy).toBeCalledTimes(2); | ||
}); | ||
}); }); |
@@ -25,3 +25,3 @@ var __assign = (this && this.__assign) || function () { | ||
this.state = AtomState.Stale; | ||
this.m = new Id(); | ||
this.m = EID; | ||
this.ti = 0; | ||
@@ -28,0 +28,0 @@ this.readFlag = false; |
@@ -21,3 +21,3 @@ var __assign = (this && this.__assign) || function () { | ||
this.vid = EID; | ||
this.m = new Id(); | ||
this.m = EID; | ||
this.ti = 0; | ||
@@ -28,4 +28,2 @@ this.readFlag = false; | ||
ValueAtom.prototype.set = function (x) { | ||
if (runtime.requireAction && !runtime.counter) | ||
throw new Error("Attempted to set atom value outside action."); | ||
if (this.options.equals(x, this.value)) | ||
@@ -36,2 +34,3 @@ return; | ||
invalidateSubs(this, true); | ||
runtime.scheduleRun(); | ||
}; | ||
@@ -38,0 +37,0 @@ ValueAtom.prototype.actualize = function () { }; |
@@ -28,4 +28,3 @@ import { ValueAtom } from "./atoms/value"; | ||
declare function atom<T>(value: T, opts?: AtomOptions_<T>): WritableAtom<T> & Getter<T>; | ||
declare const act: <T>(fn: () => T) => T; | ||
declare const untracked: <T>(fn: () => T) => T; | ||
export { ValueAtom, DerivedAtom, atom, act, untracked, observe, observable, observableObject, observableArray, as, runtime, }; | ||
declare const untracked: <T>(fn: () => T) => T, queueEffect: (x: () => void) => void, runEffects: () => void; | ||
export { ValueAtom, DerivedAtom, atom, observe, observable, observableObject, observableArray, as, untracked, untracked as batch, queueEffect, runEffects, runtime, }; |
@@ -45,5 +45,4 @@ import { ValueAtom } from "./atoms/value"; | ||
} | ||
var act = runtime.act; | ||
var untracked = act; | ||
export { ValueAtom, DerivedAtom, atom, act, untracked, observe, observable, observableObject, observableArray, as, runtime, // debug | ||
var untracked = runtime.untracked, queueEffect = runtime.queueEffect, runEffects = runtime.runEffects; | ||
export { ValueAtom, DerivedAtom, atom, observe, observable, observableObject, observableArray, as, untracked, untracked as batch, queueEffect, runEffects, runtime, // debug | ||
}; |
@@ -5,8 +5,10 @@ type Effect = () => void; | ||
counter: number; | ||
requireAction: boolean; | ||
effects: Set<Effect>; | ||
isScheduled: boolean; | ||
addEffect(x: Effect): void; | ||
scheduleRun(): void; | ||
queueEffect(x: Effect): void; | ||
runEffects(): void; | ||
act<T>(fn: () => T): T; | ||
untracked<T>(fn: () => T): T; | ||
}; | ||
export {}; |
import { thrower } from "./shared"; | ||
export var runtime = { | ||
//private | ||
currentAtom: undefined, | ||
counter: 0, | ||
requireAction: true, | ||
effects: new Set(), | ||
isScheduled: false, | ||
addEffect: function (x) { | ||
runtime.effects.add(x); | ||
}, | ||
scheduleRun: function () { | ||
if (!runtime.isScheduled) { | ||
runtime.isScheduled = true; | ||
Promise.resolve().then(function () { | ||
runtime.isScheduled = false; | ||
runtime.runEffects(); | ||
}); | ||
} | ||
}, | ||
// public | ||
queueEffect: function (x) { | ||
runtime.addEffect(x); | ||
runtime.scheduleRun(); | ||
}, | ||
runEffects: function () { | ||
@@ -25,3 +40,3 @@ if (runtime.counter > 0) | ||
}, | ||
act: function (fn) { | ||
untracked: function (fn) { | ||
var prevAtom = runtime.currentAtom; | ||
@@ -36,5 +51,4 @@ runtime.currentAtom = undefined; | ||
runtime.currentAtom = prevAtom; | ||
runtime.runEffects(); | ||
} | ||
}, | ||
}; |
import { AtomState } from "./types"; | ||
export declare const removeAtom: (a: any, self: unknown) => void; | ||
export declare function removeAtom(a: any, self: any): void; | ||
export declare function trackAtom(a: any): void; | ||
export declare function thrower(e: unknown): () => never; | ||
export declare function invalidateSubs(atom: any, isValueAtom: any, newState?: AtomState): void; |
import { runtime } from "./runtime"; | ||
import { AtomState } from "./types"; | ||
export var removeAtom = function (a, self) { | ||
export function removeAtom(a, self) { | ||
a.subs.delete(self); | ||
if (!a.subs.size) | ||
a.dispose(); | ||
}; | ||
} | ||
export function trackAtom(a) { | ||
@@ -9,0 +9,0 @@ var ca = runtime.currentAtom; |
@@ -5,9 +5,2 @@ export declare class Id { | ||
export declare const EID: Id; | ||
export interface Dependency { | ||
actualize(): void; | ||
dispose(): void; | ||
observers: Map<unknown, Id>; | ||
versionId: Id; | ||
runId: Id; | ||
} | ||
export declare enum AtomState { | ||
@@ -21,5 +14,2 @@ Actual = 0, | ||
} | ||
export type Atom = { | ||
invalidate(state: AtomState, isValueAtom: boolean): void; | ||
}; | ||
export type _AtomOptions<T> = { | ||
@@ -26,0 +16,0 @@ equals(next: T, prev: T): boolean; |
@@ -40,2 +40,3 @@ "use strict"; | ||
var _1 = require("./"); | ||
var nextTick = function () { return new Promise(process.nextTick); }; | ||
describe("atom", function () { | ||
@@ -47,3 +48,3 @@ test("basic", function () { | ||
expect(b()).toEqual(2); | ||
(0, _1.act)(function () { return a.set(2); }); | ||
a.set(2); | ||
expect(a()).toEqual(2); | ||
@@ -60,133 +61,202 @@ expect(b()).toEqual(3); | ||
expect(spy).toBeCalledTimes(1); | ||
(0, _1.act)(function () { return a.set(3); }); // b = 1 | ||
a.set(3); // b = 1 | ||
c(); | ||
expect(spy).toBeCalledTimes(1); | ||
(0, _1.act)(function () { return a.set(5); }); // b = 0 | ||
a.set(5); // b = 0 | ||
c(); | ||
(0, _1.act)(function () { return a.set(6); }); // b = 0 | ||
a.set(6); // b = 0 | ||
c(); | ||
expect(spy).toBeCalledTimes(2); | ||
}); | ||
test("diamond", function () { | ||
var computeSpy = jest.fn(); | ||
var observeSpy = jest.fn(); | ||
var a = (0, _1.atom)(1); | ||
var b = (0, _1.atom)(function () { return a() + 1; }); | ||
var c = (0, _1.atom)(function () { return a() * 10; }); | ||
var d = (0, _1.atom)(function () { | ||
computeSpy(); | ||
return b() + c(); | ||
test("diamond", function () { return __awaiter(void 0, void 0, void 0, function () { | ||
var computeSpy, observeSpy, a, b, c, d; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
computeSpy = jest.fn(); | ||
observeSpy = jest.fn(); | ||
a = (0, _1.atom)(1); | ||
b = (0, _1.atom)(function () { return a() + 1; }); | ||
c = (0, _1.atom)(function () { return a() * 10; }); | ||
d = (0, _1.atom)(function () { | ||
computeSpy(); | ||
return b() + c(); | ||
}); | ||
(0, _1.observe)(function () { | ||
d(); | ||
observeSpy(); | ||
}); | ||
expect(d()).toEqual(12); | ||
expect(computeSpy).toBeCalledTimes(1); | ||
expect(observeSpy).toBeCalledTimes(1); | ||
a.set(2); | ||
return [4 /*yield*/, nextTick()]; | ||
case 1: | ||
_a.sent(); | ||
expect(d()).toEqual(23); | ||
expect(computeSpy).toBeCalledTimes(2); | ||
expect(observeSpy).toBeCalledTimes(2); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
(0, _1.observe)(function () { | ||
d(); | ||
observeSpy(); | ||
}); }); | ||
test("onBO/onBUO", function () { return __awaiter(void 0, void 0, void 0, function () { | ||
var onBOspy, onBUOspy, a, d, d2; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
onBOspy = jest.fn(); | ||
onBUOspy = jest.fn(); | ||
a = (0, _1.atom)(1, { | ||
onBecomeObserved: onBOspy, | ||
onBecomeUnobserved: onBUOspy, | ||
}); | ||
expect(onBOspy).toBeCalledTimes(0); | ||
expect(onBUOspy).toBeCalledTimes(0); | ||
// irrelevant | ||
a.set(2); | ||
return [4 /*yield*/, nextTick()]; | ||
case 1: | ||
_a.sent(); | ||
expect(onBOspy).toBeCalledTimes(0); | ||
expect(onBUOspy).toBeCalledTimes(0); | ||
d = (0, _1.observe)(a); | ||
expect(onBOspy).toBeCalledTimes(1); | ||
expect(onBUOspy).toBeCalledTimes(0); | ||
// irrelevant | ||
a.set(3); | ||
return [4 /*yield*/, nextTick()]; | ||
case 2: | ||
_a.sent(); | ||
expect(onBOspy).toBeCalledTimes(1); | ||
expect(onBUOspy).toBeCalledTimes(0); | ||
// BUO | ||
d(); | ||
expect(onBOspy).toBeCalledTimes(1); | ||
expect(onBUOspy).toBeCalledTimes(1); | ||
// irrelevant | ||
d(); | ||
expect(onBOspy).toBeCalledTimes(1); | ||
expect(onBUOspy).toBeCalledTimes(1); | ||
// irrelevant | ||
(function () { return a.set(4); }); | ||
return [4 /*yield*/, nextTick()]; | ||
case 3: | ||
_a.sent(); | ||
expect(onBOspy).toBeCalledTimes(1); | ||
expect(onBUOspy).toBeCalledTimes(1); | ||
d2 = (0, _1.observe)(a); | ||
expect(onBOspy).toBeCalledTimes(2); | ||
expect(onBUOspy).toBeCalledTimes(1); | ||
// BUO | ||
d2(); | ||
expect(onBOspy).toBeCalledTimes(2); | ||
expect(onBUOspy).toBeCalledTimes(2); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
expect(d()).toEqual(12); | ||
expect(computeSpy).toBeCalledTimes(1); | ||
expect(observeSpy).toBeCalledTimes(1); | ||
(0, _1.act)(function () { return a.set(2); }); | ||
expect(d()).toEqual(23); | ||
expect(computeSpy).toBeCalledTimes(2); | ||
expect(observeSpy).toBeCalledTimes(2); | ||
}); | ||
test("onBO/onBUO", function () { | ||
var onBOspy = jest.fn(); | ||
var onBUOspy = jest.fn(); | ||
var a = (0, _1.atom)(1, { | ||
onBecomeObserved: onBOspy, | ||
onBecomeUnobserved: onBUOspy, | ||
}); | ||
expect(onBOspy).toBeCalledTimes(0); | ||
expect(onBUOspy).toBeCalledTimes(0); | ||
// irrelevant | ||
(0, _1.act)(function () { return a.set(2); }); | ||
expect(onBOspy).toBeCalledTimes(0); | ||
expect(onBUOspy).toBeCalledTimes(0); | ||
// BO | ||
var d = (0, _1.observe)(a); | ||
expect(onBOspy).toBeCalledTimes(1); | ||
expect(onBUOspy).toBeCalledTimes(0); | ||
// irrelevant | ||
(0, _1.act)(function () { return a.set(3); }); | ||
expect(onBOspy).toBeCalledTimes(1); | ||
expect(onBUOspy).toBeCalledTimes(0); | ||
// BUO | ||
d(); | ||
expect(onBOspy).toBeCalledTimes(1); | ||
expect(onBUOspy).toBeCalledTimes(1); | ||
// irrelevant | ||
d(); | ||
expect(onBOspy).toBeCalledTimes(1); | ||
expect(onBUOspy).toBeCalledTimes(1); | ||
// irrelevant | ||
(0, _1.act)(function () { return a.set(4); }); | ||
expect(onBOspy).toBeCalledTimes(1); | ||
expect(onBUOspy).toBeCalledTimes(1); | ||
// BO | ||
var d2 = (0, _1.observe)(a); | ||
expect(onBOspy).toBeCalledTimes(2); | ||
expect(onBUOspy).toBeCalledTimes(1); | ||
// BUO | ||
d2(); | ||
expect(onBOspy).toBeCalledTimes(2); | ||
expect(onBUOspy).toBeCalledTimes(2); | ||
}); | ||
}); }); | ||
}); | ||
describe("observe", function () { | ||
test("basic", function () { | ||
var a = (0, _1.atom)(1); | ||
var b = (0, _1.atom)(2); | ||
var spy = jest.fn(); | ||
(0, _1.observe)(function () { | ||
a() + b(); | ||
spy(); | ||
test("basic", function () { return __awaiter(void 0, void 0, void 0, function () { | ||
var a, b, spy; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
a = (0, _1.atom)(1); | ||
b = (0, _1.atom)(2); | ||
spy = jest.fn(); | ||
(0, _1.observe)(function () { | ||
a() + b(); | ||
spy(); | ||
}); | ||
expect(spy).toBeCalledTimes(1); | ||
a.set(2); | ||
return [4 /*yield*/, nextTick()]; | ||
case 1: | ||
_a.sent(); | ||
b.set(3); | ||
return [4 /*yield*/, nextTick()]; | ||
case 2: | ||
_a.sent(); | ||
expect(spy).toBeCalledTimes(3); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
expect(spy).toBeCalledTimes(1); | ||
(0, _1.act)(function () { return a.set(2); }); | ||
(0, _1.act)(function () { return b.set(3); }); | ||
expect(spy).toBeCalledTimes(3); | ||
}); | ||
test("re-runs if atoms changed in-flight", function () { | ||
var a = (0, _1.atom)(0); | ||
var spy = jest.fn(); | ||
(0, _1.observe)(function () { | ||
if (a() === 1) | ||
a.set(2); | ||
spy(); | ||
}); }); | ||
test("re-runs if atoms changed in-flight", function () { return __awaiter(void 0, void 0, void 0, function () { | ||
var a, spy, spy2; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
a = (0, _1.atom)(0); | ||
spy = jest.fn(); | ||
(0, _1.observe)(function () { | ||
if (a() === 1) | ||
a.set(2); | ||
spy(); | ||
}); | ||
expect(spy).toBeCalledTimes(1); | ||
a.set(1); | ||
return [4 /*yield*/, nextTick()]; | ||
case 1: | ||
_a.sent(); | ||
expect(spy).toBeCalledTimes(3); | ||
spy2 = jest.fn(); | ||
(0, _1.observe)(function () { | ||
if (a() === 3) | ||
a.set(4); | ||
// if we read changed atom again, effect won't be recalculated | ||
a(); | ||
spy2(); | ||
}); | ||
expect(spy2).toBeCalledTimes(1); | ||
a.set(3); | ||
return [4 /*yield*/, nextTick()]; | ||
case 2: | ||
_a.sent(); | ||
expect(spy2).toBeCalledTimes(2); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
expect(spy).toBeCalledTimes(1); | ||
(0, _1.act)(function () { return a.set(1); }); | ||
expect(spy).toBeCalledTimes(3); | ||
var spy2 = jest.fn(); | ||
(0, _1.observe)(function () { | ||
if (a() === 3) | ||
a.set(4); | ||
// if we read changed atom again, effect won't be recalculated | ||
a(); | ||
spy2(); | ||
}); }); | ||
test("dispose", function () { return __awaiter(void 0, void 0, void 0, function () { | ||
var a, spy, d; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
a = (0, _1.atom)(1); | ||
spy = jest.fn(); | ||
(0, _1.observe)(function (d) { | ||
a(); | ||
d(); | ||
spy(); | ||
}); | ||
a.set(2); | ||
return [4 /*yield*/, nextTick()]; | ||
case 1: | ||
_a.sent(); | ||
a.set(3); | ||
return [4 /*yield*/, nextTick()]; | ||
case 2: | ||
_a.sent(); | ||
expect(spy).toBeCalledTimes(1); | ||
d = (0, _1.observe)(function () { | ||
a(); | ||
spy(); | ||
}); | ||
d(); | ||
a.set(4); | ||
return [4 /*yield*/, nextTick()]; | ||
case 3: | ||
_a.sent(); | ||
a.set(5); | ||
return [4 /*yield*/, nextTick()]; | ||
case 4: | ||
_a.sent(); | ||
expect(spy).toBeCalledTimes(2); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
expect(spy2).toBeCalledTimes(1); | ||
(0, _1.act)(function () { return a.set(3); }); | ||
expect(spy2).toBeCalledTimes(2); | ||
}); | ||
test("dispose", function () { | ||
var a = (0, _1.atom)(1); | ||
var spy = jest.fn(); | ||
(0, _1.observe)(function (d) { | ||
a(); | ||
d(); | ||
spy(); | ||
}); | ||
(0, _1.act)(function () { return a.set(2); }); | ||
(0, _1.act)(function () { return a.set(3); }); | ||
expect(spy).toBeCalledTimes(1); | ||
var d = (0, _1.observe)(function () { | ||
a(); | ||
spy(); | ||
}); | ||
d(); | ||
(0, _1.act)(function () { return a.set(4); }); | ||
(0, _1.act)(function () { return a.set(5); }); | ||
expect(spy).toBeCalledTimes(2); | ||
}); | ||
}); }); | ||
test("custom scheduler", function () { return __awaiter(void 0, void 0, void 0, function () { | ||
@@ -206,4 +276,4 @@ var a, spy; | ||
expect(spy).toBeCalledTimes(0); | ||
(0, _1.act)(function () { return a.set(2); }); | ||
return [4 /*yield*/, null]; | ||
a.set(2); | ||
return [4 /*yield*/, nextTick]; | ||
case 1: | ||
@@ -224,3 +294,3 @@ _a.sent(); | ||
expect(spy).toBeCalledTimes(1); | ||
(0, _1.act)(function () { | ||
(0, _1.batch)(function () { | ||
d.invalidate( /*false*/); | ||
@@ -231,19 +301,28 @@ expect(spy).toBeCalledTimes(1); | ||
}); | ||
(0, _1.runEffects)(); | ||
expect(spy).toBeCalledTimes(2); | ||
}); | ||
}); | ||
test("action", function () { | ||
var a = (0, _1.atom)(1); | ||
var b = (0, _1.atom)(2); | ||
var spy = jest.fn(); | ||
(0, _1.observe)(function () { | ||
a() + b(); | ||
spy(); | ||
test("action", function () { return __awaiter(void 0, void 0, void 0, function () { | ||
var a, b, spy; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
a = (0, _1.atom)(1); | ||
b = (0, _1.atom)(2); | ||
spy = jest.fn(); | ||
(0, _1.observe)(function () { | ||
a() + b(); | ||
spy(); | ||
}); | ||
expect(spy).toBeCalledTimes(1); | ||
a.set(2); | ||
b.set(3); | ||
return [4 /*yield*/, nextTick()]; | ||
case 1: | ||
_a.sent(); | ||
expect(spy).toBeCalledTimes(2); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
expect(spy).toBeCalledTimes(1); | ||
(0, _1.act)(function () { | ||
a.set(2); | ||
b.set(3); | ||
}); | ||
expect(spy).toBeCalledTimes(2); | ||
}); | ||
}); }); |
@@ -28,3 +28,3 @@ "use strict"; | ||
this.state = types_1.AtomState.Stale; | ||
this.m = new types_1.Id(); | ||
this.m = types_1.EID; | ||
this.ti = 0; | ||
@@ -31,0 +31,0 @@ this.readFlag = false; |
@@ -24,3 +24,3 @@ "use strict"; | ||
this.vid = types_1.EID; | ||
this.m = new types_1.Id(); | ||
this.m = types_1.EID; | ||
this.ti = 0; | ||
@@ -31,4 +31,2 @@ this.readFlag = false; | ||
ValueAtom.prototype.set = function (x) { | ||
if (runtime_1.runtime.requireAction && !runtime_1.runtime.counter) | ||
throw new Error("Attempted to set atom value outside action."); | ||
if (this.options.equals(x, this.value)) | ||
@@ -39,2 +37,3 @@ return; | ||
(0, shared_1.invalidateSubs)(this, true); | ||
runtime_1.runtime.scheduleRun(); | ||
}; | ||
@@ -41,0 +40,0 @@ ValueAtom.prototype.actualize = function () { }; |
@@ -28,4 +28,3 @@ import { ValueAtom } from "./atoms/value"; | ||
declare function atom<T>(value: T, opts?: AtomOptions_<T>): WritableAtom<T> & Getter<T>; | ||
declare const act: <T>(fn: () => T) => T; | ||
declare const untracked: <T>(fn: () => T) => T; | ||
export { ValueAtom, DerivedAtom, atom, act, untracked, observe, observable, observableObject, observableArray, as, runtime, }; | ||
declare const untracked: <T>(fn: () => T) => T, queueEffect: (x: () => void) => void, runEffects: () => void; | ||
export { ValueAtom, DerivedAtom, atom, observe, observable, observableObject, observableArray, as, untracked, untracked as batch, queueEffect, runEffects, runtime, }; |
@@ -29,3 +29,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.runtime = exports.as = exports.observableArray = exports.observableObject = exports.observable = exports.observe = exports.untracked = exports.act = exports.atom = exports.DerivedAtom = exports.ValueAtom = void 0; | ||
exports.runtime = exports.runEffects = exports.queueEffect = exports.batch = exports.untracked = exports.as = exports.observableArray = exports.observableObject = exports.observable = exports.observe = exports.atom = exports.DerivedAtom = exports.ValueAtom = void 0; | ||
var value_1 = require("./atoms/value"); | ||
@@ -84,5 +84,6 @@ Object.defineProperty(exports, "ValueAtom", { enumerable: true, get: function () { return value_1.ValueAtom; } }); | ||
exports.atom = atom; | ||
var act = runtime_1.runtime.act; | ||
exports.act = act; | ||
var untracked = act; | ||
var untracked = runtime_1.runtime.untracked, queueEffect = runtime_1.runtime.queueEffect, runEffects = runtime_1.runtime.runEffects; | ||
exports.untracked = untracked; | ||
exports.batch = untracked; | ||
exports.queueEffect = queueEffect; | ||
exports.runEffects = runEffects; |
@@ -5,8 +5,10 @@ type Effect = () => void; | ||
counter: number; | ||
requireAction: boolean; | ||
effects: Set<Effect>; | ||
isScheduled: boolean; | ||
addEffect(x: Effect): void; | ||
scheduleRun(): void; | ||
queueEffect(x: Effect): void; | ||
runEffects(): void; | ||
act<T>(fn: () => T): T; | ||
untracked<T>(fn: () => T): T; | ||
}; | ||
export {}; |
@@ -6,9 +6,24 @@ "use strict"; | ||
exports.runtime = { | ||
//private | ||
currentAtom: undefined, | ||
counter: 0, | ||
requireAction: true, | ||
effects: new Set(), | ||
isScheduled: false, | ||
addEffect: function (x) { | ||
exports.runtime.effects.add(x); | ||
}, | ||
scheduleRun: function () { | ||
if (!exports.runtime.isScheduled) { | ||
exports.runtime.isScheduled = true; | ||
Promise.resolve().then(function () { | ||
exports.runtime.isScheduled = false; | ||
exports.runtime.runEffects(); | ||
}); | ||
} | ||
}, | ||
// public | ||
queueEffect: function (x) { | ||
exports.runtime.addEffect(x); | ||
exports.runtime.scheduleRun(); | ||
}, | ||
runEffects: function () { | ||
@@ -29,3 +44,3 @@ if (exports.runtime.counter > 0) | ||
}, | ||
act: function (fn) { | ||
untracked: function (fn) { | ||
var prevAtom = exports.runtime.currentAtom; | ||
@@ -40,5 +55,4 @@ exports.runtime.currentAtom = undefined; | ||
exports.runtime.currentAtom = prevAtom; | ||
exports.runtime.runEffects(); | ||
} | ||
}, | ||
}; |
import { AtomState } from "./types"; | ||
export declare const removeAtom: (a: any, self: unknown) => void; | ||
export declare function removeAtom(a: any, self: any): void; | ||
export declare function trackAtom(a: any): void; | ||
export declare function thrower(e: unknown): () => never; | ||
export declare function invalidateSubs(atom: any, isValueAtom: any, newState?: AtomState): void; |
@@ -6,7 +6,7 @@ "use strict"; | ||
var types_1 = require("./types"); | ||
var removeAtom = function (a, self) { | ||
function removeAtom(a, self) { | ||
a.subs.delete(self); | ||
if (!a.subs.size) | ||
a.dispose(); | ||
}; | ||
} | ||
exports.removeAtom = removeAtom; | ||
@@ -13,0 +13,0 @@ function trackAtom(a) { |
@@ -5,9 +5,2 @@ export declare class Id { | ||
export declare const EID: Id; | ||
export interface Dependency { | ||
actualize(): void; | ||
dispose(): void; | ||
observers: Map<unknown, Id>; | ||
versionId: Id; | ||
runId: Id; | ||
} | ||
export declare enum AtomState { | ||
@@ -21,5 +14,2 @@ Actual = 0, | ||
} | ||
export type Atom = { | ||
invalidate(state: AtomState, isValueAtom: boolean): void; | ||
}; | ||
export type _AtomOptions<T> = { | ||
@@ -26,0 +16,0 @@ equals(next: T, prev: T): boolean; |
{ | ||
"name": "@dhmk/atom", | ||
"version": "2.0.1-test.10", | ||
"version": "2.0.1-test.11", | ||
"description": "Lightweight mobx-like observable values, computed values and side-effects", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
76135
1981