Skip to content

Commit

Permalink
Fix #171 (#172)
Browse files Browse the repository at this point in the history
* feat: address #171

* fix: fix type

* docs: update docs
  • Loading branch information
allevo authored Aug 6, 2024
1 parent 7f79c0b commit a6a0325
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 6 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,8 @@ using `send` will reject.
- `subscribe`: You can register a callback that will be invoked
on every state transition between the `onEntry` and `onExit` hooks.
The callback returns the `subscriptionId` and receives `context` and `currentStateId`.
The callback returns the `subscriptionId` and receives `context`,
`event`, `sharedData`, and `currentStateId`.

- `unsubscribe`: Remove the subscription with the given `subscriptionId`.

Expand Down
2 changes: 1 addition & 1 deletion docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ using `send` will reject.
- `subscribe`: You can register a callback that will be invoked
on every state transition between the `onEntry` and `onExit` hooks.
The callback returns the `subscriptionId` and receives `context` and `currentStateId`.
The callback returns the `subscriptionId` and receives `context`, `event`, `sharedData`, and `currentStateId`.

- `unsubscribe`: Remove the subscription with the given `subscriptionId`.

Expand Down
10 changes: 8 additions & 2 deletions src/fsm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ export class StateMachine<
#initial: State<TContext, TEvent, TSharedData>;
#states: Map<StateIdentifier, State<TContext, TEvent, TSharedData>>;
#sharedData: TSharedData;
#subscriptions: Map<SubscriptionIdentifier, SubscriptionCallback>;
#subscriptions: Map<
SubscriptionIdentifier,
SubscriptionCallback<TContext, TEvent, TSharedData>
>;

private constructor(
states: Array<State<TContext, TEvent, TSharedData>>,
Expand Down Expand Up @@ -158,6 +161,7 @@ export class StateMachine<
context: this.context,
currentStateId: this.#current.id,
sharedData: this.#sharedData,
event,
});
}

Expand Down Expand Up @@ -212,7 +216,9 @@ export class StateMachine<
await this.enter(destination, event);
}

public subscribe(callback: SubscriptionCallback): SubscriptionIdentifier {
public subscribe(
callback: SubscriptionCallback<TContext, TEvent, TSharedData>,
): SubscriptionIdentifier {
const id = crypto.randomUUID();
this.#subscriptions.set(id, callback);
return id;
Expand Down
10 changes: 8 additions & 2 deletions src/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,21 @@ export type SubscriptionIdentifier = string;

export type SubscriptionCallbackInput<
TContext = unknown,
TEvent = unknown,
TSharedData = unknown,
> = {
context: TContext;
currentStateId: StateIdentifier;
sharedData: TSharedData;
event?: TEvent;
};

export type SubscriptionCallback<TContext = unknown> = (
callback: SubscriptionCallbackInput<TContext>,
export type SubscriptionCallback<
TContext = unknown,
TEvent = unknown,
TSharedData = unknown,
> = (
callback: SubscriptionCallbackInput<TContext, TEvent, TSharedData>,
) => void;

export type HookInput<
Expand Down
59 changes: 59 additions & 0 deletions test/subscribe.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import assert from "node:assert";
import test from "node:test";
import { StateMachine } from "../dist/index.js";

test("#171 - event is available on 'subscribe' callback", async () => {
const subscriptionEvent = [];

const states = [
{
id: "OFF",
initial: true,
transitionTo: () => "ON",
},
{
id: "ON",
transitionTo: () => "OFF",
},
];

const context = {};
const sharedData = {};
const machine = StateMachine.from(states, {
context,
sharedData,
});

machine.subscribe((event) => {
subscriptionEvent.push(event);
});

// Start the state machine
await machine.start();

const event1 = { name: "foo", value: 1 };
await machine.send(event1);
const event2 = { name: "foo", value: 2 };
await machine.send(event2);

assert.deepStrictEqual(subscriptionEvent, [
{
context,
currentStateId: "OFF",
event: undefined,
sharedData,
},
{
context,
currentStateId: "ON",
event: event1,
sharedData,
},
{
context,
currentStateId: "OFF",
event: event2,
sharedData,
},
]);
});

0 comments on commit a6a0325

Please sign in to comment.