sync `send` works
parent
0495f1d87a
commit
e328533629
@ -0,0 +1,2 @@
|
||||
var d=function(...t){return{states:t}},y=function(t,...e){return{name:t,ons:e}},v=function(t,...e){return{eventName:t,reactions:e}},D=function(t){return{type:"Do",fn:t}},k=function(t){return{type:"Goto",targetStateName:t}},c=function(t){return{doFunctions:t}};function l(t,e){let{state:o,context:s}=e;return typeof o>"u"&&(o=t.states[0].name),{machine:t,state:o,context:s,tickQueues:[]}}function i(t){return t.machine.states.find(e=>e.name===t.state)}function _(t,e){return t.ons.filter(o=>o.eventName===e[0])}function C(){}function G(t,e){let o=i(t),r=_(o,e).map(n=>n.reactions).flat(),a=r.findIndex(n=>n.type==="Goto"),E=a===-1?r.length-1:a,S=r.slice(0,E+1).map(n=>n.type==="Do"?n.fn:n.type==="Goto"?(p,f,T)=>{T.state=n.targetStateName}:C);c(S).doFunctions.forEach(n=>{n(t.context,e,t)})}var m=function(){},A=function(){};export{D as Do,k as Goto,d as Machine,v as On,m as Spawn,y as State,A as Unspawn,l as interpret,G as send};
|
||||
//# sourceMappingURL=index.js.map
|
@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../src/index.ts"],
|
||||
"sourcesContent": ["type Event_T = [name:string, payload:any];\nexport interface Machine_T<S,E extends Event_T,C> {\n states: Array<State_T<S,E,C>>\n}\nexport interface State_T<S,E extends Event_T,C> {\n name: S;\n ons: Array<On_T<S,E,C>>;\n}\nexport interface On_T<S,E extends Event_T,C> {\n eventName: E[0];\n reactions: Array<Do_T<S,E,C> | Goto_T<S>>;\n};\nexport interface Do_T<S,E extends Event_T, C> {\n type: 'Do';\n fn: DoFn_T<S,E,C>;\n};\nexport type DoFn_T<S,E extends Event_T, C> = (ctx:C,e:E,self:Interpreter_T<S,E,C>)=>any;\nexport interface Goto_T<S> {\n type: 'Goto';\n targetStateName: S;\n};\n\nexport const Machine = function<S,E extends Event_T,C>(...states:Array<State_T<S,E,C>>) : Machine_T<S,E,C> { return {states}; };\nexport 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}; };\nexport 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}; };\nexport const Do = function<S,E extends Event_T, C>(fn:DoFn_T<S,E,C>) : Do_T<S,E,C>{ return {type:'Do', fn}; };\nexport const Goto = function<S>(targetStateName:S) : Goto_T<S> { return {type:'Goto', targetStateName} };\n\ninterface Tick_T<S,E extends Event_T, C> {\n doFunctions: Array<DoFn_T<S,E,C>>\n};\nconst Tick = function<S,E extends Event_T,C>(doFunctions : Array<DoFn_T<S,E,C>>) : Tick_T<S,E,C>{ return {doFunctions}; };\n\n\nexport interface Interpreter_T<S,E extends Event_T,C> {\n machine: Machine_T<S,E,C>;\n state: S;\n context: C;\n tickQueues:Array<TickQueue_T<S,E,C>>\n}\ntype TickQueue_T<S,E extends Event_T,C> = Array<Tick_T<S,E,C>>;\nexport function interpret<S,E extends Event_T,C>(machine:Machine_T<S,E,C>, options:{state?:S, context:C}) : Interpreter_T<S,E,C>{\n let {state, context} = options;\n if(typeof state === 'undefined'){ state = machine.states[0].name; }\n return {machine, state, context, tickQueues:[]};\n}\n\n/** Helper function for `send()`\n */\nfunction getState<S,E extends Event_T,C>(interpreter : Interpreter_T<S,E,C>) : State_T<S,E,C>{\n return interpreter.machine.states.find((state)=>state.name===interpreter.state) as unknown as State_T<S,E,C>;\n}\n/** Helper function for `send()`\n */\nfunction getOns<S,E extends Event_T,C>(state : State_T<S,E,C>, event:E) : Array<On_T<S,E,C>>{\n return state.ons.filter((on)=>on.eventName===event[0]);\n}\n/** Helper function for `send()`\n */\nfunction noop(){}\n/** Inject an Event into the Interpreter's \"tick queue\".\n * \n * An event can be signify something \"new\" happening, such that its reactions should run on the next Tick;\n * or it can signify a milestone \"within\" the current Tick, such that a Tick can be thought of as having \n * \"sub-Ticks\".\n * \n * This distinction is significant for proper ordering of reaction execution, and also for determining\n * whether to run a reaction at all. If an Event is received, and is specified to be applied on a past \n * Tick, it is discarded.\n */\nexport function send<S,E extends Event_T,C>(interpreter : Interpreter_T<S,E,C>, event:E){\n const state = getState(interpreter);\n const onsTree = getOns(state, event);\n const reactions = onsTree\n .map((on)=>on.reactions)\n .flat();\n const indexOfFirstGoto = reactions.findIndex((reaction)=>reaction.type==='Goto');\n const indexOfFinalReaction = indexOfFirstGoto === -1 ? reactions.length-1 : indexOfFirstGoto;\n const reactionsUntilFirstGoto = reactions.slice(0, indexOfFinalReaction+1);\n const functionsToRunInTick = reactionsUntilFirstGoto\n .map((reaction)=>{\n if(reaction.type === 'Do'){\n return reaction.fn;\n }\n else if(reaction.type === 'Goto'){\n return (ctx:C,e:E,self:Interpreter_T<S,E,C>)=>{\n self.state = reaction.targetStateName;\n };\n }\n else{\n return noop;\n }\n });\n const tick = Tick(functionsToRunInTick);\n tick.doFunctions.forEach((fn)=>{ fn(interpreter.context, event, interpreter); });\n}\n\nexport const Spawn = function(){};\nexport const Unspawn = function(){};"],
|
||||
"mappings": "AAsBO,IAAMA,EAAU,YAAmCC,EAAiD,CAAE,MAAO,CAAC,OAAAA,CAAM,CAAG,EACjHC,EAAQ,SAAgCC,KAAWC,EAAwC,CAAE,MAAO,CAAC,KAAAD,EAAM,IAAAC,CAAG,CAAG,EACjHC,EAAK,SAAgCC,KAAmBC,EAAuD,CAAE,MAAO,CAAC,UAAAD,EAAW,UAAAC,CAAS,CAAG,EAChJC,EAAK,SAAiCC,EAA+B,CAAE,MAAO,CAAC,KAAK,KAAM,GAAAA,CAAE,CAAG,EAC/FC,EAAO,SAAYC,EAA+B,CAAE,MAAO,CAAC,KAAK,OAAQ,gBAAAA,CAAe,CAAE,EAKjGC,EAAO,SAAgCC,EAAmD,CAAE,MAAO,CAAC,YAAAA,CAAW,CAAG,EAUjH,SAASC,EAAiCC,EAA0BC,EAAqD,CAC9H,GAAI,CAAC,MAAAC,EAAO,QAAAC,CAAO,EAAIF,EACvB,OAAG,OAAOC,EAAU,MAAcA,EAAQF,EAAQ,OAAO,CAAC,EAAE,MACrD,CAAC,QAAAA,EAAS,MAAAE,EAAO,QAAAC,EAAS,WAAW,CAAC,CAAC,CAChD,CAIA,SAASC,EAAgCC,EAAoD,CAC3F,OAAOA,EAAY,QAAQ,OAAO,KAAMH,GAAQA,EAAM,OAAOG,EAAY,KAAK,CAChF,CAGA,SAASC,EAA8BJ,EAAwBK,EAA6B,CAC1F,OAAOL,EAAM,IAAI,OAAQM,GAAKA,EAAG,YAAYD,EAAM,CAAC,CAAC,CACvD,CAGA,SAASE,GAAM,CAAC,CAWT,SAASC,EAA4BL,EAAoCE,EAAQ,CACtF,IAAML,EAAQE,EAASC,CAAW,EAE5Bb,EADUc,EAAOJ,EAAOK,CAAK,EAEhC,IAAKC,GAAKA,EAAG,SAAS,EACtB,KAAK,EACFG,EAAmBnB,EAAU,UAAWoB,GAAWA,EAAS,OAAO,MAAM,EACzEC,EAAuBF,IAAqB,GAAKnB,EAAU,OAAO,EAAImB,EAEtEG,EAD0BtB,EAAU,MAAM,EAAGqB,EAAqB,CAAC,EAEtE,IAAKD,GACDA,EAAS,OAAS,KACZA,EAAS,GAEVA,EAAS,OAAS,OACjB,CAACG,EAAMC,EAAIC,IAA4B,CAC5CA,EAAK,MAAQL,EAAS,eACxB,EAGOH,CAEV,EACUZ,EAAKiB,CAAoB,EACjC,YAAY,QAASpB,GAAK,CAAEA,EAAGW,EAAY,QAASE,EAAOF,CAAW,CAAG,CAAC,CACjF,CAEO,IAAMa,EAAQ,UAAU,CAAC,EACnBC,EAAU,UAAU,CAAC",
|
||||
"names": ["Machine", "states", "State", "name", "ons", "On", "eventName", "reactions", "Do", "fn", "Goto", "targetStateName", "Tick", "doFunctions", "interpret", "machine", "options", "state", "context", "getState", "interpreter", "getOns", "event", "on", "noop", "send", "indexOfFirstGoto", "reaction", "indexOfFinalReaction", "functionsToRunInTick", "ctx", "e", "self", "Spawn", "Unspawn"]
|
||||
}
|
@ -0,0 +1 @@
|
||||
(()=>{var x=function(...t){return{states:t}},i=function(t,...e){return{name:t,ons:e}},o=function(t,...e){return{eventName:t,reactions:e}},s=function(t){return{type:"Do",fn:t}},S=function(t){return{type:"Goto",targetStateName:t}},l=function(t){return{doFunctions:t}};function u(t,e){let{state:n,context:C}=e;typeof n>"u"&&(n=t.states[0].name);let E={machine:t,state:n,context:C,tickQueues:[]};return c(E,["entry",null]),E}function m(t){return t.machine.states.find(e=>e.name===t.state)}function v(t,e){return t.ons.filter(n=>n.eventName===e[0])}function h(){}function c(t,e){let n=m(t),E=v(n,e).map(r=>r.reactions).flat(),_=E.findIndex(r=>r.type==="Goto"),f=_===-1?E.length-1:_,y=E.slice(0,f+1).map(r=>r.type==="Do"?r.fn:r.type==="Goto"?(k,d,p)=>{p.state=r.targetStateName,c(p,["entry",d])}:h);l(y).doFunctions.forEach(r=>{r(t.context,e,t)})}var a=(t,e,n)=>{setTimeout(()=>{c(n,["timer-finished",null])},800)},T=(t,e,n)=>{console.log(n.state)},D=x(i("green",o("entry",s(a),s(T)),o("timer-finished",S("yellow"))),i("yellow",o("entry",s(a),s(T)),o("timer-finished",S("red"))),i("red",o("entry",s(a),s(T)),o("timer-finished",S("green")))),M=u(D,{context:{}});})();
|
@ -1,35 +1,41 @@
|
||||
import { Machine, State, On, Do, Goto, Spawn, Unspawn } from '../index';
|
||||
import { Machine, State, On, Do, Goto, Spawn, Unspawn, interpret, Interpreter_T, send } from '../index';
|
||||
|
||||
const beginTimer = (ctx:C, e:E)=>{};
|
||||
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); };
|
||||
|
||||
type S = 'green' | 'yellow' | 'red';
|
||||
type E = ['entry',null] | ['timer-finished',null];
|
||||
type C = null;
|
||||
type C = {};
|
||||
|
||||
const machine =
|
||||
Machine<S,E,C>(
|
||||
State('green',
|
||||
On('entry',
|
||||
Do(beginTimer)
|
||||
On<S,E,C>('entry',
|
||||
Do(beginTimer),
|
||||
Do(log)
|
||||
),
|
||||
On('timer-finished',
|
||||
On<S,E,C>('timer-finished',
|
||||
Goto('yellow')
|
||||
)
|
||||
),
|
||||
State('yellow',
|
||||
On('entry',
|
||||
Do(beginTimer)
|
||||
On<S,E,C>('entry',
|
||||
Do(beginTimer),
|
||||
Do(log)
|
||||
),
|
||||
On('timer-finished',
|
||||
On<S,E,C>('timer-finished',
|
||||
Goto('red')
|
||||
)
|
||||
),
|
||||
State('red',
|
||||
On('entry',
|
||||
Do(beginTimer)
|
||||
On<S,E,C>('entry',
|
||||
Do(beginTimer),
|
||||
Do(log)
|
||||
),
|
||||
On('timer-finished',
|
||||
On<S,E,C>('timer-finished',
|
||||
Goto('green')
|
||||
)
|
||||
),
|
||||
);
|
||||
);
|
||||
|
||||
const actor = interpret(machine, {context:{}});
|
Loading…
Reference in New Issue