remove typescript generics
they were getting in the way; it can be developed after the lib is more mature
This commit is contained in:
+35
-34
@@ -1,48 +1,49 @@
|
||||
type Event_T = [name:string, payload:any] | ['entry', any];
|
||||
export interface Machine_T<S,E extends Event_T,C> {
|
||||
states: Array<State_T<S,E,C>>
|
||||
export type Event_T = [name:string, payload:any];
|
||||
export interface Machine_T {
|
||||
states: Array<State_T>
|
||||
}
|
||||
export interface State_T<S,E extends Event_T,C> {
|
||||
name: S;
|
||||
ons: Array<On_T<S,E,C>>;
|
||||
export interface State_T {
|
||||
name: string;
|
||||
ons: Array<On_T>;
|
||||
}
|
||||
export interface On_T<S,E extends Event_T,C> {
|
||||
eventName: E[0];
|
||||
reactions: Array<Do_T<S,E,C> | Goto_T<S>>;
|
||||
export interface On_T {
|
||||
eventName: string;
|
||||
reactions: Array<Do_T | Goto_T>;
|
||||
};
|
||||
export interface Do_T<S,E extends Event_T, C> {
|
||||
export interface Do_T {
|
||||
type: 'Do';
|
||||
fn: DoFn_T<S,E,C>;
|
||||
fn: DoFn_T;
|
||||
};
|
||||
export type DoFn_T<S,E extends Event_T, C> = (ctx:C,e:E,self:Interpreter_T<S,E,C>)=>any;
|
||||
export interface Goto_T<S> {
|
||||
export type DoFn_T = (ctx:any,e:Event_T,self:Interpreter_T)=>void;
|
||||
export interface Goto_T {
|
||||
type: 'Goto';
|
||||
targetStateName: S;
|
||||
targetStateName: string;
|
||||
};
|
||||
|
||||
export const Machine = function<S,E extends Event_T,C>(...states:Array<State_T<S,E,C>>) : Machine_T<S,E,C> { return {states}; };
|
||||
export const State = function<S,E extends Event_T,C>(name:S, ...ons:Array<On_T<S,E,C>>) : State_T<S,E,C>{ return {name, ons}; };
|
||||
export const On = function<S,E extends Event_T,C>(eventName:E[0], ...reactions:Array<Do_T<S,E,C> | Goto_T<S>>) : On_T<S,E,C>{ return {eventName, reactions}; };
|
||||
export const Do = function<S,E extends Event_T, C>(fn:DoFn_T<S,E,C>) : Do_T<S,E,C>{ return {type:'Do', fn}; };
|
||||
export const Goto = function<S>(targetStateName:S) : Goto_T<S> { return {type:'Goto', targetStateName} };
|
||||
export const Machine = function(...states:Array<State_T>) : Machine_T { return {states}; };
|
||||
export const State = function(name:string, ...ons:Array<On_T>) : State_T{ return {name, ons}; };
|
||||
export const On = function(eventName:string, ...reactions:Array<Do_T | Goto_T>) : On_T{ return {eventName, reactions}; };
|
||||
export const Do = function<S,E extends Event_T, C>(fn:DoFn_T) : Do_T{ return {type:'Do', fn}; };
|
||||
export const Goto = function(targetStateName:string) : Goto_T { return {type:'Goto', targetStateName} };
|
||||
|
||||
interface Tick_T<S,E extends Event_T, C> {
|
||||
doFunctions: Array<DoFn_T<S,E,C>>
|
||||
interface Tick_T {
|
||||
doFunctions: Array<DoFn_T>
|
||||
};
|
||||
const Tick = function<S,E extends Event_T,C>(doFunctions : Array<DoFn_T<S,E,C>>) : Tick_T<S,E,C>{ return {doFunctions}; };
|
||||
const Tick = function(doFunctions : Array<DoFn_T>) : Tick_T{ return {doFunctions}; };
|
||||
|
||||
|
||||
export interface Interpreter_T<S,E extends Event_T,C> {
|
||||
machine: Machine_T<S,E,C>;
|
||||
state: S;
|
||||
context: C;
|
||||
tickQueues:Array<TickQueue_T<S,E,C>>
|
||||
export interface Interpreter_T {
|
||||
machine: Machine_T;
|
||||
state: string;
|
||||
context: any;
|
||||
tickQueues:Array<TickQueue_T>
|
||||
}
|
||||
type TickQueue_T<S,E extends Event_T,C> = Array<Tick_T<S,E,C>>;
|
||||
export function interpret<S,E extends Event_T,C>(machine:Machine_T<S,E,C>, options:{state?:S, context:C}) : Interpreter_T<S,E,C>{
|
||||
type TickQueue_T = Array<Tick_T>;
|
||||
export function interpret(machine:Machine_T, options:{state?:string, context:any}) : Interpreter_T{
|
||||
let {state, context} = options;
|
||||
if(typeof state === 'undefined'){ state = machine.states[0].name; }
|
||||
const interpreter = {machine, state, context, tickQueues:[]}
|
||||
console.log(interpreter);
|
||||
//@ts-ignore
|
||||
send(interpreter, ['entry', null] );
|
||||
return interpreter;
|
||||
@@ -50,12 +51,12 @@ export function interpret<S,E extends Event_T,C>(machine:Machine_T<S,E,C>, optio
|
||||
|
||||
/** Helper function for `send()`
|
||||
*/
|
||||
function getState<S,E extends Event_T,C>(interpreter : Interpreter_T<S,E,C>) : State_T<S,E,C>{
|
||||
return interpreter.machine.states.find((state)=>state.name===interpreter.state) as unknown as State_T<S,E,C>;
|
||||
function getState(interpreter : Interpreter_T) : State_T{
|
||||
return interpreter.machine.states.find((state)=>state.name===interpreter.state) as unknown as State_T;
|
||||
}
|
||||
/** Helper function for `send()`
|
||||
*/
|
||||
function getOns<S,E extends Event_T,C>(state : State_T<S,E,C>, event:E) : Array<On_T<S,E,C>>{
|
||||
function getOns(state : State_T, event:Event_T) : Array<On_T>{
|
||||
return state.ons.filter((on)=>on.eventName===event[0]);
|
||||
}
|
||||
/** Helper function for `send()`
|
||||
@@ -71,7 +72,7 @@ function noop(){}
|
||||
* whether to run a reaction at all. If an Event is received, and is specified to be applied on a past
|
||||
* Tick, it is discarded.
|
||||
*/
|
||||
export function send<S,E extends Event_T,C>(interpreter : Interpreter_T<S,E,C>, event:E){
|
||||
export function send(interpreter : Interpreter_T, event:Event_T){
|
||||
const state = getState(interpreter);
|
||||
const onsTree = getOns(state, event);
|
||||
const reactions = onsTree
|
||||
@@ -86,7 +87,7 @@ export function send<S,E extends Event_T,C>(interpreter : Interpreter_T<S,E,C>,
|
||||
return reaction.fn;
|
||||
}
|
||||
else if(reaction.type === 'Goto'){
|
||||
return (ctx:C,e:E,self:Interpreter_T<S,E,C>)=>{
|
||||
return (ctx:any,e:Event_T,self:Interpreter_T)=>{
|
||||
self.state = reaction.targetStateName;
|
||||
//@ts-ignore
|
||||
send(self, ['entry', e] );
|
||||
|
||||
+17
-12
@@ -1,38 +1,43 @@
|
||||
import { Machine, State, On, Do, Goto, Spawn, Unspawn, interpret, Interpreter_T, send } from '../index';
|
||||
import { Machine, State, On, Do, Goto, Spawn, Unspawn, interpret, Interpreter_T, send, Event_T } from '../index';
|
||||
|
||||
const beginTimer = (ctx:C, e:E, self:Interpreter_T<S,E,C>)=>{ setTimeout(()=>{ send(self, ['timer-finished',null]); }, 800); };
|
||||
const log = (ctx:C, e:E, self:Interpreter_T<S,E,C>)=>{ console.log(self.state); };
|
||||
const beginTimer = (ctx:C, e:Event_T, self:Interpreter_T)=>{ setTimeout(()=>{ send(self, ['timer-finished',null]); }, 800); };
|
||||
const log = (ctx:C, e:Event_T, self:Interpreter_T)=>{ console.log(self.state); };
|
||||
|
||||
type S = 'green' | 'yellow' | 'red';
|
||||
type E = ['entry',null] | ['timer-finished',null];
|
||||
type S =
|
||||
| 'green'
|
||||
| 'yellow'
|
||||
| 'red';
|
||||
type E =
|
||||
| ['entry',null]
|
||||
| ['timer-finished',null];
|
||||
type C = {};
|
||||
|
||||
const machine =
|
||||
Machine<S,E,C>(
|
||||
Machine(
|
||||
State('green',
|
||||
On<S,E,C>('entry',
|
||||
On('entry',
|
||||
Do(beginTimer),
|
||||
Do(log)
|
||||
),
|
||||
On<S,E,C>('timer-finished',
|
||||
On('timer-finished',
|
||||
Goto('yellow')
|
||||
)
|
||||
),
|
||||
State('yellow',
|
||||
On<S,E,C>('entry',
|
||||
On('entry',
|
||||
Do(beginTimer),
|
||||
Do(log)
|
||||
),
|
||||
On<S,E,C>('timer-finished',
|
||||
On('timer-finished',
|
||||
Goto('red')
|
||||
)
|
||||
),
|
||||
State('red',
|
||||
On<S,E,C>('entry',
|
||||
On('entry',
|
||||
Do(beginTimer),
|
||||
Do(log)
|
||||
),
|
||||
On<S,E,C>('timer-finished',
|
||||
On('timer-finished',
|
||||
Goto('green')
|
||||
)
|
||||
),
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
import { Machine, State, On, Do, Goto, Spawn, Unspawn, interpret, Interpreter_T, send, Event_T } from '../index';
|
||||
|
||||
const wait = (ms:number)=>new Promise((resolve)=>{ setTimeout(()=>{ resolve(1); }, ms); });
|
||||
const makeRequest = (ctx,e,self)=>{ send(ctx.serverActor, ['received-request',self]); };
|
||||
const sendResponse = (ctx,e,self)=>{ send(ctx.clientActor, ['received-response',self]); };
|
||||
const startTimer = async (ctx,e,self)=>{ await wait(500); send(self, ['timer-finished',null]); }
|
||||
const log = (ctx, e, self:Interpreter_T)=>{ console.log(self.state); };
|
||||
|
||||
type Sc =
|
||||
| 'idle'
|
||||
| 'making-request'
|
||||
| 'awaiting-response';
|
||||
type Ec =
|
||||
| ['entry',null]
|
||||
| ['received-response',Interpreter_T]
|
||||
| ['server-created', Interpreter_T];
|
||||
type Cc =
|
||||
| {serverActor?:Interpreter_T};
|
||||
|
||||
const client =
|
||||
Machine(
|
||||
State('idle',
|
||||
On('entry',
|
||||
Do(log),
|
||||
),
|
||||
On('server-created',
|
||||
|
||||
Do((_ctx,[_eventName,serverActor],self)=>{ self.context.serverActor=serverActor; }),
|
||||
Goto('making-request')
|
||||
)
|
||||
),
|
||||
State('making-request',
|
||||
On('entry',
|
||||
Do(log),
|
||||
Do(makeRequest),
|
||||
Goto('awaiting-response')
|
||||
),
|
||||
),
|
||||
State('awaiting-response',
|
||||
On('entry',
|
||||
Do(log),
|
||||
),
|
||||
On('received-response',
|
||||
Do(log),
|
||||
Goto('making-request')
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
type Ss =
|
||||
| 'awaiting-request'
|
||||
| 'sending-response';
|
||||
type Es =
|
||||
| ['entry',null]
|
||||
| ['received-request',Interpreter_T]
|
||||
| ['timer-finished', null];
|
||||
type Cs = {clientActor?:Interpreter_T};
|
||||
|
||||
const server =
|
||||
Machine(
|
||||
State('awaiting-request',
|
||||
On('entry',
|
||||
Do(log),
|
||||
),
|
||||
On('received-request',
|
||||
Do((_ctx,[_eventName,clientActor],self)=>{ self.context.clientActor=clientActor; }),
|
||||
Goto('sending-response')
|
||||
),
|
||||
),
|
||||
State('sending-response',
|
||||
On('entry',
|
||||
Do(log),
|
||||
Do(startTimer)
|
||||
),
|
||||
On('timer-finished',
|
||||
Do(sendResponse),
|
||||
Goto('awaiting-request')
|
||||
)
|
||||
),
|
||||
);
|
||||
|
||||
const clientActor = interpret(client, {context:{}});
|
||||
const serverActor = interpret(server, {context:{}});
|
||||
send(clientActor, ['server-created', serverActor]);
|
||||
Reference in New Issue
Block a user