Skip to content

Commit bf125bd

Browse files
committed
Add accumulations
1 parent ad06079 commit bf125bd

File tree

2 files changed

+92
-4
lines changed

2 files changed

+92
-4
lines changed

src/index.test.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
listenTo,
1313
send,
1414
start,
15+
accumulate,
1516
} from "./index";
1617

1718
test("node version " + process.version, () => {});
@@ -615,6 +616,54 @@ describe("Button click", () => {
615616
});
616617
});
617618

619+
describe("accumulate", () => {
620+
const messagesKey = Symbol("messages");
621+
622+
function* Machine(eventTarget: EventTarget) {
623+
// yield on(new Map([["type", "error"], ["readyState", EventSource.CLOSED]]), Closed);
624+
yield on("error", Closed);
625+
626+
function* Open() {
627+
yield listenTo(eventTarget, "message");
628+
yield accumulate("message", messagesKey);
629+
}
630+
function* Closed() {}
631+
632+
return function* Connecting() {
633+
yield listenTo(eventTarget, "open");
634+
yield on("open", Open);
635+
}
636+
}
637+
638+
it("works", () => {
639+
// const eventTarget = new AbortSignal();
640+
const eventTarget = (new AbortController()).signal;
641+
const machine = start(Machine.bind(null, eventTarget));
642+
643+
expect(machine.current).toEqual("Connecting");
644+
645+
eventTarget.dispatchEvent(new Event("open"));
646+
expect(machine.current).toEqual("Open");
647+
expect(machine.accumulations).toEqual(new Map());
648+
649+
const event1 = new Event("message");
650+
const event2 = new Event("message");
651+
const event3 = new Event("message");
652+
653+
eventTarget.dispatchEvent(event1);
654+
expect(machine.current).toEqual("Open");
655+
expect(machine.accumulations).toEqual(new Map([[messagesKey, [event1]]]));
656+
657+
eventTarget.dispatchEvent(event2);
658+
expect(machine.current).toEqual("Open");
659+
expect(machine.accumulations).toEqual(new Map([[messagesKey, [event1, event2]]]));
660+
661+
eventTarget.dispatchEvent(event3);
662+
expect(machine.current).toEqual("Open");
663+
expect(machine.accumulations).toEqual(new Map([[messagesKey, [event1, event2, event3]]]));
664+
})
665+
});
666+
618667
/*describe("Counter", () => {
619668
function* Counter() {
620669
function* initial() {

src/index.ts

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,13 @@ export interface Send<Method extends string | symbol, Arguments extends any[]> {
5454
args: Arguments;
5555
}
5656

57-
export type Yielded = On | Always | Cond | EntryAction | ExitAction | ListenTo | Call<any>;
57+
export interface Accumulate {
58+
type: "accumulate";
59+
eventName: string | symbol;
60+
resultKey: symbol;
61+
}
62+
63+
export type Yielded = On | Always | Cond | EntryAction | ExitAction | ListenTo | Accumulate | Call<any>;
5864

5965
export function on<Event extends string | symbol>(event: Event, target: Target): On {
6066
return { type: "on", on: event, target };
@@ -99,10 +105,15 @@ export function compound(...targets: Array<StateDefinition>): Compound {
99105
return { type: "compound", targets };
100106
}
101107

108+
export function accumulate(eventName: string | symbol, resultKey: symbol): Accumulate {
109+
return { type: "accumulate", eventName, resultKey };
110+
}
111+
102112
export interface MachineInstance extends Iterator<null | string | Record<string, string>, void, string | symbol> {
103113
changeCount: number;
104114
current: null | string | Record<string, string>;
105115
results: null | Promise<unknown>;
116+
accumulations: Map<symbol | string, Array<symbol | string | Event>>;
106117
done: boolean;
107118
next(arg: string | symbol): IteratorResult<null | string | Record<string, string>> &
108119
PromiseLike<any> & {
@@ -120,6 +131,7 @@ class Handlers {
120131
private actionResults = new Map<string | symbol, unknown>();
121132
private promise: null | Promise<Array<unknown>> = null;
122133
public readonly eventsToListenTo = new Array<[string, EventTarget]>();
134+
public readonly eventsToAccumulate = new Array<[string | symbol, symbol]>();
123135

124136
*actions(): Generator<EntryAction, void, undefined> {
125137
yield* this.entryActions;
@@ -171,6 +183,8 @@ class Handlers {
171183
this.alwaysArray.push(value);
172184
} else if (value.type === 'listenTo') {
173185
this.eventsToListenTo.push([value.eventName, value.sender]);
186+
} else if (value.type === 'accumulate') {
187+
this.eventsToAccumulate.push([value.eventName, value.resultKey]);
174188
}
175189
}
176190

@@ -207,6 +221,7 @@ class InternalInstance {
207221
private parent: null | InternalInstance
208222
private globalHandlers = new Handlers()
209223
private resolved = null as Promise<Record<string, any>> | null
224+
private accumulations: Map<symbol | string, Array<symbol | string | Event>> = new Map();
210225
private eventAborter = new AbortController();
211226
child: null | InternalInstance = null
212227

@@ -266,8 +281,19 @@ class InternalInstance {
266281
// return build().then(pairs => Object.fromEntries(pairs as any));
267282
}
268283

284+
*allAccumulations(): Generator<[symbol | string, Array<string | symbol | Event>]> /*: Generator<{ key: symbol | string, events: Array<string | symbol | Event> }>*/ {
285+
for (const [key, events] of this.accumulations) {
286+
// yield { key, events };
287+
yield [key, events];
288+
}
289+
290+
if (this.child !== null) {
291+
yield *this.child.allAccumulations();
292+
}
293+
}
294+
269295
handleEvent(event: Event) {
270-
this.receive(event.type);
296+
this.receive(event);
271297
}
272298

273299
cleanup() {
@@ -393,13 +419,23 @@ class InternalInstance {
393419
return false;
394420
}
395421

396-
receive(event: string | symbol) {
422+
receive(event: string | symbol | Event) {
397423
this.child?.receive(event);
398424

399-
const target = this.globalHandlers.targetForEvent(event);
425+
const eventName = typeof event === 'string' || typeof event === 'symbol' ? event : event.type;
426+
427+
const target = this.globalHandlers.targetForEvent(eventName);
400428
if (target !== undefined) {
401429
this.processTarget(target);
402430
}
431+
432+
for (const [iteratedEventName, resultKey] of this.globalHandlers.eventsToAccumulate) {
433+
if (iteratedEventName === eventName) {
434+
const current = this.accumulations.get(resultKey) ?? [];
435+
console.log("accumulating event", eventName);
436+
this.accumulations.set(resultKey, current.concat(event));
437+
}
438+
}
403439
}
404440
}
405441

@@ -436,6 +472,9 @@ export function start(
436472
get results() {
437473
return instance.results;
438474
},
475+
get accumulations() {
476+
return new Map(instance.allAccumulations());
477+
},
439478
next(event: string | symbol) {
440479
instance.receive(event);
441480
const promise = instance.results;

0 commit comments

Comments
 (0)