Skip to content

Commit

Permalink
feat: Add fsm operator
Browse files Browse the repository at this point in the history
  • Loading branch information
jmeinlschmidt committed Sep 16, 2023
1 parent 218f2d6 commit 6ace584
Show file tree
Hide file tree
Showing 8 changed files with 71 additions and 14 deletions.
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,11 @@ Another approach is to avoid the _machine_ object and use this library in a pipe

```ts
const {
nextState,
fsm,
markInput,
} = fsmHelpersFactory<State, Input>(transitions);

const state$ = input$.pipe(
scan(nextState, initialState),
);
const state$ = input$.pipe(fsm(initialState));

state$.subscribe(console.log);
```
Expand Down
9 changes: 5 additions & 4 deletions examples/example-1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,22 @@ import { Subject, merge, scan } from 'rxjs';

import { fsmHelpersFactory } from '../lib';

import { Input, State, transitions } from './state.config';
import { Input, State, initialState, transitions } from './state.config';

/**
* Example 1
* Demonstrates creating a FSM only by using RxJs operators.
*/

const { nextState, markInput } = fsmHelpersFactory<State, Input>(transitions);
const {
nextState,
markInput,
} = fsmHelpersFactory<State, Input>(transitions);

// Define inputs
const toggle$ = new Subject<void>();
const hide$ = new Subject<void>();

const initialState: State = 'hidden';

// Use helper functions
const input$ = merge(
toggle$.pipe(markInput('toggle')),
Expand Down
6 changes: 2 additions & 4 deletions examples/example-2.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Observable, Subject, merge } from 'rxjs';
import { Subject, merge } from 'rxjs';

import { fsmHelpersFactory, rxjsFsmFactory } from '../lib';
import { Input, State, transitions } from './state.config';
import { Input, State, initialState, transitions } from './state.config';

/**
* Example 2
Expand All @@ -12,8 +12,6 @@ import { Input, State, transitions } from './state.config';
const toggle$ = new Subject<void>();
const hide$ = new Subject<void>();

const initialState: State = 'hidden';

const { markInput } = fsmHelpersFactory<State, Input>(transitions);

// Use helper functions
Expand Down
41 changes: 41 additions & 0 deletions examples/example-3.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Subject, merge } from 'rxjs';

import { fsmHelpersFactory } from '../lib';

import { Input, State, initialState, transitions } from './state.config';

/**
* Example 3
* Demonstrates creating a FSM using by the `fsm` operator.
*/

const {
markInput,
fsm,
} = fsmHelpersFactory<State, Input>(transitions);

// Define inputs
const toggle$ = new Subject<void>();
const hide$ = new Subject<void>();

// Use helper functions
const input$ = merge(
toggle$.pipe(markInput('toggle')),
hide$.pipe(markInput('hide')),
);

const state$ = input$.pipe(fsm(initialState));

// Listen
state$.subscribe((newState) => console.log('New state:', newState));

console.log('Initial state:', initialState);
console.log('Input: toggle');
toggle$.next();
console.log('Input: toggle');
toggle$.next();
console.log('Input: toggle');
toggle$.next();

console.log('Input: hide');
hide$.next();
2 changes: 2 additions & 0 deletions examples/state.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { StateTransitions } from '../lib';
export type Input = 'toggle' | 'hide';
export type State = 'hidden' | 'shown';

export const initialState: State = 'hidden';

export const transitions: StateTransitions<State, Input> = {
hidden: {
toggle: 'shown',
Expand Down
8 changes: 6 additions & 2 deletions lib/rxjs-fsm/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { markInput, nextState } from '../utils';
import { fsm, markInput, nextState } from '../utils';
import { BaseInput, BaseState, StateTransitions } from '../models';

/**
* Factory for helper functions, independent of state machine instance.
*/
export const fsmHelpersFactory = <S extends BaseState, T extends BaseInput>(
transitions: StateTransitions<S, T>,
) => ({ markInput: markInput<unknown, T>(), nextState: nextState<S, T>(transitions) });
) => ({
markInput: markInput<unknown, T>(),
nextState: nextState<S, T>(transitions),
fsm: fsm(transitions),
});
12 changes: 12 additions & 0 deletions lib/utils/fsm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { pipe, scan, startWith } from 'rxjs';
import { BaseInput, BaseState, StateTransitions } from '../models';
import { nextState } from './next';

export const fsm = <S extends BaseState, T extends BaseInput>(
transitions: StateTransitions<S, T>,
) => (
initialState: S,
) => pipe(
scan(nextState<S, T>(transitions), initialState),
startWith(initialState),
);
1 change: 1 addition & 0 deletions lib/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './mark-input';
export * from './next';
export * from './fsm';

0 comments on commit 6ace584

Please sign in to comment.