Skip to content

Commit 099f36a

Browse files
committed
Add exit actions
1 parent a1d2013 commit 099f36a

2 files changed

Lines changed: 36 additions & 16 deletions

File tree

src/index.test.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
1-
import { call, entry, on, start } from "./index";
1+
import { call, entry, exit, on, start } from "./index";
22

33
const fetch = jest.fn();
44
beforeEach(fetch.mockClear);
55

6+
const finishedLoading = jest.fn();
7+
beforeEach(finishedLoading.mockClear);
8+
69
describe("Machine with entry", () => {
710
function Loader() {
811
function* idle() {
912
yield on("FETCH", loading);
1013
}
1114
function* loading() {
1215
yield entry(fetchData);
16+
yield exit(finishedLoading);
1317
yield on("SUCCESS", success);
1418
yield on("FAILURE", failure);
1519
}
@@ -47,16 +51,21 @@ describe("Machine with entry", () => {
4751

4852
const transitionResult = loader.next("FETCH");
4953
expect(fetch).toHaveBeenCalledWith("https://example.org/");
50-
expect(transitionResult.actions).toEqual([{ type: "entry", f: fetchData }]);
54+
expect(transitionResult.actions).toEqual([
55+
{ type: "entry", f: fetchData },
56+
]);
5157
expect(loader.value).toEqual("loading");
5258
expect(loader.changeCount).toEqual(1);
59+
expect(finishedLoading).toHaveBeenCalledTimes(0);
5360

5461
await expect(loader.resolved).resolves.toEqual([42]);
5562
await expect(Promise.resolve(transitionResult)).resolves.toEqual([42]);
63+
expect(finishedLoading).toHaveBeenCalledTimes(1);
5664
expect(loader.changeCount).toEqual(2);
5765
expect(loader.value).toEqual("success");
58-
59-
loader.next("FETCH");
66+
67+
const transitionResult2 = loader.next("FETCH");
68+
expect(transitionResult2.actions).toEqual([]);
6069
expect(loader.changeCount).toEqual(2);
6170
expect(loader.value).toEqual("success");
6271

@@ -73,25 +82,26 @@ describe("Machine with entry", () => {
7382
const loader = start(Loader, [{ url: someURL }]);
7483
expect(loader.value).toEqual("idle");
7584

76-
const { actions } = loader.next("FETCH");
85+
const transitionResult = loader.next("FETCH");
7786
expect(fetch).toHaveBeenCalledTimes(1);
7887
expect(fetch).toHaveBeenLastCalledWith("https://example.org/");
79-
expect(actions).toEqual([{ type: "entry", f: fetchData }]);
88+
expect(transitionResult.actions).toEqual([{ type: "entry", f: fetchData }]);
8089
expect(loader.value).toEqual("loading");
8190
expect(loader.changeCount).toEqual(1);
8291

8392
await expect(loader.resolved).rejects.toEqual(new Error("Failed!"));
93+
await expect(Promise.resolve(transitionResult)).rejects.toEqual(new Error("Failed!"));
8494
expect(loader.changeCount).toEqual(2);
8595
expect(loader.value).toEqual("failure");
8696

8797
loader.next("FETCH");
8898
expect(fetch).toHaveBeenCalledTimes(1);
8999
expect(loader.changeCount).toEqual(2);
90-
100+
91101
loader.next("RETRY");
92102
expect(loader.value).toEqual("loading");
93103
expect(loader.changeCount).toEqual(3);
94-
104+
95105
expect(fetch).toHaveBeenCalledTimes(2);
96106
expect(fetch).toHaveBeenLastCalledWith("https://example.org/");
97107

src/index.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export interface On {
2323
target: Function;
2424
}
2525

26-
export type Yielded = EntryAction | On | Call<any>;
26+
export type Yielded = On | EntryAction | ExitAction | Call<any>;
2727

2828
export function call<Arguments extends Array<any>>(
2929
f: (...args: Arguments) => void,
@@ -51,9 +51,10 @@ export interface MachineInstance extends Iterator<string, void, string> {
5151
done: boolean;
5252
next(
5353
...args: [string]
54-
): IteratorResult<string, void> & PromiseLike<any> & {
55-
actions: Array<EntryAction | ExitAction>;
56-
};
54+
): IteratorResult<string, void> &
55+
PromiseLike<any> & {
56+
actions: Array<EntryAction | ExitAction>;
57+
};
5758
}
5859

5960
export function start<Arguments extends Array<any>>(
@@ -67,7 +68,8 @@ export function start<Arguments extends Array<any>>(
6768
let state = {
6869
changeCount: -1,
6970
current: "",
70-
actions: [] as Array<EntryAction | ExitAction>,
71+
entryActions: [] as Array<EntryAction>,
72+
exitActions: [] as Array<ExitAction>,
7173
resolved: null as Promise<Array<any>> | null,
7274
};
7375

@@ -81,8 +83,14 @@ export function start<Arguments extends Array<any>>(
8183
}
8284

8385
function transitionTo(stateGenerator: () => Generator<Yielded>) {
86+
state.exitActions.forEach((action) => {
87+
action.f();
88+
});
89+
8490
state.changeCount++;
8591
state.current = stateGenerator.name;
92+
state.entryActions.splice(0, Infinity);
93+
state.exitActions.splice(0, Infinity);
8694
state.resolved = null;
8795
eventsMap.clear();
8896

@@ -91,12 +99,14 @@ export function start<Arguments extends Array<any>>(
9199
const iterable = stateGenerator();
92100
for (const value of iterable) {
93101
if (value.type === "entry") {
94-
state.actions.push(value);
102+
state.entryActions.push(value);
95103
// const result = Promise.resolve(value);
96104
const result = new Promise((resolve) => {
97105
resolve(value.f());
98106
});
99107
results.push(result);
108+
} else if (value.type === "exit") {
109+
state.exitActions.push(value);
100110
} else if (value.type === "call") {
101111
const result = new Promise((resolve) =>
102112
resolve(value.f.apply(null, value.args))
@@ -134,10 +144,10 @@ export function start<Arguments extends Array<any>>(
134144
next(event: string) {
135145
receive(event, state.changeCount);
136146
const promise = state.resolved!;
137-
Promise.resolve
147+
Promise.resolve;
138148
return {
139149
value: state.current,
140-
actions: Array.from(state.actions),
150+
actions: Array.from(state.entryActions),
141151
then: promise.then.bind(promise),
142152
done: false,
143153
};

0 commit comments

Comments
 (0)